Hyperf 启动后请求 500 且日志无报错,主因是 di.php 中协程上下文未就绪时调用 Di::get() 导致 null 调用崩溃;应改用 #[Inject] 注解或运行时容器获取,禁用构造函数内容器调用。

Hyperf 启动后请求 500 且日志没报错?检查 di.php 里的协程上下文注入
Hyperf 默认用 Swoole 协程运行,但很多老项目习惯在构造函数或 __construct 里直接调用 Di::get() 或依赖容器实例——这在协程环境下会因容器未就绪而静默失败,最终返回空响应或 500。真实原因是 Di 实例在协程启动前尚未完成初始化,make() 调用返回 null,后续方法调用直接抛 Fatal error: Call to a member function xxx() on null,但 Swoole 默认不把这类致命错误写进 Hyperf 日志。
实操建议:
立即学习“PHP免费学习笔记(深入)”;
- 所有依赖注入必须走
#[Inject]属性注解,或在__invoke()/handle()等运行时方法中调用$this->container->get() - 避免在
config/autoload/di.php中使用闭包返回对象实例(如return new Redis();),应改用工厂函数并显式声明协程安全:return fn () => make(Redis::class); - 调试时临时加一句
var_dump(\Hyperf\Contract\ContainerInterface::class, $container instanceof \Hyperf\Contract\ContainerInterface);到bootstrap.php开头,确认容器已加载
Swoole 4.8+ 下 Coroutine::sleep() 不生效?别混用 sleep() 和协程版
Hyperf 基于 Swoole 协程,但 PHP 原生 sleep() 是同步阻塞的,一用就卡死整个协程调度器,表现是接口超时、CPU 占满、Coroutine::stats() 显示大量 coroutine_num 却无实际并发。很多人搜“Hyperf sleep 不生效”,其实是误用了原生函数。
实操建议:
立即学习“PHP免费学习笔记(深入)”;
- 一律用
Coroutine::sleep(),不是sleep();注意它接受秒为单位的浮点数,比如Coroutine::sleep(0.1) - 在
Command类或非 HTTP 场景下,若需模拟延迟,仍要先判断是否在协程环境:if (Coroutine::inCoroutine()) { Coroutine::sleep(1); } else { usleep(1e6); } - 第三方库(如某些 SDK)内部硬编码了
sleep(),必须通过Co::set(['hook_flags' => SWOOLE_HOOK_ALL])开启全钩子——但要注意,开启后部分扩展(如 xdebug、pcov)会异常,上线前务必关闭
Hyperf 微服务间调用超时总卡在 30s?重点看 guzzle 的 timeout 和 connect_timeout 区别
用 GuzzleHttp\Client 调其他 Hyperf 服务时,经常发现请求等满 30 秒才报 cURL error 28: Operation timed out。这不是 Guzzle 默认值,而是 Swoole 的 http_client 底层默认连接超时 + 读取超时各 30 秒,且 Guzzle 的 timeout 参数只控制读取阶段,不包含建连。
实操建议:
立即学习“PHP免费学习笔记(深入)”;
- 显式设置两个超时:
new Client(['timeout' => 5.0, 'connect_timeout' => 3.0]),否则timeout单独设成 5 仍可能卡满 30s(建连失败时) - Hyperf 自带的
HttpClient更省心:$client->get('http://svc/users', ['timeout' => 5.0]),它底层自动合并处理 connect + read 超时 - 跨机房调用务必加
retry:Swoole 的 DNS 解析在协程下有时会阻塞,['retry' => 2, 'retry_delay' => 100]比单纯调高 timeout 更有效
部署到 Docker 后 php bin/hyperf.php start 报 Address already in use?Swoole 端口复用没开
Docker 容器重启频繁,Swoole 主进程退出后子进程可能残留,导致新实例启动时报 Address already in use。这不是端口被占,而是 Swoole 默认没启用 SO_REUSEPORT,旧连接 TIME_WAIT 状态无法快速回收。
实操建议:
立即学习“PHP免费学习笔记(深入)”;
- 在
config/autoload/server.php的servers配置里加:'open_tcp_nodelay' => true, 'so_reuse_port' => true - 不要用
kill -9杀主进程,改用php bin/hyperf.php stop,它会发 SIGTERM 并等待子进程优雅退出 - Dockerfile 中确保
WORKDIR /app且bin/hyperf.php有执行权限:RUN chmod +x bin/hyperf.php,否则启动脚本静默失败,看起来像端口问题
协程不是银弹,Hyperf 的性能优势高度依赖配置细节——比如 so_reuse_port 关了,单机扛不住 1k 连接;hook_flags 开错了,JSON 解析都可能变慢。这些地方不报错,但一压测就露馅。



















