From 07e1918fa1e14a8e0e663aae202000840ae842b4 Mon Sep 17 00:00:00 2001 From: ibuler Date: Fri, 17 Nov 2023 17:07:24 +0800 Subject: [PATCH] =?UTF-8?q?perf:=20=E4=BC=98=E5=8C=96=E5=BB=B6=E8=BF=9F?= =?UTF-8?q?=E8=BF=90=E8=A1=8C?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit fix: 延迟执行设置超时 perf: 修改 delay run perf: 优化 delay_run 执行 perf: 修改 delay run --- apps/authentication/backends/drf.py | 24 +++++++++++++----------- apps/common/decorators.py | 25 ++++++++++++++++++++----- apps/orgs/signal_handlers/common.py | 2 +- 3 files changed, 34 insertions(+), 17 deletions(-) diff --git a/apps/authentication/backends/drf.py b/apps/authentication/backends/drf.py index f6818e4a4..86999037d 100644 --- a/apps/authentication/backends/drf.py +++ b/apps/authentication/backends/drf.py @@ -8,7 +8,7 @@ from django.utils.translation import gettext as _ from rest_framework import authentication, exceptions from common.auth import signature -from common.decorators import delay_run +from common.decorators import merge_delay_run from common.utils import get_object_or_none, get_request_ip_or_data, contains_ip from ..models import AccessKey, PrivateToken @@ -17,22 +17,24 @@ def date_more_than(d, seconds): return d is None or (timezone.now() - d).seconds > seconds -@delay_run(ttl=60) -def update_token_last_used(token): - token.date_last_used = timezone.now() - token.save(update_fields=['date_last_used']) +@merge_delay_run(ttl=60) +def update_token_last_used(tokens=()): + for token in tokens: + token.date_last_used = timezone.now() + token.save(update_fields=['date_last_used']) -@delay_run(ttl=60) -def update_user_last_used(user): - user.date_api_key_last_used = timezone.now() - user.save(update_fields=['date_api_key_last_used']) +@merge_delay_run(ttl=60) +def update_user_last_used(users=()): + for user in users: + user.date_api_key_last_used = timezone.now() + user.save(update_fields=['date_api_key_last_used']) def after_authenticate_update_date(user, token=None): - update_user_last_used(user) + update_user_last_used(users=(user,)) if token: - update_token_last_used(token) + update_token_last_used(tokens=(token,)) class AccessTokenAuthentication(authentication.BaseAuthentication): diff --git a/apps/common/decorators.py b/apps/common/decorators.py index 353407ab1..24b2695d3 100644 --- a/apps/common/decorators.py +++ b/apps/common/decorators.py @@ -73,6 +73,7 @@ executor = ThreadPoolExecutor( ) _loop_debouncer_func_task_cache = {} _loop_debouncer_func_args_cache = {} +_loop_debouncer_func_task_time_cache = {} def get_loop(): @@ -92,6 +93,17 @@ def cancel_or_remove_debouncer_task(cache_key): def run_debouncer_func(cache_key, org, ttl, func, *args, **kwargs): cancel_or_remove_debouncer_task(cache_key) run_func_partial = functools.partial(_run_func_with_org, cache_key, org, func) + + current = time.time() + first_run_time = _loop_debouncer_func_task_time_cache.get(cache_key, None) + if first_run_time is None: + _loop_debouncer_func_task_time_cache[cache_key] = current + first_run_time = current + + if current - first_run_time > ttl: + executor.submit(run_func_partial, *args, **kwargs) + return + loop = _loop_thread.get_loop() _debouncer = Debouncer(run_func_partial, lambda: True, ttl, loop=loop, executor=executor) task = asyncio.run_coroutine_threadsafe(_debouncer(*args, **kwargs), loop=loop) @@ -130,6 +142,7 @@ def _run_func_with_org(key, org, func, *args, **kwargs): logger.error('delay run error: %s' % e) _loop_debouncer_func_task_cache.pop(key, None) _loop_debouncer_func_args_cache.pop(key, None) + _loop_debouncer_func_task_time_cache.pop(key, None) def delay_run(ttl=5, key=None): @@ -142,6 +155,9 @@ def delay_run(ttl=5, key=None): def inner(func): suffix_key_func = key if key else default_suffix_key + sigs = inspect.signature(func) + if len(sigs.parameters) != 0: + raise ValueError('Merge delay run must not arguments: %s' % func.__name__) @functools.wraps(func) def wrapper(*args, **kwargs): @@ -186,12 +202,11 @@ def merge_delay_run(ttl=5, key=None): for k, v in kwargs.items(): if not isinstance(v, (tuple, list, set)): raise ValueError('func kwargs value must be list or tuple: %s %s' % (func.__name__, v)) + v = set(v) if k not in cache_kwargs: cache_kwargs[k] = v - elif isinstance(v, set): - cache_kwargs[k] = cache_kwargs[k].union(v) else: - cache_kwargs[k] = list(cache_kwargs[k]) + list(v) + cache_kwargs[k] = cache_kwargs[k].union(v) _loop_debouncer_func_args_cache[cache_key] = cache_kwargs run_debouncer_func(cache_key, org, ttl, func, *args, **cache_kwargs) @@ -201,8 +216,8 @@ def merge_delay_run(ttl=5, key=None): @delay_run(ttl=5) -def test_delay_run(username): - print("Hello, %s, now is %s" % (username, time.time())) +def test_delay_run(): + print("Hello, now is %s" % time.time()) @merge_delay_run(ttl=5, key=lambda users=(): users[0][0]) diff --git a/apps/orgs/signal_handlers/common.py b/apps/orgs/signal_handlers/common.py index 83edeb425..57333a2e8 100644 --- a/apps/orgs/signal_handlers/common.py +++ b/apps/orgs/signal_handlers/common.py @@ -53,7 +53,7 @@ def subscribe_orgs_mapping_expire(sender, **kwargs): @delay_run(ttl=5) -def expire_user_orgs(*args): +def expire_user_orgs(): User.expire_users_rbac_perms_cache()