背景
Issue #103 修了 upstream 不跟随 WiFi 切换的 bug,但 hot-swap 仍然依赖 60 秒一次的 polling。最坏情况:用户在第 0 秒切 WiFi,要等到第 60 秒 polling tick 才生效。这期间所有 DNS 查询要么走旧 upstream(可能 timeout / 拿到错的 IP),要么落在 8.8.8.8 / 1.1.1.1(如果 hickory rotate 命中公共 DNS)。
已完成:Polling 间隔降到 15s(option 1)
PR #104 第三个 commit 把 UPSTREAM_REFRESH_INTERVAL 从 Duration::from_secs(60) 改成 Duration::from_secs(15)。
最坏延时从 60s 降到 15s。每次 tick 调用 networksetup + ipconfig 共 4 个 shell 命令,加起来 < 10ms,对 CPU / 电量影响可忽略。
后续可选优化
Option 2: SCDynamicStore 事件驱动(< 1s 延时)
监听 macOS SystemConfiguration 的 State:/Network/Interface/.*/IPv4 和 State:/Network/Global/IPv4 变化,WiFi 一切换立刻回调。
实现要点:
- 新增 FFI 依赖:
objc2-system-configuration(更现代)或 core-foundation
- C 回调桥到 tokio:用
mpsc::Sender 投递到 refresh task
- 在
run_upstream_refresh_loop 的 tokio::select! 增加一个 notify_one 分支,收到事件立刻重新拉取 upstream 并 hot-swap
- macOS-only;Windows / Linux 走 15s polling 兜底
- 预计 +150 行,单测能覆盖大部分,集成测要 macOS 实机
参考 API:
SCDynamicStoreCreate(...)
SCDynamicStoreSetNotificationKeys(keys: ["State:/Network/Interface/.*/IPv4", "State:/Network/Global/IPv4"])
SCDynamicStoreSetCallback(...)
Option 3: Hybrid — SCDynamicStore + Notify wakeup + 60s polling 兜底
保留 15s polling 的安全网(兜底、防漏事件),加一个 SCDynamicStore listener 在事件触发时 refresh_shutdown.notify_one() 提前唤醒 refresh loop。比 Option 2 更稳(不会漏事件),复杂度略高。
推荐路径
短期:当前 15s polling 已经够用。
中长期:上 Option 3(最稳),或者如果觉得依赖太重直接 Option 2(最简)。
关联
验证步骤
启用 DNS 模式 → 切 WiFi → 看日志:
INFO mhost_dns::server: DNS upstream refresh tick: change detected <old> -> <new>
INFO mhost_dns::server: DNS server upstream hot-swapped: <old> -> <new> (network change applied)
两条 INFO 之间的间隔应 ≤ 15s(option 1)。
背景
Issue #103 修了 upstream 不跟随 WiFi 切换的 bug,但 hot-swap 仍然依赖 60 秒一次的 polling。最坏情况:用户在第 0 秒切 WiFi,要等到第 60 秒 polling tick 才生效。这期间所有 DNS 查询要么走旧 upstream(可能 timeout / 拿到错的 IP),要么落在
8.8.8.8/1.1.1.1(如果 hickory rotate 命中公共 DNS)。已完成:Polling 间隔降到 15s(option 1)
PR #104 第三个 commit 把
UPSTREAM_REFRESH_INTERVAL从Duration::from_secs(60)改成Duration::from_secs(15)。最坏延时从 60s 降到 15s。每次 tick 调用
networksetup+ipconfig共 4 个 shell 命令,加起来 < 10ms,对 CPU / 电量影响可忽略。后续可选优化
Option 2: SCDynamicStore 事件驱动(< 1s 延时)
监听 macOS
SystemConfiguration的State:/Network/Interface/.*/IPv4和State:/Network/Global/IPv4变化,WiFi 一切换立刻回调。实现要点:
objc2-system-configuration(更现代)或core-foundationmpsc::Sender投递到 refresh taskrun_upstream_refresh_loop的tokio::select!增加一个notify_one分支,收到事件立刻重新拉取 upstream 并 hot-swap参考 API:
Option 3: Hybrid — SCDynamicStore + Notify wakeup + 60s polling 兜底
保留 15s polling 的安全网(兜底、防漏事件),加一个 SCDynamicStore listener 在事件触发时
refresh_shutdown.notify_one()提前唤醒 refresh loop。比 Option 2 更稳(不会漏事件),复杂度略高。推荐路径
短期:当前 15s polling 已经够用。
中长期:上 Option 3(最稳),或者如果觉得依赖太重直接 Option 2(最简)。
关联
087111e+ 后续 polling 间隔 commit)验证步骤
启用 DNS 模式 → 切 WiFi → 看日志:
两条 INFO 之间的间隔应 ≤ 15s(option 1)。