Mac VPN 在你点击断开后立刻自行重连
把每个断开状态都当成故障的监控程序,会和“断开”按钮对着干。把用户意图和观测状态分开记录,再给重试设上限。
按下“断开”确实有效,十秒后隧道却又回来了。这个循环很少是 VPN 客户端本身出了问题;它是一个恢复脚本,永远只问一个问题——“是不是断了?”,然后用连接来回答。一旦你把用户回答的问题与系统报告的问题分开,修复就变成一小份状态,而不是更久的等待。
两个问题,不是一个
这个配置现在应该保持连接吗,系统此刻又在报告什么?这是两个归属不同的问题,恢复策略在行动之前两者都需要。意图是你的工具决定并记住的东西。观测状态是平台告诉你的东西。
| Intent | What you observe | What to do |
|---|---|---|
| Wanted | Dropped unexpectedly | Allow one supported recovery attempt |
| Paused by the user | Disconnected | Do nothing until intent changes |
| Wanted | Already connecting | Wait instead of starting a rival attempt |
| Wanted | Authentication needs a person | Prompt, then stop replaying credentials |
把这些行读成一条策略,而不是一串案例。第二行是大多数脚本会漏掉的那一行,也是唯一能把监控程序和“非要对到底”的机器区分开的一行。
观测状态不是偏好
Apple 的 Network Extension 状态模型会报告 connecting、connected、disconnecting、disconnected 和 recovery 五种状态。这五种描述的都是连接。它们都没有说“用户要求这个配置保持暂停”,因为那根本不是一种连接状态。不基于该框架构建的客户端会公开自己支持的控制项和状态调用,它们用自己的词汇划出同一条界线。
结果就是,断开状态永远不能被单独解读。它至少意味着三种情况之一:隧道掉线、用户主动停止,或者系统正处于两次尝试之间。只有你自己的意图记录才能区分它们。把这份记录写下来,如果它必须扛过重启就持久保存,并在用户操作的那一刻更新,而不是事后从日志行里推断。
scutil --nc list
scutil --nc status "Office VPN"
还有谁被允许启动这个配置
你的助手承诺的暂停,强度只等于同一配置的其他所有者。On Demand 规则、受管理的配置或第二个客户端都可能请求连接,而你的助手会一边严格照章行事,一边看起来像坏了。
找出所有能启动该配置的机制 在你承诺尊重暂停之前,写下哪一个会胜出。当受管理的服务刻意不提供个人暂停选项时,那是管理员对策略的决定,而不是脚本该靠与管理层对抗去填补的空缺。
让重试变得无聊
限制尝试次数,并让每一次都针对某个发生了变化的东西:网络恢复了、网关响应了、凭据提示完成了。网关不可用、身份过期、第二因素被拒绝,需要三种不同的反应,而紧密循环给三者同一个反应。
看看快速重试在屏幕上实际产生了什么。用户反复关掉的对话框比一条清晰的失败提示更糟,它们训练人们不读提示就点掉。
暂停和流量策略是两个不同的承诺
用户暂停的隧道往往会故意让流量保持阻断,这正是 kill switch 式策略的全部意义。这意味着“暂停”只应承诺一件事:恢复停止。它不应悄悄改变网络允许的内容。
单独决定流量行为,把它记录在“暂停”控件旁边,并且无论隧道是暂停、失败还是不存在都保持一致。否则用户会学到:按“断开”会发生不可预测的事,而下一张支持工单就是关于一个“有时会毫无征兆地停止工作”的网络。