Skip to content

Decorators

exactly_once

django_periodic_tasks.decorators.exactly_once(func)

Decorator ensuring a scheduled task runs at most once per invocation.

When :meth:~django_periodic_tasks.models.ScheduledTask.enqueue_now (used by both the scheduler and the Django admin “Run now” action) creates a TaskExecution row and passes its ID via the _periodic_tasks_execution_id keyword argument, this decorator will:

  1. Pop _periodic_tasks_execution_id from kwargs.
  2. Lock the TaskExecution row with SELECT FOR UPDATE.
  3. Run the wrapped function only if the row’s status is PENDING.
  4. Mark the row COMPLETED on success.

If _periodic_tasks_execution_id is absent (e.g. manual invocation), the wrapped function runs normally without any execution-permit logic.

.. warning::

This decorator is designed exclusively for tasks managed by
:class:~django_periodic_tasks.models.ScheduledTask.  The
deduplication guarantee depends on
:func:~django_periodic_tasks.enqueue.enqueue_scheduled_task creating a
</span><span class="n">TaskExecution</span><span class="n n-Quoted"> row and injecting </span><span class="n">_periodic_tasks_execution_id</span><span class="n n-Quoted">
into the task kwargs before enqueue.

Calling a </span><span class="nv">@exactly_once</span><span class="n n-Quoted">-decorated task directly via
</span><span class="n">task</span><span class="p">.</span><span class="n">enqueue</span><span class="p">()</span><span class="n n-Quoted"> (bypassing </span><span class="n">ScheduledTask</span><span class="n n-Quoted">) will run the function
normally but without any deduplication protection.