-
Notifications
You must be signed in to change notification settings - Fork 46
Open
Labels
tasks-apiIssues relating to the tasks API and general API contract from the libraryIssues relating to the tasks API and general API contract from the library
Description
In django_tasks.backends.database.DatabaseBackend there is a parameter ENQUEUE_ON_COMMIT to control whether tasks should enqueue in the same transaction, or after the transaction commits using transaction.on_commit. The default is to enqueue on commit - not in the same transaction.
Consider this example:
from django.db import transaction
from django_tasks import task
@task()
def send_email(to: str, message: str) -> None:
print(f"Sending email to {to}: {message}")
def notify_user(order_id: int) -> Order:
with transaction.atomic():
order = Order.objects.select_for_update().get(id=order_id)
if order.user_notified:
return order
# ↓↓↓ What happens if this fails? ↓↓↓
send_email.enqueue(order.user.email, "Your order has been completed.")
order.user_notified = True
order.save()
return orderIf for some reason send_email.enqueue failed to enqueue (not execute! enqueue...):
- If enqueue happens in the same database transaction -> an exception will raise, the process will rollback,
user_notifiedwill remain False (good!) - If enqueue happens on_commit -> an exception will raise, the function will fail,
user_notifiedwill be True (bad!)
The problem in the second scenario is that when enqueue failed, the transaction already committed and set user_notified to True. This is bad because the user was not, and will not, be notified which is inconsistent with what we just committed to the db.
I think a safer default would be False - enqueue in the same transaction.
Metadata
Metadata
Assignees
Labels
tasks-apiIssues relating to the tasks API and general API contract from the libraryIssues relating to the tasks API and general API contract from the library