12345678910111213141516171819202122232425262728293031323334353637383940414243444546 |
- # Credit https://gist.github.com/pardo/19d672235bbef6fa793a
- import functools
- from django.core.cache import cache
- def debounced_wrap(func):
- @functools.wraps(func)
- def wrapper(*args, **kwargs):
- key = kwargs.pop("key") # it's required
- call_count = kwargs.pop("call_count", 1)
- count = cache.get(key, 1)
- if count > call_count:
- # someone called the function again before the this was executed
- return None
- # I'm the last call
- return func(*args, **kwargs)
- return wrapper
- def debounced_task(key_generator):
- """
- :param func: must be the @debounced_wrap decorated with @task / @shared_task from celery
- :param key_generator: function that knows how to generate a key from
- args and kwargs passed to func or a constant str used in the cache
- key will be prepended with function module and name
- :return: function that calls apply_async on the task keep that in mind when send the arguments
- """
- def decorator(func):
- @functools.wraps(func)
- def wrapper(**kwargs):
- func_args = kwargs.get("args", [])
- func_kwargs = kwargs.get("kwargs", {})
- key = f"{func.__module__}.{func.__name__}.{key_generator(*func_args, **func_kwargs)}"
- cache.add(key, 0, 3600)
- call_count = cache.incr(key)
- func_kwargs.update({"key": key, "call_count": call_count})
- kwargs["args"] = func_args
- kwargs["kwargs"] = func_kwargs
- return func.apply_async(**kwargs)
- return wrapper
- return decorator
|