This is a simple illustration of a django view having a potential race condition:
# myapp/views.py from django.contrib.auth.models import User from my_libs import calculate_points def add_points(request): user = request.user user.points += calculate_points(user) user.save()
The race condition ought to be fairly apparent: A person could make this request two times, and also the application may potentially execute
user = request.user concurrently, leading to among the demands to override another.
Imagine that the function
calculate_points is comparatively complicated, and makes information according to a myriad of strange stuff that can't be placed in one
update and could be difficult to set up a saved procedure.
Here is my question: What type of securing systems are for sale to django, to cope with situations such as this?
By Django 1.1 you should use the ORM's F() expressions to resolve this unique problem. For additional particulars begin to see the documentation:
Database securing is what you want here. You will find intends to add "choose for update" support to Django (here), but for the time being the easiest is always to use raw SQL to UPDATE the consumer object before you begin to calculate the score.
There are many methods to single-thread this type of factor.
One standard approach is Update First. You need to do an update that will seize a unique lock around the row then do your projects and lastly commit the modification. With this to operate, you have to bypass the ORM's caching.
Another standard approach is to possess a separate, single-threaded application server that isolates the net transactions in the complex calculation.
Your internet application can produce a queue of scoring demands, spawn another process, after which write the scoring demands for this queue. The spawn may be put in Django's
urls.pytherefore it happens on web-application startup. Or it may be put in separate
manage.pyadmin script. Or it is possible "when neededInch once the first scoring request is attempted.
You may also produce a separate WSGI-flavored web server using Werkzeug which accepts WS demands via urllib2. For those who have just one port number with this server, demands are queued by TCP/IP. In case your WSGI handler has one thread, then, you've accomplished serialized single-threads. This really is a little more scalable, because the scoring engine is really a WS request and may be run anywhere.
Another approach would be to possess some other resource that needs to be acquired and held to complete the calculation.
A Singleton object within the database. Just one row inside a unique table could be up-to-date having a session ID to get control update with session ID of
Noneto produce control. The fundamental update needs to incorporate a
WHERE SESSION_ID IS NONEfilter to make sure the update fails once the lock is held by another person. This really is interesting since it is naturally race-free -- it is a single update -- not really a Choose-UPDATE sequence.
An outdoor-variety semaphore may be used outdoors the database. Queues (generally) are simpler to utilize than the usual low-level semaphore.
You could utilize transactions to encapsulate your request. In the per-request level it appears such as this:
from django.db import transaction @transaction.autocommit def add_points(request): ...
This shoudl be adequate should you read increase the consumer data inside the request.
When the user may also edit other fields within the form after which save this data, you must do something similar to this:
Keep last modified time stamp within the request. Before saving the brand new data, determine if it's still exactly the same. Otherwise there's a race condition and you will display a note.