|
@@ -653,3 +653,42 @@ re-fetch the article in the task body:
|
|
|
|
|
|
There might even be performance benefits to this approach, as sending large
|
|
|
messages may be expensive.
|
|
|
+
|
|
|
+Database transactions
|
|
|
+---------------------
|
|
|
+
|
|
|
+Let's look at another example:
|
|
|
+
|
|
|
+.. code-block:: python
|
|
|
+
|
|
|
+ from django.db import transaction
|
|
|
+
|
|
|
+ @transaction.commit_on_success
|
|
|
+ def create_article(request):
|
|
|
+ article = Article.objects.create(....)
|
|
|
+ expand_abbreviations.delay(article.pk)
|
|
|
+
|
|
|
+This is a Django view creating an article object in the database,
|
|
|
+then passing its primary key to a task. It uses the `commit_on_success`
|
|
|
+decorator, which will commit the transaction when the view returns, or
|
|
|
+roll back if the view raises an exception.
|
|
|
+
|
|
|
+There is a race condition if the task starts executing
|
|
|
+before the transaction has been committed: the database object does not exist
|
|
|
+yet!
|
|
|
+
|
|
|
+The solution is to **always commit transactions before applying tasks
|
|
|
+that depends on state from the current transaction**:
|
|
|
+
|
|
|
+.. code-block:: python
|
|
|
+
|
|
|
+ @transaction.commit_manually
|
|
|
+ def create_article(request):
|
|
|
+ try:
|
|
|
+ article = Article.objects.create(...)
|
|
|
+ except:
|
|
|
+ transaction.rollback()
|
|
|
+ raise
|
|
|
+ else:
|
|
|
+ transaction.commit()
|
|
|
+ expand_abbreviations.delay(article.pk)
|