| 12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576 |
- # coding=utf-8
- """
- @project: qabot
- @Author:虎
- @file: lock.py
- @date:2023/9/11 11:45
- @desc:
- """
- from functools import wraps
- import uuid_utils.compat as uuid
- from django.core.cache import caches
- from django_redis import get_redis_connection
- memory_cache = caches['default']
- class RedisLock():
- def __init__(self):
- self.lock_value = None
- def try_lock(self, key: str, timeout=None):
- """
- 获取锁
- :param key: 获取锁 key
- :param timeout 超时时间
- :return: 是否获取到锁
- """
- redis_client = get_redis_connection("default")
- if timeout is None:
- timeout = 3600 # 默认超时时间为3600秒
- self.lock_value = str(uuid.uuid7())
- return redis_client.set(key, self.lock_value, nx=True, ex=timeout)
- def un_lock(self, key: str):
- """
- 解锁
- :param key: 解锁 key
- :return: 是否解锁成功
- """
- redis_client = get_redis_connection("default")
- unlock_script = """
- if redis.call("get", KEYS[1]) == ARGV[1] then
- return redis.call("del", KEYS[1])
- else
- return 0
- end
- """
- redis_client.eval(unlock_script, 1, key, self.lock_value)
- def lock(lock_key, timeout=None):
- """
- 给一个函数上锁
- @param lock_key: 上锁key 字符串|函数 函数返回值为字符串
- @param timeout: 超时时间
- :return: 装饰器函数 当前装饰器主要限制一个key只能一个线程去调用 相同key只能阻塞等待上一个任务执行完毕 不同key不需要等待
- """
- def decorator(func):
- @wraps(func)
- def wrapper(*args, **kwargs):
- key = lock_key(*args, **kwargs) if callable(lock_key) else lock_key
- rlock = RedisLock()
- if not rlock.try_lock(key, timeout):
- # 获取锁失败,可自定义异常或返回
- return None
- try:
- return func(*args, **kwargs)
- finally:
- rlock.un_lock(key)
- return wrapper
- return decorator
|