You've already forked pruchase_jhw
first commit
This commit is contained in:
+89
@@ -0,0 +1,89 @@
|
||||
import asyncio
|
||||
import signal
|
||||
import sys
|
||||
from loguru import logger
|
||||
|
||||
from src.config.settings import get_settings
|
||||
from src.config.accounts import load_accounts_config
|
||||
from src.notifications.service import NotificationService
|
||||
from src.utils.logger import setup_logger
|
||||
from src.task_queue.dispatcher import TaskDispatcher
|
||||
from src.task_queue.delay_zset_listener import RedisZSetDelayListener
|
||||
from src.task_queue.listener import RedisStreamListener
|
||||
from src.task_queue.redis_manager import get_redis_manager
|
||||
|
||||
async def main() -> None:
|
||||
"""
|
||||
应用程序主入口函数。
|
||||
- 初始化定制的 Loguru 结构化日志系统。
|
||||
- 校验 Pydantic 配置及多站点账号 YAML 配置文件是否正确。
|
||||
- 针对不同操作系统平台注册优雅退出信号处理器。
|
||||
- 启动 Redis Stream 消息队列持续消费监听循环。
|
||||
"""
|
||||
# 1. 初始化按天分割日志系统
|
||||
setup_logger()
|
||||
logger.info("正在初始化日本采购自动化守护进程...")
|
||||
|
||||
# 2. 启动前快速校验:验证全局环境变量设置与账号配置文件
|
||||
try:
|
||||
settings = get_settings()
|
||||
logger.info(f"应用配置加载成功: APP_ENV={settings.app_env.upper()}")
|
||||
NotificationService(settings).validate_configuration()
|
||||
|
||||
# 解析并校验 accounts.yaml
|
||||
load_accounts_config()
|
||||
await get_redis_manager().initialize()
|
||||
except Exception as e:
|
||||
logger.critical(f"由于配置错误,守护进程启动失败: {e}")
|
||||
sys.exit(1)
|
||||
|
||||
# 3. 实例化核心任务分发器与 Stream 监听器
|
||||
dispatcher = TaskDispatcher()
|
||||
stream_listener = RedisStreamListener(dispatcher)
|
||||
delay_listener = RedisZSetDelayListener(dispatcher)
|
||||
|
||||
# 4. 优雅停机信号处理 (跨平台支持)
|
||||
loop = asyncio.get_running_loop()
|
||||
|
||||
def shutdown_handler(sig_name: str) -> None:
|
||||
logger.warning(f"接收到系统退出信号 '{sig_name}'。正在启动优雅停机流程...")
|
||||
# 触发监听器停止的协程任务
|
||||
asyncio.create_task(stream_listener.stop())
|
||||
asyncio.create_task(delay_listener.stop())
|
||||
|
||||
# Windows 默认的 Proactor 事件循环不支持 add_signal_handler。
|
||||
if sys.platform != "win32":
|
||||
logger.debug("正在注册 Unix 系统信号监听器 (SIGINT / SIGTERM)。")
|
||||
for sig in (signal.SIGINT, signal.SIGTERM):
|
||||
try:
|
||||
loop.add_signal_handler(sig, lambda s=sig: shutdown_handler(s.name))
|
||||
except NotImplementedError:
|
||||
pass
|
||||
else:
|
||||
logger.debug("运行于 Windows 平台。跳过系统信号注册,将直接捕获 KeyboardInterrupt。")
|
||||
|
||||
# 5. 启动消息监听消费主循环
|
||||
try:
|
||||
stream_task = asyncio.create_task(stream_listener.listen())
|
||||
delay_task = asyncio.create_task(delay_listener.listen())
|
||||
await asyncio.gather(stream_task, delay_task)
|
||||
except asyncio.CancelledError:
|
||||
logger.warning("监听器轮询执行被事件循环取消。")
|
||||
except Exception as e:
|
||||
logger.exception(f"主守护进程轮询中发生致命崩溃: {e}")
|
||||
finally:
|
||||
# 保证安全回收与连接断开
|
||||
await asyncio.gather(
|
||||
stream_listener.stop(),
|
||||
delay_listener.stop(),
|
||||
get_redis_manager().close(),
|
||||
return_exceptions=True,
|
||||
)
|
||||
logger.success("日本采购自动化守护进程已安全优雅退出。")
|
||||
|
||||
if __name__ == "__main__":
|
||||
try:
|
||||
asyncio.run(main())
|
||||
except KeyboardInterrupt:
|
||||
logger.warning("捕获到键盘手动中断。立即退出程序...")
|
||||
sys.exit(0)
|
||||
Reference in New Issue
Block a user