技术栈:Python · FastAPI · Redis · asyncio · 原生 HTML / Tailwind / ECharts
事情的起因很简单:我想在本地从 0 搭一套【轻量级分布式异步任务调度与实时监控看板】------后端能可靠地分发任务、支持多个 Worker 并发消费,前端能实时看到队列积压、处理速率和完成日志。一个人,我用 Seed-2.1-pro-0915(豆包工作模式可以选择)当成了全程的工程搭档。从一句需求开始,到最后一键压测看到图表上的波峰,整个系统被真正跑通了。
一、输入:我要的不是 Demo,而是"能落地"
我给模型的第一条指令只做两件事:给出模块化的项目结构和最简依赖。但我在要求里写得很明确------不要玩具代码。我心里"落地"的标准是:
-
队列必须可靠:Worker 宕机或僵死时,任务不能凭空消失;
-
多个 Worker 同时消费时,不能重复领取同一个任务;
-
失败要能自动重试,超过上限要进死信队列;
-
服务关闭时要优雅停机,而不是一刀杀掉正在执行的任务;
-
看板上的每一个数字,都来自后端真实数据。
Seed-2.1-pro-0915 没有急着写代码,而是先交付了分层架构:core/ 放不依赖 Web 框架的核心逻辑,worker/ 是消费节点,api/ 是薄路由层,static/ 放零构建的前端,再用一个 run.py 统一启动。这个分层后来贯穿了全部开发------每一轮新代码都知道自己该待在哪一层。
二、核心:一条"不丢任务"的可靠队列
系统的心脏是 core/queue.py。它采用经典的 At-Least-Once(至少一次)语义,用三个队列加一把锁实现:
-
pending:等待消费;processing:已被领取、正在执行;dead:死信; -
每个任务被领取时,会设置一把带 TTL 的占锁,锁过期仍未确认,就认为 Worker 失联;
-
所有涉及多个 key 的操作,全部用 Lua 脚本在 Redis 单线程内原子执行。
抢占任务的核心只有一行 Lua,却同时完成了「移动任务 + 加锁 + 状态翻转 + 尝试次数 +1」:
local item = redis.call('RPOPLPUSH', KEYS[1], KEYS[2]) -- pending -> processing,原子
redis.call('SET', lock_key, worker_id, 'PX', ttl_ms) -- 带过期的占锁
rec.status = 'running'; rec.attempts = rec.attempts + 1
成功后调用 ack 确认并写入「最近完成」列表;执行失败调用 fail,未超限时自动重投,超限则进入死信。另有一个回收器,周期性把锁已过期的任务捞回来------集群里通过一把分布式互斥锁,保证同一时刻只有一个回收者在跑。
在这之上,worker/pool.py 用 asyncio 实现了固定大小的消费池:消费者数量就是并发上限;每个任务有执行超时保护;心跳协程持续上报在线状态;收到停机信号后不再领新任务,等待在途任务完成,超过宽限期才强制取消------被取消的任务不确认,等锁过期后自动重投。
图 1 · GET /api/metrics 返回的原始 JSON:队列长度、在线 Worker、累计计数、最近完成任务,看板上的每个数字都从这里来
三、接口与入口:一条命令启动全套服务
对外只有两个接口:POST /api/tasks 提交任务(支持批量),GET /api/metrics 聚合监控数据。run.py 在应用生命周期里自动连接 Redis、启动 Worker、挂载静态页面。启动后,Swagger 文档是自动生成的:
图 2 · FastAPI 自动生成的 Swagger UI,两个接口与全部数据模型一目了然
前端则是单文件 index.html,Tailwind 和 ECharts 全部走 CDN,不需要 Node.js、不需要打包:暗色科技风、4 张指标卡、每秒轮询一次的实时折线图、压测按钮和滚动日志。
四、真正的考验:两个真实的 Bug
如果说前面是"写得顺",那安装启动阶段才是真正考验模型工程能力的地方------我连续撞上了两个非常"本地化"的问题。
第一个坑:pip 安装直接报 UnicodeDecodeError。 最初的 requirements.txt 里有中文注释,文件是 UTF-8 编码;而我系统的区域编码是 GBK(cp936),pip 解码失败,整个安装中断,导致 redis 等包都没装上。模型读完报错后,直接把依赖文件改成纯 ASCII 英文注释,并在我的虚拟环境里重新执行安装验证------从根上消除了编码问题,而不是让我去改系统编码。
第二个坑:我本地的 Redis 是 5.0.14.1 的 Windows 移植版。 redis-py 8 默认走 RESP3 协议,会发送旧版 Redis 不认识的 HELLO 3;代码里用的 LMOVE 也要 Redis 6.2 才有。模型没有简单地甩给我一句「装个 Docker 跑 Redis 7」(我并没有 Docker),而是让代码向下兼容:客户端固定 protocol=2,Lua 中用老牌的 RPOPLPUSH 替代 LMOVE,并调整入队方向保持 FIFO。中间还顺手修了 redis-py 8 中 Script 类导入路径变化的问题。
client = redis.asyncio.from_url(url, decode_responses=True, protocol=2)
# RESP2 不发 HELLO;RPOPLPUSH 在 Redis 2.6+ 即可用
让我印象最深的是:它不是把代码丢给我让我自己跑,而是自己启动服务、自己派发任务、自己调接口验证结果,确认 10 个任务全部完成、失败任务正确进入死信之后,才宣布交付。这正是一次"对结果负责"的 Agent 式工作流。
五、压测时刻:看着波峰在图表上长出来
系统跑通后,我在操作面板上点了「一键批量派发」。为了拿到更直观的画面,我还让模型用 CDP(Chrome DevTools Press)写了个自动化脚本:先让看板加载并积累基线,中途派发 30 个 0.8--2.2 秒的随机任务,在波峰形成的瞬间截图,最后等任务全部排空。
图 3 · 压测中途抓拍:等待数(黄色虚线)瞬间冲顶后逐步回落,处理速率(青色实线)随并发消费上下波动

