Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Don't return lock after task ends #104

Open
steverecio opened this issue Jun 19, 2019 · 3 comments
Open

Don't return lock after task ends #104

steverecio opened this issue Jun 19, 2019 · 3 comments

Comments

@steverecio
Copy link

I want a task to not release the lock when it returns. Effectively, when task_A is called with the same signature, I want it to fail gracefully until redis expires the lock. This ensures the same task can't be called with the same signature until the cache releases the lock after the default timeout.

I tried unlock_before_run but that doesn't seem to work. With my current set up, Once blocks tasks from being run in parallel but I want to enforce an hour long blocking period until a task with the same signature can be re-run. (For context, I'm doing this to prevent multiple notification emails from getting sent within a short time period in my app)

@cameronmaske
Copy link
Owner

Hi, @steverecio that's an interesting use case!

Possibly the simplest/quickest way to get something into your project, could be to customize the Redis backend, and just remove the logic currently in the clear_lock (i.e. don't delete the key, just let it expire).

Once down, you can point to your custom backend, in your project in the configuration.

celery.conf.ONCE = {
  'backend': 'myproject.custom_backends.CustomRedis', # for example
  'settings': {
    'url': 'redis://localhost:6379/0',
    'default_timeout': 60 * 60
  }
}

I'd be interested to see if others want this functionality, as it could be something we include as a default on the task itself, something like (the naming of the option needs work)

@celery.task(base=QueueOnce, once={'unlock_after_run': False})
def example(a, b):
	....

@steverecio
Copy link
Author

Hey @cameronmaske

Thanks, that did the trick. I implemented the custom backend below for reference:

from celery_once.backends import Redis


class OnceBackend(Redis):
    """
    Overrides clear lock so that keys are not returned but left to expire.
    This prevents multiple notification emails from getting sent.
    """
    def clear_lock(self, key):
        pass
app.conf.ONCE = {
  'backend': 'project.taskapp.backends.OnceBackend',
  'settings': {
      'url': settings.CELERY_BROKER_URL,
      'default_timeout': 60 * 60
  }
}

This would definitely be nice to have as an option in the default Redis backend so that it can be configured more easily per task. I like the option unlock_after_run that you mentioned 👍

@frankV
Copy link

frankV commented May 17, 2020

@cameronmaske I too would like to use something like unlock_after_run to control this behavior per task, but while you're waiting to collect broader feedback to that - do you have an idea of how you might handle it? Just curious if it can be patched in as the override to clear_lock.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

3 participants