Skip to content

Should ENQUEUE_ON_COMMIT default to False? #189

@hakib

Description

@hakib

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 order

If 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_notified will remain False (good!)
  • If enqueue happens on_commit -> an exception will raise, the function will fail, user_notified will 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

No one assigned

    Labels

    tasks-apiIssues relating to the tasks API and general API contract from the library

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions