The exact configuration, depends on which locking backend you want to use. See Backends.

Behind the scenes, this overrides apply_async and delay. It does not affect calling the tasks directly.

When running the task, celery_once checks that no lock is in place (against a Redis key).
If it isn’t, the task will run as normal. Once the task completes (or ends due to an exception) the lock will clear.
If an attempt is made to run the task again before it completes an AlreadyQueued exception will be raised.

graceful

Optionally, instead of raising an AlreadyQueued exception, the task can return None if once={'graceful': True} is set in the task’s options or when run through apply_async.

fromcelery_onceimportAlreadyQueued# Either catch the exception,try:example.delay(10)exceptAlreadyQueued:pass# Or, handle it gracefully at run time.result=example.apply(args=(10),once={'graceful':True})# or by default.@celery.task(base=QueueOnce,once={'graceful':True})defslow_task():sleep(30)return"Done!"

keys

By default celery_once creates a lock based on the task’s name and its arguments and values.
Take for example, the following task below…

@celery.task(base=QueueOnce)defslow_add(a,b):sleep(30)returna+b

Running the task with different arguments will default to checking against different locks.

slow_add(1,1)slow_add(1,2)

If you want to specify locking based on a subset, or no arguments you can adjust the keys celery_once looks at in the task’s options with once={'keys':[..]}

unlock_before_run

By default, the lock is removed after the task has executed (using celery’s after_return). This behaviour can be changed setting the task’s option unlock_before_run. When set to True, the lock will be removed just before executing the task.

Caveats:

Any retry of the task won’t re-enable the lock!

This can only be set when defining the task, it cannot be passed dynamically to apply_async

Backends

Redis Backend

Redis is used as a distributed locking mechanism. Behind the scenes, it use Redlock. This page has more infomation about the locking guarantees.

Configuration:

backend - celery_once.backends.Redis

settings

default_timeout - how many seconds after a lock has been set before it should automatically timeout (defaults to 3600 seconds, or 1 hour).

url - should point towards a running Redis instance (defaults to redis://localhost:6379/0). See below for the format options supported

blocking (boolean value: default False) - If set to True, scheduling a task (by .delay/.apply_async) will block for X seconds to acquire the lock (see: blocking_timeout below). If no lock could be acquired after X seconds, will raise an AlreadyQueued exception. This is a very specific use-case scenario and by default is disabled.

blocking_timeout (int or float value: default 1) - How many seconds the task will block trying to aquire the lock, if blocking is set to True. Setting this to None set’s no timeout (equivalent to infinite seconds).

The URL parser supports two patterns of urls:

redis://host:port[/db][?options]: redis over TCP

redis+socket:///path/to/redis.sock[?options]: redis over a UNIX socket