自托管 AI-Trader 如何把 API 与后台 worker 拆成独立进程启动并确认单实例运行?
2026/9/14 5:08:32 网站建设 项目流程

自托管 AI-Trader 如何把 API 与后台 worker 拆成独立进程启动并确认单实例运行?

【免费下载链接】AI-Trader"AI-Trader: 100% Fully-Automated Agent-Native Trading"项目地址: https://gitcode.com/GitHub_Trending/aitrad/AI-Trader

如果你自托管 AI-Trader,会遇到一个明确的部署问题:FastAPI 服务既要对 HTTP 请求低延迟响应,又要周期性地拉取行情价格、结算 Polymarket 仓位、压缩利润历史这些重活。这个仓库给出的方案是把两者拆成两个进程:API 进程默认只做 HTTP 服务(见 main.py 中AI_TRADER_API_BACKGROUND_TASKS默认 false 的分支),后台循环放进独立的 worker.py,并且 worker 自带 Redis / 文件两级单实例锁。本文的操作路径是:装依赖、配环境 → 启动 API 进程 → 启动 worker 进程 → 用日志和锁文件确认只有一个 worker 在跑、任务确实在执行。

拆分方式:两个入口进程,任务清单共享

两个入口都依赖 tasks.py 中的同一份后台任务注册表BACKGROUND_TASK_REGISTRY,包含 14 个任务:

pricesprofit_historypolymarket_settlementchallenge_settlementteam_mission_formteam_contribution_scoreteam_mission_settlementsignal_quality_scoreagent_metric_snapshotsnetwork_edgesmarket_newsmacro_signalsetf_flowsstock_analysis

  • API 进程:main.py 通过background_tasks_enabled_for_api()判断是否在本进程内启动后台任务,该开关读取AI_TRADER_API_BACKGROUND_TASKS默认 false。关闭时启动日志会明确提示:

    API background tasks disabled. Run `python service/server/worker.py` to process prices, profit history, settlements, and market intel.
  • worker 进程:worker.py 的模块注释写明它就是为此设计的——“Run this separately from the FastAPI process so HTTP requests are not competing with price refreshes, profit-history compaction, and market-intel snapshots.”。它启动时若未设置AI_TRADER_BACKGROUND_TASKS,会默认启用全部任务(DEFAULT_BACKGROUND_TASKS)。

也就是说,默认配置下正确的拓扑是:API 进程 HTTP-only,worker 进程负责所有后台循环。

准备环境

  1. 安装后端依赖(service/requirements.txt 包含fastapiuvicorn[standard]redis等):

    pip install -r service/requirements.txt
  2. 按 README.md 的 “Self-hosting (database)” 一节配置数据库:复制.env.example.env,二选一——

    • PostgreSQL:设置DATABASE_URL=postgresql://...(共享或生产部署推荐);
    • SQLite:留空DATABASE_URL,使用DB_PATH(默认service/server/data/clawtrader.db,仅限本地快速启动)。

    优先级规则:DATABASE_URL非空时用 PostgreSQL,DB_PATH被忽略。两个进程会连接同一个数据库,所以必须使用同一份.env环境。

  3. (可选)配置 Redis,用于跨机器的 worker 单实例锁。config.py 读取以下变量:

    REDIS_ENABLED=true REDIS_URL=redis://... # 你的 Redis 地址 REDIS_PREFIX=ai_trader # 键前缀,默认 ai_trader

    不配置 Redis 也能跑,worker 会自动回退到本机文件锁,见下文。

启动 API 进程

在仓库根目录执行(main.py 的__main__分支直接以host="0.0.0.0", port=8000调用 uvicorn):

python service/server/main.py

启动后先观察两类日志判断 API 侧状态:

  • 数据库与缓存状态行,如Database ready: backend=...Cache ready: enabled=... configured=...
  • 确认走到了 HTTP-only 分支,即出现上文那句API background tasks disabled. Runpython service/server/worker.py...。如果没看到这句而是看到Background tasks started: N,说明AI_TRADER_API_BACKGROUND_TASKS被设成了真值,此时 API 进程已经在跑后台任务,不要再启动 worker.py,否则同一组任务会在两个进程里重复执行(worker 锁只约束 worker 进程,不约束 API 进程)。

验证 API 可用:/health端点定义在 routes_market.py,返回{'status': 'ok', 'timestamp': <UTC 时间>}

curl http://127.0.0.1:8000/health

启动 worker 进程

另开一个终端(同一仓库根目录)执行:

python service/server/worker.py

启动后的预期日志(按 worker.py 中的logger输出顺序):

  1. 单实例锁获取成功,二选一:
    • Acquired worker singleton lock via Redis(配置了 Redis 时);
    • Acquired worker singleton lock via file(无 Redis 或 Redis 客户端不可用时)。
  2. Worker database ready: {...},确认 worker 连上了同一个数据库。
  3. 每启动一个任务输出一行Starting background task: <任务名>,任务名与AI_TRADER_BACKGROUND_TASKS中的清单一一对应。

如果看到No background tasks enabled; set AI_TRADER_BACKGROUND_TASKS to a comma-separated task list.,说明你显式设置的AI_TRADER_BACKGROUND_TASKS里没有任何注册表中的合法任务名,需要检查拼写。

