Repository navigation
Conversation
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> Copilot-Session: 9163e8cc-4a32-471b-a4fe-f35cbb4339b7
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> Copilot-Session: 9163e8cc-4a32-471b-a4fe-f35cbb4339b7
There was a problem hiding this comment.
🟡 Changes recommended
新增的超时处理 hook 需要做异常隔离(避免 timeoutHandler 抛错中断超时扫描/回调),且新增测试里过短的 Mockito.after(200) 可能导致用例不稳定。
Once you've addressed the issues Copilot identified, you can request another Copilot review.
Pull request overview
该 PR 针对推送超时后仍可能复用旧连接(尤其是副本推送)的问题,通过在超时路径中使 TransportClient 失效并关闭底层 Netty channel,确保后续请求能建立新连接,同时将超时副本 peer 临时加入 unavailablePeers 以复用现有 fast-fail 语义。
Changes:
- 在 push 请求超时处理时触发超时回调(用于使
TransportClient失效并关闭连接),并新增单测验证回调顺序与连接替换行为。 - Worker 侧将副本推送超时的 peer 放入
unavailablePeers,并抽取/补充过期清理逻辑及对应测试。 - Spark IT 用例增加对超时后
unavailablePeers被填充的断言,并调整 fast-fail 配置以稳定验证。
File summaries
| File | Description |
|---|---|
| worker/src/main/scala/org/apache/celeborn/service/deploy/worker/Worker.scala | 抽取 removeExpiredUnavailablePeers 方法,用于统一清理过期的 fast-fail peer。 |
| worker/src/test/scala/org/apache/celeborn/service/deploy/worker/WorkerSuite.scala | 增加 removeExpiredUnavailablePeers 的过期清理测试覆盖。 |
| worker/src/main/scala/org/apache/celeborn/service/deploy/worker/PushDataHandler.scala | 在副本推送超时(PUSH_DATA_TIMEOUT_REPLICA)场景将 peer 写入 unavailablePeers。 |
| tests/spark-it/src/test/scala/org/apache/celeborn/tests/spark/PushDataTimeoutTest.scala | 增加 IT 断言:副本超时应导致某些 worker 的 unavailablePeers 非空,并清理测试状态。 |
| common/src/main/java/org/apache/celeborn/common/write/PushRequestInfo.java | 为 push 请求引入 timeoutHandler 并提供 handleTimeout() 入口。 |
| common/src/main/java/org/apache/celeborn/common/network/client/TransportResponseHandler.java | push 超时扫描中调用 info.handleTimeout(),为连接失效等超时动作提供挂钩。 |
| common/src/main/java/org/apache/celeborn/common/network/client/TransportClient.java | push/merged push 构造 PushRequestInfo 时注入超时 handler(失效并关闭 channel)。 |
| common/src/test/java/org/apache/celeborn/common/network/TransportResponseHandlerSuiteJ.java | 新增单测验证:先执行 timeoutHandler,再触发 push failure callback。 |
| common/src/test/java/org/apache/celeborn/common/network/TransportClientFactorySuiteJ.java | 新增 pooled client 场景单测:push 超时后 client 被替换、后续新连接推送成功。 |
Review details
Suppressed comments (1)
common/src/main/java/org/apache/celeborn/common/network/client/TransportResponseHandler.java:146
- 在 failExpiredPushRequest() 中新增的 info.handleTimeout() 如果抛出异常,会直接中断超时扫描逻辑,导致当前超时请求未回调 onFailure、并可能遗留 outstandingPushes(后续也不会被正确清理)。建议对 timeoutHandler 做保护性 try/catch,并记录日志,避免影响主超时处理流程。
if (info.channelFuture != null) {
info.channelFuture.cancel(true);
}
info.handleTimeout();
String module = conf.getModuleName();
// When module name equals to DATA_MODULE, mean shuffle client push data, else means
// do data replication.
if (TransportModuleConstants.DATA_MODULE.equals(module)) {
- Files reviewed: 9/9 changed files
- Comments generated: 1
- Review effort level: Lite
💡 Add a code-review agent skill or configure MCP servers for context-aware, tailored reviews. Learn more in the docs.
Co-authored-by: Copilot Autofix powered by AI <175728472+Copilot@users.noreply.github.com>
There was a problem hiding this comment.
Warning
Copilot couldn't run its full agentic review because it didn't start before the timeout. Make sure your repository has a runner available, or add a copilot-code-review.yml file specifying one with the runs-on attribute. See the docs for more details.
Pull request overview
Copilot reviewed 9 out of 9 changed files in this pull request and generated 2 comments.
| timedOutClient.pushData( | ||
| new PushData( | ||
| (byte) 0, | ||
| "shuffleKey", | ||
| "partitionId-1", | ||
| new NioManagedBuffer(ByteBuffer.allocate(1))), | ||
| 0, | ||
| timedOutCallback); | ||
| timedOutClient.pushData( | ||
| new PushData( | ||
| (byte) 0, | ||
| "shuffleKey", | ||
| "partitionId-2", | ||
| new NioManagedBuffer(ByteBuffer.allocate(1))), | ||
| TimeUnit.MINUTES.toMillis(1), | ||
| outstandingCallback); | ||
|
|
||
| timedOutClient.getHandler().failExpiredPushRequest(); |
There was a problem hiding this comment.
Addressed. The first request now uses a 1 ms timeout and the test waits 10 ms before calling failExpiredPushRequest(), ensuring dueTime is deterministically in the past even with a strict comparison.
| private void invalidate() { | ||
| this.timedOut = true; | ||
| channel.close(); | ||
| } |
There was a problem hiding this comment.
Addressed. invalidate() now delegates timedOut state management to the existing timeOut() method before closing the channel, avoiding duplicated state-setting logic.
|
Gentle ping for reviews! |
|
Production evidence for this, from a ~500-worker 0.6.2 fleet. We see sustained
A representative burst: Two things corroborate the stale-pooled-client diagnosis:
On scale: without invalidation the poisoned client stays eligible for reuse, so every subsequent push to that peer expires at 300s as well. One 20-minute window recorded 1,974,971 increments, 34% of a three-day total. The repeat rate looks unbounded. Adding Client-visible cost is real: Would be glad to see this merged, and we would need a |
|
This PR is stale because it has been open 20 days with no activity. Remove stale label or comment or this will be closed in 10 days. |
Problem
A push request timeout leaves the pooled
TransportClienteligible for reuse while its Netty channel still reports active. After a Worker restart or Pod IP replacement, long-running applications can therefore repeatedly send replica pushes over a stale connection and receivePUSH_DATA_TIMEOUT_REPLICA.JIRA: CELEBORN-2458
Fix
TransportClientFactorycreates a fresh connection for the next request.unavailablePeers, reusing the existing replica fast-fail duration.Verification
unavailablePeers.TransportResponseHandlerSuiteJandTransportClientFactorySuiteJ: passed.WorkerSuite: 7 passed.PushDataTimeoutTestwith Spark 3.5: 5 passed.common,worker, andspark-itpackage build: passed.