Conversation
When a region has dependee input ports (e.g. a HashJoin probe), its non-dependee operators are launched from a later advance round via syncStatusAndTransitionRegionExecutionPhase(). advanceRegionExecutions discarded those futures, so if a worker failed there (e.g. a Python UDF whose code raises NameError at load time) the error was lost: no FatalError reached the client, no operator in the region started, and the execution stayed RUNNING forever. - Keep the sync futures and fail the advance future if any fails, so AdvanceRegionExecutionsHandler reports a FatalError. - Log ControlError contents in AsyncRPCClient; it is not a Throwable, so the logger silently dropped it. - Tests: manager unit tests for a failing/succeeding second phase, and e2e csv->join->Python UDF tests, including a UDF missing `from pytexera import *`, which now fails in ~1s instead of timing out. Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
Backport auto-label reportThis
|
Automated Reviewer SuggestionsBased on the
|
|
| config | throughput | MB/s | latency | max Δ latest / 7d | |
|---|---|---|---|---|---|
| 🟢 | bs=10 sw=10 sl=64 | 404 | 0.247 | 23,734/30,374/30,374 us | 🟢 -20.6% / 🔴 +80.2% |
| 🔴 | bs=100 sw=10 sl=64 | 797 | 0.486 | 120,098/190,042/190,042 us | 🔴 +42.2% / 🔴 +69.5% |
| 🔴 | bs=1000 sw=10 sl=64 | 914 | 0.558 | 1,091,422/1,199,202/1,199,202 us | 🔴 +5.8% / 🔴 +11.8% |
Baseline details
Latest main 14de458 from same runner
| config | metric | PR | latest main | 7d avg | Δ latest | Δ 7d |
|---|---|---|---|---|---|---|
| bs=10 sw=10 sl=64 | throughput | 404 tuples/sec | 403 tuples/sec | 736.99 tuples/sec | +0.2% | -45.2% |
| bs=10 sw=10 sl=64 | MB/s | 0.247 MB/s | 0.246 MB/s | 0.45 MB/s | +0.4% | -45.1% |
| bs=10 sw=10 sl=64 | p50 | 23,734 us | 22,912 us | 13,174 us | +3.6% | +80.2% |
| bs=10 sw=10 sl=64 | p95 | 30,374 us | 38,273 us | 16,900 us | -20.6% | +79.7% |
| bs=10 sw=10 sl=64 | p99 | 30,374 us | 38,273 us | 19,889 us | -20.6% | +52.7% |
| bs=100 sw=10 sl=64 | throughput | 797 tuples/sec | 826 tuples/sec | 946.47 tuples/sec | -3.5% | -15.8% |
| bs=100 sw=10 sl=64 | MB/s | 0.486 MB/s | 0.504 MB/s | 0.578 MB/s | -3.6% | -15.9% |
| bs=100 sw=10 sl=64 | p50 | 120,098 us | 121,032 us | 105,257 us | -0.8% | +14.1% |
| bs=100 sw=10 sl=64 | p95 | 190,042 us | 133,653 us | 112,150 us | +42.2% | +69.5% |
| bs=100 sw=10 sl=64 | p99 | 190,042 us | 133,653 us | 125,962 us | +42.2% | +50.9% |
| bs=1000 sw=10 sl=64 | throughput | 914 tuples/sec | 917 tuples/sec | 973.64 tuples/sec | -0.3% | -6.1% |
| bs=1000 sw=10 sl=64 | MB/s | 0.558 MB/s | 0.56 MB/s | 0.594 MB/s | -0.4% | -6.1% |
| bs=1000 sw=10 sl=64 | p50 | 1,091,422 us | 1,086,193 us | 1,032,217 us | +0.5% | +5.7% |
| bs=1000 sw=10 sl=64 | p95 | 1,199,202 us | 1,133,575 us | 1,072,497 us | +5.8% | +11.8% |
| bs=1000 sw=10 sl=64 | p99 | 1,199,202 us | 1,133,575 us | 1,102,623 us | +5.8% | +8.8% |
Raw CSV
config_idx,batch_size,schema_width,string_len,num_batches,total_ms,total_tuples,total_bytes,tuples_per_sec,mb_per_sec,lat_p50_us,lat_p95_us,lat_p99_us
0,10,10,64,20,494.98,200,128000,404,0.247,23734.03,30373.85,30373.85
1,100,10,64,20,2510.16,2000,1280000,797,0.486,120098.18,190042.25,190042.25
2,1000,10,64,20,21877.26,20000,12800000,914,0.558,1091422.25,1199201.68,1199201.68
Codecov Report❌ Patch coverage is Additional details and impacted files@@ Coverage Diff @@
## main #8668 +/- ##
============================================
+ Coverage 92.73% 92.76% +0.02%
+ Complexity 4943 4926 -17
============================================
Files 1242 1243 +1
Lines 52548 52451 -97
Branches 6492 6449 -43
============================================
- Hits 48731 48656 -75
+ Misses 2212 2194 -18
+ Partials 1605 1601 -4
*This pull request uses carry forward flags. Click here to find out more. ☔ View full report in Codecov by Harness. 🚀 New features to boost your workflow:
|
|
/request-review @aicam |
|
Removed backport label: not a regression (the behavior predates v1.2), the failure is visible rather than silent. |
Wrap the per-worker RPCs that launch a region (initializeExecutor, assignPort, openExecutor, startWorker) so a failure becomes a WorkflowRuntimeException carrying the target worker id. The existing FatalError(err, err.relatedWorkerId) in AdvanceRegionExecutionsHandler then reports it, and the UI can attribute the error to that operator. Addresses review feedback on apache#8668. Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
|
@Ma77Ball Thanks, good call. Done in 1d583d5. The failure arrived as a plain The tests now assert the worker ID too, and they failed before this change:
|
Wrap the per-worker RPCs that launch a region (initializeExecutor, assignPort, openExecutor, startWorker) so a failure becomes a WorkflowRuntimeException carrying the target worker id. The existing FatalError(err, err.relatedWorkerId) in PortCompletedHandler then reports it, and the UI can attribute the error to that operator. Port of review feedback on apache/texera#8668. Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
|
@sshiv012 there does appear to be a failing test in the |
The amber CI job has no Python environment, so the e2e tests that started a real Python worker could not run there. Use a Java UDF whose code does not compile instead: it fails in initializeExecutor exactly like a Python UDF with an import error, with no external runtime. The happy path stays covered by the existing join e2e test and the WorkflowExecutionManagerSpec unit test. Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
|
Fixed in d784f5d. The new e2e tests started a real Python worker, which passed locally but not in CI, because CI's amber job has no Python environment?? The test now uses a Java UDF that fails to compile at the same setup step, so it needs no Python. |
What changes were proposed in this PR?
A worker failing to initialize in a region's second (non-dependee) phase, e.g. a Python UDF after a HashJoin, used to leave the execution
RUNNINGforever with no error. See the issue for the full chain.WorkflowExecutionManager.advanceRegionExecutions: keep thesyncStatusAndTransitionRegionExecutionPhase()futures instead of dropping them in aforeach. The advance future now fails if any sync fails, so the existing.onFailure → FatalErrorinAdvanceRegionExecutionsHandlerreports it. The rest of the method moved unchanged intoadvanceToNextRegions.RegionExecutionManager: a failed launch RPC (initializeExecutor,assignPort,openExecutor,startWorker) is wrapped asWorkflowRuntimeExceptionwith the target worker ID, so theFatalErrornames the failing worker and operator (review feedback).AsyncRPCClient.logControlReply: log theControlErrormessage, details and stack trace. It isn't aThrowable, so the logger silently dropped it.from pytexera import *after a joinname 'UDFTableOperator' is not defined, attributed to the UDF workerreceived error from …received error from … (controlID: N): <message>Behavior note: the future returned by
advanceRegionExecutionsnow also waits on, and fails with, the syncs it triggers.AdvanceRegionExecutionsHandlerdoesn't wait on it.StartWorkflowHandlerhas no unfinished regions at start, so nothing changes there.Any related issues, documentation, discussions?
Closes #8667
How was this PR tested?
Added tests. Each new failing-case test fails before the fix and passes after it.
WorkflowExecutionManagerSpec, 2 new tests: a region whose probe op has a dependee port, followed by a UDF op.initializeExecutorreturns aControlError→ the advance fails with that message.DataProcessingSpec, 1 new e2e test on csv, csv → join → UDF: a Java UDF whose code doesn't compile, so the worker fails ininitializeExecutor, the same step as a Python UDF with an import error.RegionExecutionManagerTestSupport:CoordinatorRpcProbetakes an optionalinitializeExecutorResponse.Was this PR authored or co-authored using generative AI tooling?
Generated-by: Claude Code (Claude Opus 5.5)
🤖 Generated with Claude Code