64 lines
2.8 KiB
Markdown
64 lines
2.8 KiB
Markdown
|
|
# 部署与任务调度架构方案 (Deployment & Cron)
|
|||
|
|
|
|||
|
|
## 1. 业务诉求分析
|
|||
|
|
Hermes 作为纯后台的智能体,它的执行过程长达几分钟甚至几小时。它绝不能与提供给前台 HTTP 请求的主 Web 服务混合在同一个事件循环(Event Loop)或同步进程中,否则会导致 API 严重堵塞和超时崩溃。
|
|||
|
|
|
|||
|
|
因此,Hermes 的部署需要进行**进程级解耦**。
|
|||
|
|
|
|||
|
|
## 2. 选型对比与推荐方案
|
|||
|
|
|
|||
|
|
### 方案 A:Celery + Redis (重型/工业级标准)
|
|||
|
|
- **优势**:业界最成熟的 Python 异步任务队列,支持极其复杂的 Cron 配置,原生支持任务重试、失败回调以及分布式扩展。
|
|||
|
|
- **劣势**:增加系统组件(必须额外部署 Redis / RabbitMQ 容器),运维成本相对较高。
|
|||
|
|
- **结论**:如果 X-Financial 后续要承载上千人的企业报销,这是**首选必经之路**。
|
|||
|
|
|
|||
|
|
### 方案 B:APScheduler + Background Worker (中型/轻量级)
|
|||
|
|
- **优势**:直接在 Python 进程内运行,无需额外的消息队列组件。可以用一个单独的 Docker 容器运行 `python run_hermes_scheduler.py`。
|
|||
|
|
- **劣势**:多节点部署时难以控制并发(可能会多个节点同时执行同样的任务),需要引入基于数据库表或 Redis 的分布式锁。
|
|||
|
|
- **结论**:适合初期快速跑通 MVP 的方案。
|
|||
|
|
|
|||
|
|
## 3. 推荐架构:基于 Redis 分布式锁的独立容器方案
|
|||
|
|
结合当前现状,建议采用 **方案B 叠加 分布式锁** 的轻量微服务架构。
|
|||
|
|
|
|||
|
|
### 部署拓扑:
|
|||
|
|
```yaml
|
|||
|
|
# docker-compose.yml 示例切片
|
|||
|
|
services:
|
|||
|
|
x-financial-api:
|
|||
|
|
build: .
|
|||
|
|
command: uvicorn main:app
|
|||
|
|
ports:
|
|||
|
|
- "8000:8000"
|
|||
|
|
|
|||
|
|
x-financial-hermes:
|
|||
|
|
build: .
|
|||
|
|
command: python scripts/start_hermes_daemon.py
|
|||
|
|
# 这个容器不暴露外部端口,纯粹在后台运行定时任务和消费队列
|
|||
|
|
```
|
|||
|
|
|
|||
|
|
### 执行伪代码 (`start_hermes_daemon.py`)
|
|||
|
|
```python
|
|||
|
|
from apscheduler.schedulers.blocking import BlockingScheduler
|
|||
|
|
from app.services.system_hermes import SystemHermesService
|
|||
|
|
|
|||
|
|
scheduler = BlockingScheduler()
|
|||
|
|
hermes = SystemHermesService()
|
|||
|
|
|
|||
|
|
# 每天凌晨 3 点执行深度风控扫表
|
|||
|
|
@scheduler.scheduled_job('cron', hour=3, minute=0)
|
|||
|
|
def job_risk_scan():
|
|||
|
|
# 获取分布式锁防止集群脑裂重复执行
|
|||
|
|
if acquire_redis_lock("hermes:lock:risk_scan"):
|
|||
|
|
try:
|
|||
|
|
hermes.run_query("执行全局风控扫描技能...", skills=["global_risk_scan"])
|
|||
|
|
finally:
|
|||
|
|
release_redis_lock("hermes:lock:risk_scan")
|
|||
|
|
|
|||
|
|
if __name__ == "__main__":
|
|||
|
|
scheduler.start()
|
|||
|
|
```
|
|||
|
|
|
|||
|
|
## 4. 容灾与可观测性保障
|
|||
|
|
- **日志采集**:确保 `hermes.run_query` 及其后台生成的 stdout/stderr 日志能够写入 ELK 或文件系统中,方便第二天的运维排查。
|
|||
|
|
- **告警链路**:如果调度系统挂掉或者大模型连续多次返回失败状态码,必须通过 Webhook 飞书/钉钉及时告警系统管理员。
|