mirror of https://github.com/jumpserver/jumpserver
				
				
				
			
		
			
				
	
	
		
			135 lines
		
	
	
		
			3.1 KiB
		
	
	
	
		
			Python
		
	
	
			
		
		
	
	
			135 lines
		
	
	
		
			3.1 KiB
		
	
	
	
		
			Python
		
	
	
# -*- coding: utf-8 -*-
 | 
						|
#
 | 
						|
import functools
 | 
						|
import inspect
 | 
						|
import time
 | 
						|
import uuid
 | 
						|
from concurrent.futures import ThreadPoolExecutor
 | 
						|
 | 
						|
from django.core.cache import cache
 | 
						|
from django.db import transaction
 | 
						|
 | 
						|
 | 
						|
def on_transaction_commit(func):
 | 
						|
    """
 | 
						|
    如果不调用on_commit, 对象创建时添加多对多字段值失败
 | 
						|
    """
 | 
						|
 | 
						|
    def inner(*args, **kwargs):
 | 
						|
        transaction.on_commit(lambda: func(*args, **kwargs))
 | 
						|
 | 
						|
    return inner
 | 
						|
 | 
						|
 | 
						|
class Singleton(object):
 | 
						|
    """ 单例类 """
 | 
						|
 | 
						|
    def __init__(self, cls):
 | 
						|
        self._cls = cls
 | 
						|
        self._instance = {}
 | 
						|
 | 
						|
    def __call__(self):
 | 
						|
        if self._cls not in self._instance:
 | 
						|
            self._instance[self._cls] = self._cls()
 | 
						|
        return self._instance[self._cls]
 | 
						|
 | 
						|
 | 
						|
def _run_func_if_is_last(ttl, func, *args, **kwargs):
 | 
						|
    ix = uuid.uuid4().__str__()
 | 
						|
    key = f'DELAY_RUN_{func.__name__}'
 | 
						|
    cache.set(key, ix, ttl)
 | 
						|
    st = (ttl - 2 > 1) and ttl - 2 or 2
 | 
						|
    time.sleep(st)
 | 
						|
    got = cache.get(key, None)
 | 
						|
 | 
						|
    if ix == got:
 | 
						|
        func(*args, **kwargs)
 | 
						|
 | 
						|
 | 
						|
executor = ThreadPoolExecutor(10)
 | 
						|
 | 
						|
 | 
						|
def delay_run(ttl=5):
 | 
						|
    def inner(func):
 | 
						|
        @functools.wraps(func)
 | 
						|
        def wrapper(*args, **kwargs):
 | 
						|
            executor.submit(_run_func_if_is_last, ttl, func, *args, **kwargs)
 | 
						|
 | 
						|
        return wrapper
 | 
						|
 | 
						|
    return inner
 | 
						|
 | 
						|
 | 
						|
def _merge_run(ttl, func, *args, **kwargs):
 | 
						|
    if not args or not isinstance(args[0], (list, tuple)):
 | 
						|
        raise ValueError('args[0] must be list or tuple')
 | 
						|
 | 
						|
    key = f'DELAY_MERGE_RUN_{func.__name__}'
 | 
						|
    ix = uuid.uuid4().__str__()
 | 
						|
    value = cache.get(key, [])
 | 
						|
    value.extend(args[0])
 | 
						|
 | 
						|
    st = (ttl - 2 > 1) and ttl - 2 or 2
 | 
						|
    time.sleep(st)
 | 
						|
    got = cache.get(key, None)
 | 
						|
 | 
						|
    if ix == got:
 | 
						|
        func(*args, **kwargs)
 | 
						|
 | 
						|
 | 
						|
def merge_delay_run(ttl):
 | 
						|
    """
 | 
						|
    合并 func 参数,延迟执行, 在 ttl 秒内, 只执行最后一次
 | 
						|
    func 参数必须是 *args
 | 
						|
    :param ttl:
 | 
						|
    :return:
 | 
						|
    """
 | 
						|
 | 
						|
    def inner(func):
 | 
						|
        sigs = inspect.signature(func)
 | 
						|
        if len(sigs.parameters) != 1:
 | 
						|
            raise ValueError('func must have one arguments: %s' % func.__name__)
 | 
						|
        param = list(sigs.parameters.values())[0]
 | 
						|
        if not str(param).startswith('*'):
 | 
						|
            raise ValueError('func args must be startswith *: %s' % func.__name__)
 | 
						|
 | 
						|
        @functools.wraps(func)
 | 
						|
        def wrapper(*args):
 | 
						|
            key = f'DELAY_MERGE_RUN_{func.__name__}'
 | 
						|
            values = cache.get(key, [])
 | 
						|
            new_arg = [*values, *args]
 | 
						|
            cache.set(key, new_arg, ttl)
 | 
						|
            return delay_run(ttl)(func)(*new_arg)
 | 
						|
 | 
						|
        return wrapper
 | 
						|
 | 
						|
    return inner
 | 
						|
 | 
						|
 | 
						|
def delay_run(ttl=5):
 | 
						|
    """
 | 
						|
    延迟执行函数, 在 ttl 秒内, 只执行最后一次
 | 
						|
    :param ttl:
 | 
						|
    :return:
 | 
						|
    """
 | 
						|
 | 
						|
    def inner(func):
 | 
						|
        @functools.wraps(func)
 | 
						|
        def wrapper(*args, **kwargs):
 | 
						|
            executor.submit(_run_func_if_is_last, ttl, func, *args, **kwargs)
 | 
						|
 | 
						|
        return wrapper
 | 
						|
 | 
						|
    return inner
 | 
						|
 | 
						|
 | 
						|
@delay_run(ttl=10)
 | 
						|
def test_delay_run(username, year=2000):
 | 
						|
    print("Hello, %s, now is %s" % (username, year))
 | 
						|
 | 
						|
 | 
						|
@merge_delay_run(ttl=10)
 | 
						|
def test_merge_delay_run(*users):
 | 
						|
    name = ','.join(users)
 | 
						|
    print("Hello, %s, now is %s" % (name, time.time()))
 |