返回 MoneyPrinterTurbo
base_manager.py
根目录 / app / controllers / manager / base_manager.py
1 import threading
2 from typing import Any, Callable, Dict
3
4 from loguru import logger
5
6
7 class TaskQueueFullError(ValueError):
8 pass
9
10
11 class TaskManager:
12 def __init__(self, max_concurrent_tasks: int, max_queued_tasks: int = 100):
13 self.max_concurrent_tasks = max_concurrent_tasks
14 self.max_queued_tasks = max_queued_tasks
15 self.current_tasks = 0
16 self.lock = threading.Lock()
17 self.queue = self.create_queue()
18
19 def create_queue(self):
20 raise NotImplementedError()
21
22 def add_task(self, func: Callable, *args: Any, **kwargs: Any):
23 with self.lock:
24 if self.current_tasks < self.max_concurrent_tasks:
25 logger.info(
26 f"add task: {func.__name__}, current_tasks: {self.current_tasks}"
27 )
28 self.execute_task(func, *args, **kwargs)
29 else:
30 queue_size = self.queue_size()
31 # 并发数已满时才进入排队。队列必须有上限,否则匿名接口可以持续
32 # 堆积任务对象和请求参数,最终造成内存耗尽或第三方 API 成本失控。
33 if queue_size >= self.max_queued_tasks:
34 logger.warning(
35 f"reject task: {func.__name__}, queue_size: {queue_size}, "
36 f"max_queued_tasks: {self.max_queued_tasks}"
37 )
38 raise TaskQueueFullError("task queue is full, please try again later")
39
40 logger.info(
41 f"enqueue task: {func.__name__}, current_tasks: {self.current_tasks}, "
42 f"queue_size: {queue_size}"
43 )
44 self.enqueue({"func": func, "args": args, "kwargs": kwargs})
45
46 def execute_task(self, func: Callable, *args: Any, **kwargs: Any):
47 thread = threading.Thread(
48 target=self.run_task, args=(func, *args), kwargs=kwargs
49 )
50 thread.start()
51
52 def run_task(self, func: Callable, *args: Any, **kwargs: Any):
53 try:
54 with self.lock:
55 self.current_tasks += 1
56 func(*args, **kwargs) # call the function here, passing *args and **kwargs.
57 finally:
58 self.task_done()
59
60 def check_queue(self):
61 with self.lock:
62 if (
63 self.current_tasks < self.max_concurrent_tasks
64 and not self.is_queue_empty()
65 ):
66 task_info = self.dequeue()
67 func = task_info["func"]
68 args = task_info.get("args", ())
69 kwargs = task_info.get("kwargs", {})
70 self.execute_task(func, *args, **kwargs)
71
72 def task_done(self):
73 with self.lock:
74 self.current_tasks -= 1
75 self.check_queue()
76
77 def enqueue(self, task: Dict):
78 raise NotImplementedError()
79
80 def dequeue(self):
81 raise NotImplementedError()
82
83 def is_queue_empty(self):
84 raise NotImplementedError()
85
86 def queue_size(self):
87 raise NotImplementedError()
88
88 lines PYTHON