如何通过PHP异常触发Supervisor指定退出码?
解决方案:用自定义Exception实现Supervisord不重启PHP Worker
这个问题我之前维护PHP任务队列Worker时也碰到过,核心原因是默认情况下PHP抛出未捕获的Exception(比如RuntimeException)时,进程会以退出码1终止——这个码不在你配置的exitcodes=99,255列表里,所以supervisord还是会按规则重启进程。
要实现用Exception触发“阻止重启”的逻辑,我们可以通过自定义异常类+全局异常捕获的方式,既保持代码的面向对象特性,又能精准控制退出码。
步骤1:定义自定义异常类
首先创建一个专属的异常类,用来标记“需要让supervisord停止重启”的场景:
<?php class SupervisorStopException extends Exception { // 无需额外逻辑,保持极简即可,也可根据需求自定义构造方法 }
步骤2:在业务逻辑中抛出异常
当满足你设定的“需要终止进程且不重启”的条件时,抛出这个自定义异常:
// 示例:Worker的任务处理逻辑 public function processTask() { // 检查特定条件,比如任务队列关闭、资源耗尽、触发维护模式等 if ($this->shouldStopWorker()) { throw new SupervisorStopException('触发Worker主动终止,Supervisord无需重启'); } // 正常处理任务的逻辑 $this->handleTask(); }
步骤3:全局捕获异常并指定退出码
接下来在Worker的入口文件中,通过全局异常处理器或包裹主循环的try-catch,捕获自定义异常后以exit(99)终止进程:
方案A:全局异常处理器(推荐,覆盖所有未捕获异常)
<?php // 注册全局异常处理器 set_exception_handler(function (Throwable $e) { if ($e instanceof SupervisorStopException) { // 可选:将终止原因写入错误日志,方便后续排查 fwrite(STDERR, "[主动终止] {$e->getMessage()}" . PHP_EOL); exit(99); // 触发Supervisord的不重启规则 } // 其他异常:以退出码1终止,让Supervisord自动重启Worker fwrite(STDERR, "[异常重启] {$e->getMessage()}" . PHP_EOL); exit(1); }); // 启动Worker主循环 $worker = new TaskQueueWorker(); $worker->run();
方案B:包裹主循环的try-catch
如果你的Worker有明确的主循环,也可以直接用try-catch包裹:
<?php $worker = new TaskQueueWorker(); try { while (true) { $worker->processTask(); // 任务间隔休息时间 sleep(1); } } catch (SupervisorStopException $e) { fwrite(STDERR, "[主动终止] {$e->getMessage()}" . PHP_EOL); exit(99); } catch (Exception $e) { fwrite(STDERR, "[异常重启] {$e->getMessage()}" . PHP_EOL); exit(1); }
关键注意事项
- 保持Supervisord配置不变:确保你的
supervisord.conf中依然保留exitcodes=99,255,这样当进程以99退出时,Supervisord会识别为“正常终止,无需重启”。 - 区分异常场景:自定义异常只用于“主动要求终止且不重启”的情况,其他业务异常仍以退出码1终止,保证Worker遇到普通错误时能自动重启。
内容的提问来源于stack exchange,提问作者mils
相关产品推荐
相关产品推荐

