Decorator to execute a method only once

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
from functools import wraps
from django.core.cache import cache

def execute_once_in(seconds):
    """
    This decorator wraps a normal function
    so that it can be executed only once in the next few seconds.

    Useful to make Celery email sending tasks idempotent and safeguard
    against SQS messages delivered twice (in rare cases).

    Usage:

    @task
    @execute_once_in(3600)
    def myfunction():
        pass

    If called multiple times, the above method will be executed only one
    time during the next hour following its first execution.
    """

    def decorator(func):
        def inner_decorator(*args, **kwargs):
            key = "%s.%s" % (func.__module__, func.__name__)
            key = key.replace(' ','_') # memcache doesn't like spaces

            # NB: there's no way to tell if
            # func() didn't execute or returned nothing
            if cache.get(key):
                return

            cache.set(key, True, seconds)
            return func(*args, **kwargs)


        return wraps(func)(inner_decorator)

    return decorator

More like this

  1. Using Templates to Send E-Mails by rpoulton 7 years, 1 month ago
  2. Execute a signal once by johnnoone 4 years, 11 months ago
  3. group_required decorator by msanders 4 years, 8 months ago
  4. EmailListField for Django by sciyoshi 4 years, 8 months ago
  5. DebugFooter middleware with syntax highlighting and code inspection by monolar 5 years, 10 months ago

Comments

(Forgotten your password?)