From b9863631bdbfb4d37dbecce2df650125ef7ab2ef Mon Sep 17 00:00:00 2001 From: AKW <2497744746@qq.com> Date: Fri, 29 Dec 2023 15:12:10 +0800 Subject: [PATCH] =?UTF-8?q?=E4=BF=AE=E6=94=B9?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- apps/jqr/models.py | 1 + apps/jqr/tasks.py | 5 +++- utils/redis_lock.py | 58 +++++++++++++++++++++++++++++++++++++++++++++ 3 files changed, 63 insertions(+), 1 deletion(-) create mode 100644 utils/redis_lock.py diff --git a/apps/jqr/models.py b/apps/jqr/models.py index ffa3fde..34f98d3 100644 --- a/apps/jqr/models.py +++ b/apps/jqr/models.py @@ -277,6 +277,7 @@ class JqrKeywordSendGroupMsg(JqrBaseSendMsg): choices=JqrKeywordSendGroupMsgPatternChoices.choices, default=JqrKeywordSendGroupMsgPatternChoices.ANY) keyword_text = models.TextField(verbose_name='关键字数组', null=True, blank=True) + priority = models.IntegerField(verbose_name='优先级', default=0) class Meta: db_table = 'jqr_keywordsendgroupmsg' diff --git a/apps/jqr/tasks.py b/apps/jqr/tasks.py index 01847af..5b031d1 100644 --- a/apps/jqr/tasks.py +++ b/apps/jqr/tasks.py @@ -15,6 +15,7 @@ from apps.jqr.models import JqrExternalFollowUser, JqrExternalUser, JqrHookUser from apps.qc.utils import generate_qrcode_by_qrcode from apps.warning.models import QcWarningRule, WarningLog, WarningSetting from libs.wechat import WechatWorkerUtil +from utils.redis_lock import SimpleLock logger = logging.getLogger('apps') @@ -87,7 +88,9 @@ def save_add_contact_by_channel(data, corpinfo, *args, **kwargs): now = datetime.now() nine_minute_ago = now - timedelta(minutes=9) uid = hook_user.uid - if hook_user.utime > nine_minute_ago and hook_user.new_user: + rc = SimpleLock(f'{corpid}:{userid}:{externaluserid}') + success = rc.try_lock(60 * 10) + if hook_user.utime > nine_minute_ago and hook_user.new_user and success: # 发送消息 send_new_user_msg(corpid, userid, externaluserid, uid=uid) diff --git a/utils/redis_lock.py b/utils/redis_lock.py new file mode 100644 index 0000000..410336f --- /dev/null +++ b/utils/redis_lock.py @@ -0,0 +1,58 @@ +import uuid +from abc import ABC, abstractmethod +from threading import current_thread + +from django_redis import get_redis_connection + +import logging + +logger = logging.getLogger('apps') + + +class ILock(ABC): + + @abstractmethod + def try_lock(self, timeout: int) -> bool: + pass + + @abstractmethod + def unlock(self) -> None: + pass + + +class SimpleLock(ILock): + KEY_PREFIX = "lock:" + # ID_PREFIX = str(uuid.uuid4()).replace("-", '') + "-" + ID_PREFIX = '-' + + def __init__(self, name: str, alias: str = "default") -> None: + self.name = name + self.redis_con = get_redis_connection(alias) + self.key = f"{self.KEY_PREFIX}{self.ID_PREFIX}" + + def try_lock(self, timeout: int) -> bool: + current_thread_id, value = self.get_value() + logger.info(f"线程:{current_thread_id}开始获取锁") + is_locked = self.set_if_absent(self.key, value, timeout) + logger.info(f"线程:{current_thread_id}获取锁是否成功: {bool(is_locked)}") + return bool(is_locked) + + def get_value(self) -> tuple: + current_thread_id = current_thread().ident + value = f"{self.ID_PREFIX}{current_thread_id}" + return current_thread_id, value + + def unlock(self) -> None: + current_thread_id, value = self.get_value() + logger.info(f"线程:{current_thread_id}开始删除锁") + lua_script = """if (redis.call('get', KEYS[1]) == ARGV[1]) then + -- 释放锁 del key + return redis.call('del', KEYS[1]) + end + return 0 + """ + deleted = self.redis_con.eval(lua_script, 1, self.key, value) + logger.info(f"线程:{current_thread_id}删除锁是否成功: {bool(deleted)}") + + def set_if_absent(self, key: str, value: str, timeout: int) -> bool: + return bool(self.redis_con.set(key, value, ex=timeout, nx=True))