用途:periodic-worker-dedup 描述一种 Android 周期性通知器(periodic worker)的实现策略,解决后台任务被延迟、跳过或中途终止时如何不漏条、如何避免重复推送的问题。资料将其定位为一种模式/示例,而非可直接安装的库;原文包含 Kotlin 代码片段,但未提供安装命令或依赖坐标。
主要能力与机制:
- 双重条件门控:每个条目需同时满足“发布时间在窗口内”和“数据库中不存在该通知记录”才会推送。窗口限定回溯范围;数据库检查是唯一防止某次运行重复通知的机制,因此实现的是至少一次投递并带一个很窄的重复窗口,并非精确一次。
- 旧到新排序:按 publishedAt 升序处理,使通知按发布时间到达;若运行中途被杀死,已处理的是最旧条目,剩余最新条目下次仍在窗口内,可被补发。
- 窗口宽于间隔:示例调度为 24 小时、窗口为 48 小时,为至少一次完全错过的运行留出余量,因为窗口加宽不增加重复推送成本(由数据库检查兜底)。
主要陷阱(资料明确列出):
- worker 每次运行新建对象、进程可能被杀,内存里的“上次已见 id”不可靠;需持久化的内容应放数据库。
- 去重键应使用稳定标识(示例用链接),解析出空链接的条目在解析阶段丢弃;标题可能被上游修改,不宜作键。
- 日期解析失败返回 0L,窗口判断以 publishedAt > 0L 开头,从而跳过坏日期条目;不能把坏时间戳默认为当前时间,否则畸形条目会在每次运行反复通知。
- 先通知后记录会留下很窄的重复窗口(两次操作之间被杀会重复一条);先记录后通知则可能静默丢一条,需明确取舍,不能假定继承代码是精确一次。
- 异常时重试整个抓取而非单条,因数据库检查使重复处理整份 feed 安全;通知渠道在循环内、推送前创建,渠道创建幂等,且让从 worker 内启动的新进程也有渠道可发。
验证方式(资料给出):
- 无 feed 变化时连续运行 worker 两次,第二次不得推送。
- 删除已记录行后重跑,窗口内条目应全部重新推送,证明数据库是真实来源。
- 将设备时钟拨快一个间隔或跳过一轮,确认间隔期发布的条目仍能到达。
- 确认窗口确实宽于间隔:调度写在入队处而非常量旁,可用 grep -rn "PeriodicWorkRequestBuilder" --include='*.kt' <src> 查找并对比周期与窗口常量。
- 向解析器喂入日期畸形条目和无链接条目,确认两者都不通知。
适用场景:Android 上需要按固定周期拉取 feed 并发通知、且能容忍至少一次语义的后台任务。
限制:资料标注为 Android only;未提供完整项目结构、安装方式、许可证、收费或性能数据,这些暂未提供。