图 4 · 压测操作面板:批量派发按钮、耗时滑块、失败模拟开关与队列迷你状态(抓拍时 4 个任务正在执行)
图 5 · 任务完成日志滚动列表:时间、任务名、任务 ID、实际耗时与来源 Worker 一应俱全
最终的整页看板长这样------指标卡、实时图表、操作面板、完成日志同屏,所有数字都是真实压测的结果:
图 6 · 最终交付的看板整页:一条 python run.py 启动,30 任务压测后的完整状态
六、复盘:升级后的能力,到底在哪些瞬间帮我落地
回到这次 Seed-2.1-pro-0915 升级本身。对我而言,真正有体感的不是任何一个跑分数字,而是这样几个瞬间:
-
长程一致性:横跨十几轮对话、十余个文件,架构分层始终没有走样,每个新模块都准确落位;
-
工程严谨度:主动给文件加类型注解、发现自己脚本里的笔误立刻修正、坚持"先验证再交付";
-
真实环境适配:面对我机器上冷门的 Redis 5.0 Windows 版和 GBK 编码,能基于真实版本做向下兼容,而不是背标准答案;
-
端到端负责:从架构、编码、排错、压测到截图,一路推进到我能直接用,而不是写完片段就结束。
过去用 AI 做工程,我常常要扮演"集成商"------把它生成的碎片拼起来、自己跑、自己擦屁股。而这一次,我更像一个提需求、做决策的人,把执行整条链路交给了它。
一行需求起,一条命令终。当图表上的波峰真实地长出来,我知道:这套系统落地了,这次升级也落地了。
项目地址:https://github.com/jinmo666/kanban-system
附提示词:
1."你好,我现在要在本地从 0 搭建一个轻量级、工程级的『分布式异步任务调度与实时监控看板系统』。后端使用 Python + FastAPI + Redis,前端使用单页原生 HTML + Tailwind CSS + ECharts。 请先帮我完成两件事: 列出规范、模块化的项目文件夹结构(包含 core/、worker/、api/、static/、run.py 等)。 给出 requirements.txt 文件,包含运行所必需的最简核心依赖(如 fastapi, uvicorn, redis, pydantic 等)。"
2."现在开始编写核心后端代码。请严格遵循模块化原则,不要写玩具代码,给出带有类型注解(Type Hints)的完整文件内容: core/config.py:定义基础配置(Redis 连接地址、队列名称等)。 core/queue.py:基于 Redis 实现安全任务队列。必须包含原子性任务推入(Push)、带过期保护的任务抢占(Pop/Lock 防止多 Worker 重复消费)、任务完成确认(ACK)以及失败记录逻辑。 worker/pool.py:实现基于 asyncio 的 Worker 消费池。限制最大并发数,模拟真实耗时任务执行,能够统计已完成、进行中和失败的任务数,并支持优雅停机(Graceful Shutdown)。"
3."接下来编写对外接口与统一入口: api/routes.py:使用 FastAPI 编写接口: POST /api/tasks:提交新任务(接收任务名称、执行耗时参数,推入队列)。 GET /api/metrics:获取集群实时监控指标(队列中等待数、当前活跃 Worker 数量、已完成总数、最近完成的任务列表)。 run.py:主启动脚本。同时启动 Worker 异步消费后台任务和 FastAPI Web 服务(挂载 static 静态资源目录),直接运行 python run.py 即可启动全套服务。"
- "最后开发前端运维监控页面 static/index.html。不要复杂的打包工具,直接通过 CDN 引入 Tailwind CSS 和 Apache ECharts: 仪表盘:暗色科技风格。顶部展示 4 个指标卡片(等待中任务、活跃工作线程、已完成任务数、系统状态)。 动态图表:中间使用 ECharts 绘制实时动态折线图,每 1 秒轮询一次 /api/metrics,展示系统处理速率波动。 操作面板: 提供一个『批量派发任务』按钮(例如一键派发 20 个随机时长的任务),方便我实时压测观察图表变化。 底部展示最新的任务完成日志滚动列表。"