...but keep in mind that
or Functions as a Service (FaaS)
Serverless computing (or serverless for short), is an execution model where the cloud provider is responsible for executing a piece of code by dynamically allocating the resources. And only charging for the amount of resources used to run the code. The code is typically run inside stateless containers that can be triggered by a variety of events including http requests, database events, queuing services, monitoring alerts, file uploads, scheduled events (cron jobs), etc. The code that is sent to the cloud provider for execution is usually in the form of a function. Hence serverless is sometimes referred to as “Functions as a Service” or “FaaS”.
or Functions as a Service (FaaS)
basic premises:
well known providers:
Deploy your WSGI apps on AWS Lambda
With Zappa, each request is given its own virtual HTTP "server" by Amazon API Gateway. AWS handles the horizontal scaling automatically, so no requests ever time out. After your app returns, the "server" dies.
zappa up and running
wsgi vs asgi
WSGI is an inherently thread-concurrency interface, so it cannot do any async context switching inside
ASGI has an async interface, and includes more than just HTTP request/responses, and is very much more general purpose and highly adabtable.
asgi servers
Daphne, Hypercorn, and Uvicorn
asgi frameworks
Starlette, Responder, FastAPI
asgi server benefits
starlette - hello world
from starlette.applications import Starlette
from starlette.responses import JSONResponse
import uvicorn
app = Starlette(debug=True)
@app.route('/')
async def homepage(request):
return JSONResponse({'hello': 'world'})
if __name__ == '__main__':
uvicorn.run(app, host='0.0.0.0', port=8000)
starlette - db request
@app.route("/notes", methods=["GET"])
async def list_notes(request):
query = notes.select()
results = await database.fetch_all(query)
content = [
{
"text": result["text"],
"completed": result["completed"]
}
for result in results
]
return JSONResponse(content)
starlette
django async roadmap
https://www.aeracode.org/2018/06/04/django-async-roadmap/
import logging
logger = logging.getLogger(__name__)
logger.error(f'Failed to perform operation on object #{object.id} for user #{user.id}')
what logging usually looks like:
ideas:
structlog
import structlog
logger = structlog.getLogger()
logger.error('transaction_failed',
user=user.id, target_user=target_user.id, transaction=transaction.id)
2018-04-20 16:20.13 transaction_failed user=324 target_user=134 transaction=150
structlog
logger.bind(user=user.id, target_user=target_user.id)
...
logger.bind(transaction=transaction.id)
...
logger.info('transaction_initiated')
2018-04-20 16:20.13 transaction_initiated user=324 target_user=134 transaction=150
...
logger.error('transaction_failed')
2018-04-20 16:21.15 transaction_failed user=324 target_user=134 transaction=150
trace logs across multiple services
import uuid, structlog
logger = structlog.get_logger('structlog')
def structlog_middleware(get_response): # Use as first middleware
def _inner(request):
request.trace_id = request.headers.get('x_trace_id') or str(uuid.uuid4)
logger.bind(trace_id=request.trace_id)
return get_response(request)
return _inner
def structlog_user_middleware(get_response): # Use after authentication middleware
def _inner(request):
if request.user.is_authenticated:
logger.bind(logger, user.id)
return get_response(request)
return _inner
https://gitlab.com/MarkusH/django-structlog/tree/master/bank/bank
subqueries django >= 1.11
>>> from django.db.models import OuterRef, Subquery
>>> newest = Comment.objects.filter(post=OuterRef('pk')).order_by('-created_at')
>>> Post.objects.annotate(newest_commenter_email=Subquery(newest.values('email')[:1]))
SELECT "post"."id", (
SELECT U0."email"
FROM "comment" U0
WHERE U0."post_id" = ("post"."id")
ORDER BY U0."created_at" DESC LIMIT 1
) AS "newest_commenter_email" FROM "post"
>>> print(Blog.objects.filter(title='My Blog').explain(verbose=True))
Seq Scan on public.blog (cost=0.00..35.50 rows=10 width=12) (actual time=0.004..0.004 rows=10 loops=1)
Output: id, title
Filter: (blog.title = 'My Blog'::bpchar)
Planning time: 0.064 ms
Execution time: 0.058 ms
class Order(Model):
...
class Meta:
constraints = [
UniqueConstraint(
name='limit_pending_orders',
fields=['customer', 'is_shipped'],
condition=Q(is_shipped=False)
)
]
class MontlyBudget(Model):
class Meta:
constraints = [
CheckConstraint(
check=Q(month__in=range(1, 13)),
name='check_valid_month',
)
]
]
>>> objs = [
... Entry.objects.create(headline='Entry 1'),
... Entry.objects.create(headline='Entry 2'),
... ]
>>> objs[0].headline = 'This is entry 1'
>>> objs[1].headline = 'This is entry 2'
>>> Entry.objects.bulk_update(objs, ['headline'])
class Article(models.Model):
title = models.CharField(max_length=1000)
upvotes = models.IntegerField()
class Meta:
indexes = [
models.Index(
fields=['upvotes'],
name='upvotes_idx',
condition=Q(upvotes__gt=100)
)
]
from django.db.models import Avg, F, Window
from django.db.models.functions import ExtractYear
# annotate each movie with the average rating
# for the movies by the same studio in the same genre
Movie.objects.annotate(
avg_rating=Window(
expression=Avg('rating'),
partition_by=[F('studio'), F('genre')],
order_by=ExtractYear('released').asc(),
),
)
In Django: set SECURE_BROWSER_XSS_FILTER = True and include the SecurityMiddleware in your middlewares.
stops pages from loading when they detect reflected cross-site scripting
In Django: set SECURE_HSTS_SECONDS to and include SecurityMiddleware.
Note: If you break your HTTPS after having set this flag, any browser that has seen is will not be able to see your website again.
Lets a web site tell browsers that it should only be accessed using HTTPS, instead of using HTTP.
In Django: X_FRAME_OPTIONS = 'DENY' (or use whitelisting), and include the XFrameOptionsMiddleware.
Can be used to indicate whether or not a browser should be allowed to render a page in an inframe
In Django: Mozilla provides django-csp, add CSPMiddleware, and then set a couple of values, e.g.CSP_DEFAULT_SRC = 'self'.
img-src *; # images from anywhere
script-src userscripts.example.com # scripts only from here
New and not yet supported in all browsers – this header lets you disable browser feature, like autoplay, geolocation, camera, etc.
In Django: Install django-feature-policy, add FeaturePolicyMiddleware and set FEATURE_POLICY.
https://securityheaders.com/