背景
项目架构采用 Swoole\Http\Server + Yaf 实现,业务层 Yaf 若有未捕获异常配置如下:
application.dispatcher.throwException = 1
; 开启此项,如果有未捕获的异常,Yaf将会把它定向到Error controller, Error Action。
application.dispatcher.catchException = 1
业务层所有未捕获异常可在 ErrorController->ErrorAction 中处理。
解决方案是更改 Yaf 配置项 application.dispatcher.catchException = 0,worker 中对 Yaf 层做 try{...}catch(...) 处理。
深度解析
Yaf 源码文件 yaf_dispatcher.c 中的 yaf_dispatcher_exception_handler 方法对异常做了处理: YAF_G(in_exception) = 1;,在 PHP_RSHUTDOWN_FUNCTION 模块做的清除工作。导致 Swoole 的每个 worker 仅在进程首次可以由 ErrorController->ErrorAction 捕获异常,其他情况将导致 worker 进程异常退出。
源码解决方案:
-
yaf_dispatcher_exception_handler方法尾部追加YAF_G(in_exception) = 0; - 自定义清除函数,
ErrorController中处理异常后调用$this->clear();重置。
$ vim yaf_controller.c
PHP_METHOD(yaf_controller, clear) {
YAF_G(in_exception) = 0;
RETURN_TRUE;
}
/** {{{ yaf_controller_methods
*/
zend_function_entry yaf_controller_methods[] = {
PHP_ME(yaf_controller, render, yaf_controller_render_arginfo, ZEND_ACC_PROTECTED)
PHP_ME(yaf_controller, display, yaf_controller_display_arginfo, ZEND_ACC_PROTECTED)
PHP_ME(yaf_controller, getRequest, yaf_controller_void_arginfo, ZEND_ACC_PUBLIC)
PHP_ME(yaf_controller, getResponse, yaf_controller_void_arginfo, ZEND_ACC_PUBLIC)
PHP_ME(yaf_controller, getModuleName,yaf_controller_void_arginfo, ZEND_ACC_PUBLIC)
PHP_ME(yaf_controller, getView, yaf_controller_void_arginfo, ZEND_ACC_PUBLIC)
PHP_ME(yaf_controller, initView, yaf_controller_initview_arginfo,ZEND_ACC_PUBLIC)
PHP_ME(yaf_controller, setViewpath, yaf_controller_setvdir_arginfo, ZEND_ACC_PUBLIC)
PHP_ME(yaf_controller, getViewpath, yaf_controller_void_arginfo, ZEND_ACC_PUBLIC)
PHP_ME(yaf_controller, forward, yaf_controller_forward_arginfo, ZEND_ACC_PUBLIC)
PHP_ME(yaf_controller, redirect, yaf_controller_redirect_arginfo,ZEND_ACC_PUBLIC)
PHP_ME(yaf_controller, getInvokeArgs,yaf_controller_void_arginfo, ZEND_ACC_PUBLIC)
PHP_ME(yaf_controller, getInvokeArg, yaf_controller_getiarg_arginfo,ZEND_ACC_PUBLIC)
PHP_ME(yaf_controller, clear, NULL, ZEND_ACC_PUBLIC)
PHP_ME(yaf_controller, __construct, NULL, ZEND_ACC_PUBLIC|ZEND_ACC_CTOR|ZEND_ACC_FINAL)
PHP_ME(yaf_controller, __clone, NULL, ZEND_ACC_PRIVATE|ZEND_ACC_FINAL)
{NULL, NULL, NULL}
};
/* }}} */







网友评论