# /// # queue_service.py # 描述:消息队列服务,支持Redis后端 # 作者:AI Generated # 创建日期:2026-04-05 # /// import asyncio import json from typing import Dict, Any, Optional, Callable from datetime import datetime from enum import Enum from config import get_settings class QueueName(Enum): MESSAGE_SEND = "wxauto:queue:message_send" MESSAGE_BROADCAST = "wxauto:queue:message_broadcast" class QueueService: def __init__(self): self._redis_client = None self._redis_available = False self._local_queue = asyncio.Queue() self._init_redis() self._worker_task = None self._running = False def _init_redis(self): try: import redis settings = get_settings() redis_config = settings.redis self._redis_client = redis.from_url( redis_config.url, db=redis_config.db, password=redis_config.password, decode_responses=True ) self._redis_client.ping() self._redis_available = True except Exception: self._redis_available = False self._redis_client = None def enqueue(self, queue_name: QueueName, data: Dict[str, Any]) -> bool: job_data = { "data": data, "enqueued_at": datetime.now().isoformat(), "status": "pending" } if self._redis_available: try: self._redis_client.rpush(queue_name.value, json.dumps(job_data, ensure_ascii=False)) return True except Exception: return False else: try: asyncio.create_task(self._local_enqueue(queue_name, job_data)) return True except Exception: return False async def _local_enqueue(self, queue_name: QueueName, job_data: Dict[str, Any]): await self._local_queue.put((queue_name, job_data)) async def dequeue(self, queue_name: QueueName, timeout: int = 1) -> Optional[Dict[str, Any]]: if self._redis_available: try: result = self._redis_client.blpop(queue_name.value, timeout=timeout) if result: _, job_data = result return json.loads(job_data) except Exception: pass else: try: queue_item = await asyncio.wait_for(self._local_queue.get(), timeout=timeout) if queue_item and queue_item[0] == queue_name: return queue_item[1] except asyncio.TimeoutError: pass return None def get_queue_length(self, queue_name: QueueName) -> int: if self._redis_available: try: return self._redis_client.llen(queue_name.value) except Exception: pass return 0 def start_worker(self, processor: Callable): if self._running: return self._running = True self._worker_task = asyncio.create_task(self._worker_loop(processor)) async def _worker_loop(self, processor: Callable): while self._running: for queue_name in [QueueName.MESSAGE_SEND]: job = await self.dequeue(queue_name, timeout=1) if job: try: await processor(job) except Exception as e: pass def stop_worker(self): self._running = False if self._worker_task: self._worker_task.cancel() queue_service = QueueService()