6.0 KiB
6.0 KiB
超时对连接复用的影响分析
问题描述
当前测试套件没有充分验证超时与连接池交互的"无形结果"(intangible outcomes),可能存在以下风险:
- 超时后的连接泄漏
- 连接池被超时连接污染
- 连接池无法从超时中恢复
- 并发场景下部分超时影响整体池健康
代码行为分析
超时处理流程
HttpdnsNWHTTPClient.m:144-145
if (!rawResponse) {
[self returnConnection:connection forKey:poolKey shouldClose:YES];
// 返回 nil,error 设置
}
returnConnection:forKey:shouldClose: (line 279-281)
if (shouldClose || connection.isInvalidated) {
[connection invalidate]; // 取消底层 nw_connection
[pool removeObject:connection]; // 从池中移除
}
结论:代码逻辑正确,超时连接会被移除而非留在池中。
当前测试覆盖情况
已有测试:testIntegration_RequestTimeout_ReturnsError
验证内容:
- ✅ 超时返回
nilresponse - ✅ 超时设置
error
未验证内容(缺失):
- ❌ 连接是否从池中移除
- ❌ 池计数是否正确
- ❌ 后续请求是否正常工作
- ❌ 是否存在连接泄漏
- ❌ 并发场景下部分超时的影响
需要验证的"无形结果"
1. 单次超时后的池清理
场景:
- 请求 A 超时(timeout=1s, endpoint=/delay/10)
- 验证池状态
应验证:
- Pool count = 0(连接已移除)
- Total connection count 没有异常增长
- 无连接泄漏
测试方法:
[client resetPoolStatistics];
// 发起超时请求
NSError *error = nil;
HttpdnsNWHTTPClientResponse *response = [client performRequestWithURLString:@"http://127.0.0.1:11080/delay/10"
userAgent:@"TimeoutTest"
timeout:1.0
error:&error];
XCTAssertNil(response);
XCTAssertNotNil(error);
// 验证池状态
NSString *poolKey = @"127.0.0.1:11080:tcp";
XCTAssertEqual([client connectionPoolCountForKey:poolKey], 0, @"Timed-out connection should be removed");
XCTAssertEqual([client totalConnectionCount], 0, @"No connections should remain");
XCTAssertEqual(client.connectionCreationCount, 1, @"Should have created 1 connection");
XCTAssertEqual(client.connectionReuseCount, 0, @"No reuse for timed-out connection");
2. 超时后的池恢复能力
场景:
- 请求 A 超时
- 请求 B 正常(验证池恢复)
- 请求 C 复用 B 的连接
应验证:
- 请求 B 成功(池已恢复)
- 请求 C 复用连接(connectionReuseCount = 1)
- Pool count = 1(只有 B/C 的连接)
3. 并发场景:部分超时不影响成功请求
场景:
- 并发发起 10 个请求
- 5 个正常(timeout=15s)
- 5 个超时(timeout=0.5s, endpoint=/delay/10)
应验证:
- 5 个正常请求成功
- 5 个超时请求失败
- Pool count ≤ 5(只保留成功的连接)
- Total connection count ≤ 5(无泄漏)
- connectionCreationCount ≤ 10(合理范围)
- 成功的请求可以复用连接
4. 连续超时不导致资源泄漏
场景:
- 连续 20 次超时请求
- 验证连接池没有累积"僵尸连接"
应验证:
- Pool count = 0
- Total connection count = 0
- connectionCreationCount = 20(每次都创建新连接,因为超时的被移除)
- connectionReuseCount = 0(超时连接不可复用)
- 无内存泄漏(虽然代码层面无法直接测试)
5. 超时不阻塞连接池
场景:
- 请求 A 超时(endpoint=/delay/10, timeout=1s)
- 同时请求 B 正常(endpoint=/get, timeout=15s)
应验证:
- 请求 A 和 B 并发执行(不互相阻塞)
- 请求 B 成功(不受 A 超时影响)
- 请求 A 的超时连接被正确移除
- Pool 中只有请求 B 的连接
6. 多端口场景下的超时隔离
场景:
- 端口 11443 请求超时
- 端口 11444 请求正常
- 验证端口间隔离
应验证:
- 端口 11443 pool count = 0
- 端口 11444 pool count = 1
- 两个端口的连接池互不影响
测试实现建议
P 组:超时与连接池交互测试
P.1 单次超时清理验证
testTimeout_SingleRequest_ConnectionRemovedFromPool
P.2 超时后池恢复
testTimeout_PoolRecovery_SubsequentRequestSucceeds
P.3 并发部分超时
testTimeout_ConcurrentPartialTimeout_SuccessfulRequestsReuse
P.4 连续超时无泄漏
testTimeout_ConsecutiveTimeouts_NoConnectionLeak
P.5 超时不阻塞池
testTimeout_NonBlocking_ConcurrentNormalRequestSucceeds
P.6 多端口超时隔离
testTimeout_MultiPort_IsolatedPoolCleaning
Mock Server 支持
需要添加可配置延迟的 endpoint:
/delay/10- 延迟 10 秒(已有)- 测试时设置短 timeout(如 0.5s-2s)触发超时
预期测试结果
| 验证项 | 当前状态 | 目标状态 |
|---|---|---|
| 超时连接移除 | 未验证 | ✅ 验证池计数=0 |
| 池恢复能力 | 未验证 | ✅ 后续请求成功 |
| 并发超时隔离 | 未验证 | ✅ 成功请求不受影响 |
| 无连接泄漏 | 未验证 | ✅ 总连接数稳定 |
| 超时不阻塞 | 未验证 | ✅ 并发执行不阻塞 |
| 多端口隔离 | 未验证 | ✅ 端口间独立清理 |
风险评估
如果不测试这些场景的风险:
- 连接泄漏:超时连接可能未正确清理,导致内存泄漏
- 池污染:超时连接留在池中,被后续请求复用导致失败
- 级联故障:部分超时影响整体连接池健康
- 资源耗尽:连续超时累积连接,最终耗尽系统资源
当前代码逻辑正确性: ✅ 高(代码分析显示正确处理) 测试验证覆盖率: ❌ 低(缺少池交互验证)
建议: 添加 P 组测试以提供可观测的证据证明超时处理正确。
创建时间: 2025-11-01 维护者: Claude Code