这是为 *DEV 的夏季漏洞清除活动:清理阵容** 由 Sentry 提供支持。*
项目概述
我维护着 StayPresent,这是一个开源的 Python 包,旨在帮助开发者在 Render、Railway、Koyeb 和 Heroku 等平台上保持机器人程序和后台服务的持续运行。
该库会在一个或多个机器人进程旁边启动一个轻量级的 Web 服务器,对这些进程进行监控,并在它们崩溃时自动重启。由于它专为长期运行的应用程序设计,因此可靠性远比添加新功能重要得多。
在开发 v1.5.10 版本期间,我发现了一个微妙的关闭竞态条件,这可能导致在应用程序本应退出后,仍有进程在运行。
代码仓库:
https://github.com/StayElite/StayPresent
漏洞修复或性能改进
该漏洞在被监控的机器人程序崩溃时出现。
StayPresent 在生成替换进程之前,会等待一段可配置的重新启动延迟时间。在该延迟期间,监控线程处于不可中断的 time.sleep() 睡眠状态。
如果用户在该重新启动窗口期间按下 Ctrl+C 或主机发送了 SIGTERM 信号,关闭流程将在监控线程仍处于睡眠状态时开始。
当睡眠结束时,监控线程可能会在关闭流程已经清理完所有已知进程之后,仍然创建一个全新的机器人进程。
由于监控线程被特意设置为非守护线程,这可能导致应用程序无限期地等待一个本不应启动的进程。
尽管该竞态条件仅在非常特定的时间窗口内发生,但它影响了优雅关闭——这是任何长期运行服务中最重要的部分之一。
解决方案包括两项更改:
- 将不可中断的重新启动延迟替换为可中断的等待。
- 将机器人进程的重启与关闭序列同步,确保一旦关闭开始,就无法创建新进程。
经过这些更改后,关闭操作会立即中断任何挂起的重启,并保证在应用程序终止期间不会创建孤立的机器人进程。
代码
GitHub 代码仓库
https://github.com/StayElite/StayPresent
发布版本
v1.5.10
提交 / 拉取请求
https://github.com/StayElite/StayPresent/commit/1210148731ed8e3146bb4ccd36a931b58c9705d8
我的改进
在修复此问题时,我希望在不引入不必要复杂性的情况下保留现有的重启行为。
挑战不在于重启崩溃的机器人程序,而在于确保重启逻辑和关闭逻辑永远不会相互干扰。
为了验证修复效果,我反复测试了以下场景:
- 机器人在关闭前立即崩溃。
- 在重启退避期间按下 Ctrl+C。
- 在多个被监控的机器人程序活跃时发送 SIGTERM 信号。
- 重复的崩溃/重启循环。
- 在进程健康状态下进行正常的优雅关闭。
最终实现确保了关闭操作始终优先于重启进程。
除了解决竞态条件本身外,这也提高了在生产环境中部署 StayPresent 时的信心,因为在这些环境中,干净的进程终止至关重要。
免责声明:本文内容来自互联网,该文观点不代表本站观点。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌抄袭侵权/违法违规的内容,请到页面底部单击反馈,一经查实,本站将立刻删除。