arq worker独立部署知识总结;任务队列架构初步认识;API进程和Worker进程在同一个项目下的启动方式;
arq worker独立部署知识总结
1. worker 进程需要完整的业务代码和依赖
worker 进程启动时会真正执行 import 链,一路带出更深层的依赖,也就是实现任务流程的整条工作流。
worker 环境需要的东西
- 项目自己的完整代码,因为 worker 是在进程内直接调用这些函数,不是通过网络转发;
- 这些代码依赖的第三方库。
worker 环境不需要的东西
fastapi、uvicorn 这类只有 API 进程用得到的库,worker.py 完全没 import到它们。
最省心的做法
不用手动分辨"这个包 worker 需不需要",直接把 API 环境的完整依赖列表
(requirements.txt)原样装一份到 worker 环境:多装几个用不上的包(比如 fastapi)没有副作用,比精简依赖列表更不容易漏装。
2. 生产者 / 消费者架构分工
用成熟任务队列之后,自然形成标准的生产者(API)/ 消费者(worker)分工。
生产者端:FastAPI 服务(API 层)
职责很薄,只做三件事:
- 接收 HTTP 请求,做参数校验
- 把任务丢进 Redis 队列(
redis.enqueue_job(...)),不等任务真正执行完 - 查询状态/结果(查 arq job 状态,或查业务结果的权威来源,比如LangGraph checkpointer)
这一层不需要真正跑 LangGraph 的图、不需要跑模型推理,只是"收件员"。
消费者端:arq worker 进程(执行层)
职责是"真正干活":
- 拉取队列里的任务,执行 handler 函数本身
- 需要项目里几乎全部业务代码,因为是在进程内直接调用
- 需要能访问所有业务依赖的资源:数据库、Redis(存 checkpoint)、GPU(跑模型推理)、外部 API(比如天地图瓦片下载)
两者通过 Redis 里的 job 沟通,互不知道对方内部细节。
生产者 / 消费者为什么值得
- 独立扩容:GPU 推理任务成为瓶颈时,只加 worker 数量/换更强机器,不用动 API 那台;反之 API 请求量暴涨也只需要扩 API 进程
- 容错隔离:worker 因某个 handler 的 bug 崩溃重启,不影响 API,继续正常收请求
- 职责清晰:消费者端需要完整运行环境的部分;纯 API 层代码;
可以不拆成两个代码仓库
运行时的两个进程,是两个不同的入口,不是代码物理上分成两个工程。"逻辑上拆开、代码上仍是一体",不需要进一步的物理拆分。
任务队列架构初步认识
任务队列架构的标准形态,再加上 Redis 本身(存队列消息、任务状态),完整跑起来通常是三个东西在同时运行:
┌─────────────┐ ┌─────────────┐ ┌─────────────┐
│ API 进程 │ 写任务 │ │ 取任务 │ Worker 进程 │
│ (uvicorn) │ ──────> │ Redis │ <────── │ (arq) │
│ │ 查状态 │ │ 写状态 │ │
└─────────────┘ <────── └─────────────┘ ──────> └─────────────┘
API 进程:一般只需要一个;很轻量,因为它们不干真正的活;
worker 进程:可以开多个,甚至分布在不同机器上,任务的资源需求差异很大,分别在不同机器上跑各自的 worker 进程,通过同一个 Redis 分发任务。
API进程和Worker进程在同一个项目下的启动方式;
由于各自有独立的Python解释器,也就不是一个入口启动整个项目了,所以启动方式有所改变
1.项目目录结构
目录结构保持不变,api入口与worker入口保持同级就行。
ai-workflow/ ← 项目根目录,两个环境都从这里启动
├── app/
│ ├── api.py ← API 入口
│ ├── worker.py ← worker 入口
2. (测试阶段F5)配置文件:.vscode/launch.json
顶部下拉框选择 "Launch API + Worker";按 F5 可以两个进程同时启动,各自独立调试终端;
"compounds": [
{
"name": "Launch API + Worker",
"configurations": [
"Python Debugger: FastAPI",
"Python Debugger: arq worker"
],
"stopAll": true
}
]
关键点
- 两个普通
configurations各自独立,只有加了compounds才能一键联动启动 compounds.configurations里引用的是上面 configuration 的name字符串stopAll: true→ 点停止时两个进程一起终止uvicorn --reload会 fork 子进程,调用堆栈里出现的 "Subprocess" 是这个,不是 worker
前提:两个进程用同一个 Python 解释器/环境,否则 compound 不适用,需分开调试
3.(生产环境)交给 Supervisor 管理
配置直接指向conda环境里的可执行文件绝对路径,配置文件处:
[program:ai-workflow-api]
command=/home/user/miniconda3/envs/sam3/bin/uvicorn app.main:app --host 0.0.0.0 --port 8000
...
[program:ai-workflow-worker]
command=/home/user/miniconda3/envs/arq-worker/bin/arq app.worker.WorkerSettings
...
这个方式两个进程可用不同python解释器,也就是独立环境。
浙公网安备 33010602011771号