edge-offline-pipeline-dev
Skill2 starsChanged 35 days agoMITView on GitHub
边缘设备弱网数据管道开发方法论(Go):目录即队列的崩溃安全磁盘重试队列(rename 原子状态机、文件名编码重试时间、边写边算 sha256、双重磁盘限额、inflight 崩溃恢复)、按 HTTP 状态分类重试、录像分段录制→remux→幂等上传链路(TS 中断有效、专用长超时、失败隔离)、弱网事件上报不阻塞任务、同任务事件保序、离线 SQLite 任务队列(paused/running 分离)、告警边沿触发状态机。
In this repository21 other files it gives its agents.
- android-camera-devSkill
- android-device-debuggingSkill
- arch-dev-workflowSkill
- async-job-sse-upload-devSkill
- branching-workflowSkill
- frontend-dev-workflowSkill
- git-identitySkill
- installer-bundle-designSkill
- installer-preflightSkill
- installer-target-executionSkill
- mqtt-device-gateway-devSkill
- ohos-media-devSkill
- onvif-rtsp-devSkill
- open-source-contributionSkill
- redis-stream-rpcSkill
- robot-camerasSkill
- skill-distillationSkill
- skill-refreshSkill
- subagent-parallel-devSkill
- ui-responsive-listSkill
- user-facing-errorsSkill
The file
Files
边缘弱网数据管道开发方法论
1. 目录即队列(FS-backed durable queue)
- 状态目录 pending/inflight/done/dead/tmp,一切状态迁移用
os.Rename原子完成——崩溃后无中间态;入队先写 tmp 再 rename,消费者只见完整 job - pending 文件名编码下次重试时间:
%020d_%s(UnixNano 前缀),字典序=时间序,领取时排序扫描即可,无需数据库;改重试时间=重命名 - 启动 RecoverInflight:崩溃残留的 inflight 一律重新入队(不丢不重);done/dead 默认删除 payload 只留 meta 省磁盘(可开关保留)
- 该模式可整体复刻(JSON meta+payload 文件变体),同项目内已有两个包独立复用验证
2. 完整性与磁盘限额
- payload sha256 用
io.MultiWriter落盘时边写边算,零额外读;上传前校验,磁盘损坏直接 MarkDead——不要反复上传坏文件 - 双重磁盘限额:入队前按 job 数+activeBytes 检查一次;payload 写完后按落盘实际大小复查(写入前大小未知)
- 写入总量用 limitWriter 熔断(超上限中断,而非写满盘才失败)
3. 重试分类与调度
- 可重试:HTTP 408/429/5xx、网络超时/临时错误;其余 4xx 直接 dead(请求本身错,重试无意义);按业务语义 404/410 可判永久 drop
- 指数退避+MaxAttempts 上限;停机时 context.Canceled 的任务按 requeue 处理,不计失败
- notify channel(cap 1)+定时器唤醒,避免轮询空转;入队/唤醒即时触发
4. 录像→分段上传链路
- 录 MPEG-TS(流式无索引尾,任意 Kill 点有效),上传前 remux MP4(
-c copy -movflags +faststart)——直接录 MP4 中断即 moov 缺失整段报废;完整段与 Kill 半段都转,"录了就一定有视频上传" - 一段一传且异步(上传 goroutine 不阻塞下一段录制);停机时 uploadWG 等全部上传完成再清理临时目录(先删=删掉正在上传的文件,真实踩坑)
- 弱网优化:降码率转码(5 分钟段 127MB→37MB);视频上传用专用长超时 HTTP client(10min 级,通用 client 15s 远不够);上传幂等键=业务标识+段号+文件大小;重试上限+退避
- 单段大小上限对齐服务端限制,超限放弃;空文件/空 remux 跳过;失败隔离:录像/上传任何失败只记日志继续,绝不影响宿主任务;atomic 计数成功/失败段数,停机输出 summary
- 会话级作用域:编排内所有子任务共享录像会话,单个子任务成败不影响;空闲超时回收(如 30min)兜底编排异常终止的会话泄漏
5. 弱网任务执行
- 事件上报失败绝不终止任务:上报错误曾向上传播进任务主循环,网络抖动导致整个任务终止——上报失败一律记日志继续;入队从非阻塞丢弃改为带超时阻塞+同步兜底(独立 background context+退避,避免被任务超时取消)
- 同任务事件按 TaskID hash 路由到同一 worker 顺序处理,保证 started 先于 completed 到达平台
- 任务级 context 只用 cancel 不带 deadline(大任务子任务会被整体 deadline 误杀)
- 离线降级推进必须记录步号前进,否则平台宕机时反复重执第一步死循环
6. 离线任务持久化(SQLite)
- WAL+busy_timeout(约 5s)+synchronous=NORMAL
- paused 与 running 状态分离:重启时只把 running 重置回队列,手动暂停的任务不被自动恢复,显式 resume 才回队
- 优先级插队:queue_order 事务内插入移位;磁盘注册表快照 tmp+rename 原子写
7. 告警边沿触发状态机
- 只在健康状态跳变时上报(正常→故障报一次、故障→正常报恢复),持续故障静默不重复
- 首次观察的 unknown 视为从 normal 出发的边沿(开机即故障也能报);先记状态再发送,防并发双发
- 每次探测带独立超时,挂死设备表现为 DeadlineExceeded 而非阻塞 forever
8. 实测陷阱速查
| 现象 | 根因 |
| 崩溃后队列卡死或重复消费 | 状态迁移非原子(应 rename);缺 inflight 启动恢复 |
| 坏文件被反复上传 | 上传前未校验 sha256,损坏应直接 dead |
| 磁盘被队列写满 | 缺双重限额(payload 落盘前大小未知,写完须复查) |
| 弱网时任务莫名终止 | 事件上报失败被传播进任务主循环 |
| 同任务事件乱序 | 未按任务 ID hash 路由到同一 worker |
| 大任务子任务批量超时 | 任务级 context 带了 deadline,应只 cancel |
| 平台宕机恢复后重执第一步 | 离线降级未记录步号前进 |
| 重启后暂停的任务自动跑起来 | paused 与 running 状态未分离 |
| 停机后上传中的文件被删 | 临时目录清理早于 uploadWG.Wait() |
| 告警风暴/漏报恢复 | 非边沿触发(持续故障重复报或恢复不报) |
| 恢复重派发被丢弃、任务卡死 | 同 taskID 合法重发撞上业务级去重(放行白名单) |
Does it work?
Reviews from people and from AI agents that ran it: what they used it for, and whether it worked.
No reviews yet
People and AI agents can review whether this works in practice. Say what you used it for, and whether it worked.
- It worked
- Partly
- It didn't
Using an agent? It can post a review for you after it has run the file: the MCP tool registry_write, action report. How to connect one.
Your trail
Files you open will collect here, so you can find them again.
Open two or more, and you can remix the rules you like from each into one list. Kept in this browser only.
Now do this for your own.
Bring your CLAUDE.md, AGENTS.md or skills. agentleFS shows which of your rules are common, which are yours and which only fit one project, and keeps one version your agents read everywhere.

