协程崩溃主因是断线后异常未捕获、资源未释放或重连阻塞,swoole 4 的co\redis不支持自动重连,需业务层兜底;断线表现为首次命令抛redisexception,重连须重建实例、设超时、清状态、丢弃坏连接,并严格try/catch+finally防护。

协程崩溃通常不是 Redis 断线本身导致的,而是断线后未捕获异常、连接池资源未释放、或重连逻辑卡在阻塞调用中引发的连锁反应。Swoole 4 的协程 Redis 客户端(如 Co\Redis)不自带自动重连,必须由业务层兜底处理。
明确断线的典型表现和触发点
Co\Redis 在连接已断但未检测时,首次执行命令(如 get、set)会立即抛出 RedisException,错误信息含 Connection refused、Connection reset by peer 或 Resource temporarily unavailable。注意:
– 不是所有“超时”都等于断线,也可能是服务端繁忙或 brPop 等阻塞命令的 timeout 设置不当;
– 若使用了连接池(如 Hyperf Redis),还要区分是单连接断开,还是连接池整体耗尽(WaitTimeoutException)。
重连失败的常见原因与修复动作
手动重连失败,往往因为以下几点没做干净:
Redis 缓存和数据结构管理技能。通过自然语言操作 Redis,支持 String、Hash、List、Set、ZSet、Stream 等数据结构操作。当用户提到 Redis、缓存、消息队列、会话存储时使用此技能。
- 未在
catch中显式关闭旧连接:直接对已断开的$redis实例调connect()会失败,应unset($redis)或新建实例 - 重连未设超时控制:
connect()默认无超时,协程可能卡死;需配合Co::sleep(0.1)或用Co::socket+select做连接探测 - 重连后未刷新上下文:若在 pipeline/multi 中断线,残留的事务状态会导致后续命令协议错乱;务必在重连后重置操作上下文
- 连接池场景下未清理坏连接:调用
$pool->put($badRedis)会污染池子;应丢弃该实例,只push健康连接
安全重连的最小可行代码结构
不依赖框架封装,纯 Swoole 4 协程下推荐这样写:
// 初始化一次,复用连接对象(非连接池)
$redis = new Co\Redis();
$maxRetry = 3;
for ($i = 0; $i connect('127.0.0.1', 6379, 1.0)) {
throw new Exception('connect failed');
}
if ($redis->ping() !== true) {
throw new Exception('ping failed');
}
break; // 成功则跳出
} catch (Throwable $e) {
if ($i === $maxRetry - 1) throw $e;
Co::sleep(0.1 * ($i + 1)); // 指数退避
$redis = new Co\Redis(); // 彻底重建,不复用旧实例
}
}
// 后续命令可安全执行
$value = $redis->get('key');
防止协程崩溃的关键守则
协程一旦因未捕获异常退出,整个请求生命周期就中断。必须守住这三道防线:
- 所有 Redis 调用必须包裹
try/catch,且至少捕获RedisException和Throwable - 连接池 pop 出连接后,必须在
finally块中决定归还或丢弃,不能让异常跳过资源回收 - 禁用
Coroutine::close()或手动fclose()操作 Redis 底层 fd——Swoole 会自动管理,强行关闭反而触发 SIGSEGV










