import logging import os from logging.handlers import RotatingFileHandler from queue import Queue import threading from apscheduler.schedulers.background import BackgroundScheduler from urllib.parse import unquote class AppTools: def __init__(self, config): self.config = config self.task_queue = Queue() self.logger = self._setup_logger() self.scheduler = self._setup_scheduler() self._start_task_thread() def _setup_logger(self): """配置日志记录器(不依赖 Flask)。""" log_dir = self.config.LOGS_DIRECTORY if not os.path.exists(log_dir): os.makedirs(log_dir) log_file = self.config.LOG_FILE logger = logging.getLogger("app") logger.setLevel(logging.INFO) # 防止重复添加 handler if not any(isinstance(h, RotatingFileHandler) and getattr(h, 'baseFilename', None) == str(log_file) for h in logger.handlers): file_handler = RotatingFileHandler(log_file, maxBytes=1024 * 1024 * 5, backupCount=5, encoding='utf-8') file_handler.setLevel(logging.INFO) formatter = logging.Formatter('%(asctime)s %(levelname)s:%(name)s:%(message)s') file_handler.setFormatter(formatter) logger.addHandler(file_handler) return logger def _setup_scheduler(self): """配置后台调度器""" scheduler = BackgroundScheduler() # 如需定时任务可在此添加 import atexit atexit.register(lambda: scheduler.shutdown(wait=False)) return scheduler def _start_task_thread(self): """启动任务处理线程""" task_thread = threading.Thread(target=self.process_tasks, daemon=True) task_thread.start() def process_tasks(self): """处理任务队列中的任务""" while True: task = self.task_queue.get() if task is None: self.logger.error("任务处理线程已终止") break try: result = task['handler'](task['data']) task['response'].put(result) except Exception as e: self.logger.error(f"任务执行失败: {str(e)}") task['response'].put({'msg': f'任务执行失败: {str(e)}'}) finally: self.task_queue.task_done() self.logger.info("任务处理完成") def enqueue_task(self, handler, data): """将任务放入消息队列""" response_queue = Queue() self.task_queue.put({ 'handler': handler, 'data': data, 'response': response_queue }) return response_queue @staticmethod def decode_headers(headers): """解码包含中文字符的 HTTP 请求头""" return {key: unquote(value, encoding='utf-8') for key, value in headers.items()} # 简易的全局日志记录器设置(与原项目解耦) logger = None def setup_global_logger(config): global logger if logger is None: app_tools = AppTools(config) logger = app_tools.logger return logger