按需裁剪任务:AI_TRADER_BACKGROUND_TASKS是逗号分隔的任务名列表,只写你需要的子集,例如只跑价格刷新和利润历史:

AI_TRADER_BACKGROUND_TASKS=prices,profit_history python service/server/worker.py

确认 worker 单实例运行

worker 在启动早期就竞争单实例锁,逻辑见 worker.py 与 cache.py 的acquire_lock

  • Redis 锁:配置了 Redis 时,worker 尝试获取键worker:singleton的锁(非阻塞,blocking=False)。锁超时时间由AI_TRADER_WORKER_LOCK_TIMEOUT_SECONDS控制,代码中下限为 30 秒、默认 120 秒,worker 运行期间会周期性reacquire续期;若续期失败(锁被抢走),worker 记录Lost worker singleton Redis lock: ...后直接退出(os._exit(1)),避免双实例并发。

  • 文件锁:Redis 不可用时回退到fcntl.flock对锁文件加非阻塞排他锁,默认路径/tmp/ai-trader-worker.lock,可用AI_TRADER_WORKER_LOCK_FILE覆盖。拿到锁后 worker 会把自己的 PID 写入该文件,因此锁文件同时是一个单实例证明:

    cat /tmp/ai-trader-worker.lock # 输出应为正在运行的 worker 的 PID

判定方法:再开一个终端重复执行python service/server/worker.py。第二个进程不应继续运行,而会打印下面之一后退出:

Another AI-Trader worker is already running; Redis singleton lock is held.

Another AI-Trader worker is already running; lock_file=/tmp/ai-trader-worker.lock

看到这条 WARNING 且进程退出,即单实例机制生效;如果第二个进程继续打出Starting background task:日志,说明两个进程没共享同一把锁(典型原因:不同机器/容器之间没有共享 Redis 也没有共享文件系统,此时文件锁无法跨主机生效,需要配置 Redis 锁)。

相关环境变量汇总(均有默认值,只列影响拆分部署的项):

变量默认值作用
AI_TRADER_API_BACKGROUND_TASKSfalse是否让 API 进程内跑后台任务;拆分部署保持默认
AI_TRADER_BACKGROUND_TASKS全部 14 个任务worker 启用的任务清单,逗号分隔
AI_TRADER_WORKER_LOCK_FILE/tmp/ai-trader-worker.lock文件锁路径
AI_TRADER_WORKER_LOCK_TIMEOUT_SECONDS120(下限 30)Redis 锁超时/续期周期基准
AI_TRADER_WORKER_NICE10worker 启动时对自己的进程设置 nice 值,降低其调度优先级
PROFIT_HISTORY_PRUNE_ON_WORKER_STARTfalsetrue 时 worker 启动后额外调度一次利润历史 prune

注意fcntl是 Unix/Linux 机制,文件锁路径适用于 Linux 类系统;跨主机部署应以 Redis 锁为准。

确认后台任务确实在执行

锁只证明“只有一个 worker”,任务是否真在跑看周期性日志。以下均为 tasks.py 代码中的输出格式,具体数值随行情和数据库内容变化,仅作格式参照:

[Price Update] candidates=... skipped_unsupported=... ... [Price Update] summary requested=... updated=... failed=... [Profit History] Recorded profit for N agents in X.XXs [Polymarket Settler] positions=... settled=... skipped=... [Market Intel] Refreshed market news snapshots: inserted_categories=... errors=...

例如prices任务每轮结束会打印下一轮间隔([Price Update] Next update in {refresh_interval} seconds,间隔由POSITION_REFRESH_INTERVAL控制,默认 900 秒,.env.example中示例值为 300 秒)。若某任务持续打印[... Error]行而没有正常 summary 行,说明该任务在报错空转,对照行首的[Task Name]前缀定位是哪个循环。

限制与下一步

  • 文件锁只在本机有效;多台机器/容器部署 worker 时必须配置REDIS_ENABLED=trueREDIS_URL,由 Redis 锁保证全局单实例。
  • AI_TRADER_API_BACKGROUND_TASKS与 worker.py 是两条互斥路径:默认走 worker.py;若把它设为 true 让 API 进程内跑任务,就不要再起 worker,避免同一任务双跑。
  • 仓库的本地生产运维文档 docs/local-ops/production-branch.md 提到生产 API 服务以 systemd 单元ai-trader-api管理(变更分支后用systemctl restart ai-trader-api重启)。如果你的环境同样用 systemd 托管,worker 进程可以用同样的方式做成常驻单元,并配合AI_TRADER_WORKER_LOCK_FILE/ Redis 锁避免重启竞态下出现双实例。
  • worker 收到SIGINT/SIGTERM时会取消所有任务、释放锁后干净退出(worker.py),重启流程不会遗留锁状态(文件锁随进程退出自动释放,Redis 锁在 finally 中主动 release)。

【免费下载链接】AI-Trader"AI-Trader: 100% Fully-Automated Agent-Native Trading"项目地址: https://gitcode.com/GitHub_Trending/aitrad/AI-Trader

创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考

需要专业的网站建设服务?

联系我们获取免费的网站建设咨询和方案报价,让我们帮助您实现业务目标

立即咨询