fix(reminder): 地点提醒常驻守护在进程被杀后无法恢复投递 - #414
Merged
znnnnnnn-wil merged 4 commits intoAug 29, 2026
Merged
Conversation
打上上游 expo/expo#47958 的修复(patch-package),并给 ReminderGuardCoordinator 加陈旧检测:不再拿注册 options 当"还在投递" 的证据,改用"本进程是否自己成功建过注册 + 最近是否收到过心跳"判断, 检测到继承自上一个(已死)进程的注册时主动重建。 详见 issue 1024XEngineer#413,未获完整真机验证,作为已知修复方向保留。 Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
expo-task-manager(及其依赖 unimodules-app-loader)默认从 Maven 拉官方 预编译二进制,不读 node_modules 本地源码——导致之前 patch-package 打的 expo/expo#47958 backport 从未被真正编译进任何 APK,之前几轮"打了 patch 还是不行"的观测因此都不算数。 在 package.json 加 expo.autolinking.buildFromSource,逼这两个模块走本地 源码编译,backport 才第一次真正生效。真机验证:强杀重开后出圈再回圈, [reminder] TRIGGERED 正常触发,原生响铃正常展示。 顺带把地点提醒触发半径从 400m 调到 200m。 Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Codecov Report✅ All modified and coverable lines are covered by tests.
Flags with carried forward coverage won't be shown. Click here to find out more.
🚀 New features to boost your workflow:
|
Contributor
There was a problem hiding this comment.
审阅了构建配置、TaskManager backport、守护注册协调器、headless 刷新路径及新增单测。当前实现能在冷启动时重建继承注册,但运行中的静默失活和清理失败路径仍可能让地点/时间提醒永久停摆,建议先修复以下两处。
Additional findings
frontend/src/features/reminder/application/ReminderGuardCoordinator.ts:?: [P1] Do not restart after failed task unregistration: 如果unregisterTaskAsync()抛错,这里仍继续执行startLocationUpdatesAsync()并把ownsRegistration设为true。但本次改动的根因和注释都说明持久化的 TaskManager 注册必须被真正移除;清理失败时继续复用同名注册可能再次命中同一个失活的原生记录,随后协调器又会把它当成健康注册而提前返回,导致恢复失败。请在注销失败时中止本次重建并保留可重试状态(或确认注销成功后再启动)。
- package.json:补 prettier 格式,修 CI 的 format:check 失败 - 注销失败(unregisterTaskAsync 抛错)时不再继续 startLocationUpdatesAsync(): 持久化记录没被真正删掉的话,重注册走的还是原生"已存在就 setOptions"分支, 等于又绑上同一条失活记录,下次 reconcile 会把它当健康注册直接早退,恢复 彻底失败且无声无息。现在中止本次重建,把重试留给下一次 reconcile。 - 新增独立于心跳事件的 watchdog 定时器:isRegistrationStale() 要判的恰恰是 "心跳已经不再来了",此前只在 start()/日程订阅/handleSample() 触发的 reconcile 里查——一旦心跳静默失活,这三个触发源全指望不上,会一直卡到 用户手动改日程或重启 App。定时器本身在 Node 测试环境下 unref(),不影响 真机运行也不会拖 Jest 进程退出。 Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Contributor
Author
|
两条 P1 都确认是真问题,已在 ff2d5bc 修复:
CI 那次 Frontend 失败是 |
半径改成 200 之后漏了这处 vitest 断言,CI 里 npm run test 分两段跑 (vitest + jest),本地只跑过 jest 没发现。改成引用常量,以后半径再变不会 再断。 Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
znnnnnnn-wil
approved these changes
Aug 29, 2026
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Summary
expo-task-manager(及其依赖unimodules-app-loader)默认从 Maven 拉官方预编译二进制,不读node_modules本地源码。这意味着此前打的所有补丁(下面这些)从未被真正编译进任何 APK,之前几轮"打了 patch 还是不行"的观测因此都不算数。在package.json加expo.autolinking.buildFromSource逼这两个模块走本地源码编译后,补丁才第一次真正生效。patches/expo-task-manager+57.0.9.patch,patch-package自动生效)ReminderGuardCoordinator新增陈旧检测:不再拿原生注册 options(foreground/degraded)当"还在投递"的证据,改用"本进程是否自己成功建过注册 + 最近是否收到过心跳"判断;检测到继承自上一个(已死)进程的注册时主动重建(含真正的TaskManager.unregisterTaskAsync())[guard] state=... stale=... wantInterval=.../[guard] registered interval=.../[guard] refreshed interval=... withService=...),后续复测和排查用背景
详见 #413。地点提醒依赖的常驻定位守护,在 App 进程被系统杀掉后,原生位置订阅仍在正常投递(
adb dumpsys location证实),但expo-task-manager的defineTask回调收不到,此前只有卸载重装能恢复。已通过真机端到端验证 ✅
补上
buildFromSource配置、确认 patch 真正编译进 APK 之后:强杀重开 App,走出围栏再走回来,日志出现:原生响铃/通知正常展示。多轮心跳(
[guard] dispatching sample to the live listener)持续稳定,未再出现"冷启动余波后彻底沉默"的旧现象。Test plan
npx jest(830+ 测试全过)npx tsc --noEmitnpx eslint(无新增问题)[reminder] TRIGGERED正常触发且原生弹窗/通知正常展示TimeflowDiag诊断字符串真的编进了安装的 APK(unzip+grepdex 直接验证),排除"改了但没编译进去"的可能🤖 Generated with Claude Code