Skip to content

refactor(amber): count a materialized input port as completed once its END is processed - #8938

Merged
aglinxinyuan merged 4 commits into
apache:mainfrom
aglinxinyuan:fix-loop-integration-flaky
Oct 15, 2026
Merged

aglinxinyuan merged 4 commits into
apache:mainfrom
aglinxinyuan:fix-loop-integration-flaky

Conversation

@aglinxinyuan

@aglinxinyuan aglinxinyuan commented Oct 9, 2026 •

Copy link
Copy Markdown
Contributor

What changes were proposed in this PR?

InputManager.isPortCompleted now treats a port read from materialization the same as a port fed by a link: it counts as completed once END_CHANNEL has been processed on it. EndChannelHandler marks that by setting WorkerPort.completed.

Before, such a port reported its reader thread's finished flag. The thread sets that flag only after enqueuing END. So a DP thread waiting on the queue, typically the worker that got no tuples, could run EndChannelHandler before the flag was set. It then saw the port as not completed and skipped finalizeOutput. Nothing called it again, so the worker never finished and its region hung until the test deadline. That is the intermittent TimeoutException: 1.minutes+30.seconds in LoopIntegrationSpec.

Before:  reader enqueues END -> DP processes END, flag not set yet -> output never finalized -> region hangs
After:   reader enqueues END -> DP processes END, port completed   -> output finalized       -> region completes

Two related effects of the change:

  • The flag could also be set while END was still queued. A worker with a second materialized input no longer finalizes before that port's END has been processed.
  • startInputPortReaderThreads uses the same check to skip ports that already completed. The second StartWorker of a two-phase region arrives only after the coordinator has the port's PortCompleted, which the worker sends after processing END. So it skips the same ports as before.
  • Nothing reads the reader thread's finished flag any more, so it is removed, and it can't stand in for port completion again. The reader-thread tests that read it now check the END_CHANNEL the reader enqueues instead.

Any related issues, documentation, discussions?

Closes #8937. The two LoopIntegrationSpec cases added in #8639 hit the race most often; the race itself dates from #3460.

How was this PR tested?

Tests first: the first commit adds the tests and fails on main, and the second commit makes them pass.

  • InputManagerSpec: a materialized port is completed once END has been processed, even before its reader thread has returned. It is not completed while END is still queued, even after the thread has returned.
  • EndChannelHandlerSpec: when END arrives on a materialized input port before its reader thread has returned, the worker emits the output FinalizePort and FinalizeExecutor. On main it emits only the input port's FinalizePort, which is the hang.
sbt "WorkflowExecutionService/testOnly *InputManagerSpec *EndChannelHandlerSpec *StartHandlerSpec *DataProcessorSpec *EndHandlerSpec *StartChannelHandlerSpec *AssignPortHandlerSpec *DPThreadSpec *WorkerSpec"
sbt "WorkflowExecutionService/scalafmtCheckAll" "WorkflowExecutionService/scalafixAll --check"

InputPortMaterializationReaderThreadSpec reads real Iceberg tables. Locally only its two cases that don't need storage ran; CI runs the rest.

LoopIntegrationSpec, run locally on Windows with the sbt JVM and its Python workers pinned to 3 CPUs (affinity mask 0x7), one case per JVM:

Case main This PR
bind a $i reference after two branches of the loop body meet again 3 of 5 runs hung on the first attempt; 1 also hung on the retry and failed as on CI 10 of 10 passed on the first attempt, 42–44 s each
bind the inner loop's variable where it shadows the outer loop's (fails on CI, see #8937) 10 of 10 passed on the first attempt, 64–70 s each

Unpinned, the whole spec passes with this PR: 8 of 8 cases, 29–59 s each, no retries.

AMBER_TEST_FILTER= STORAGE_ICEBERG_CATALOG_TYPE=postgres sbt "WorkflowExecutionService/testOnly *LoopIntegrationSpec -- -z \"after two branches of the loop body meet again\""
AMBER_TEST_FILTER=integration-only STORAGE_ICEBERG_CATALOG_TYPE=postgres sbt "WorkflowExecutionService/testOnly *LoopIntegrationSpec"

Was this PR authored or co-authored using generative AI tooling?

Generated-by: Claude Code (Claude Opus 5.5)

🤖 Generated with Claude Code

A materialized input port's reader thread enqueues END_CHANNEL and only
then flags itself finished. These tests deliver END before that flag
flips (and the reverse: the flag set while END is still queued) and
expect the port to count as completed exactly when END was processed,
so the worker finalizes its output. They fail on main, where
isPortCompleted reads the reader thread's flag.
… is processed

InputManager.isPortCompleted returned the materialization reader
thread's finished flag for a port read from storage. The thread sets
that flag only after enqueuing END_CHANNEL, so a DP thread waiting on
the queue could run EndChannelHandler first, see the port as not
completed and skip finalizeOutput. Nothing retried it: the worker never
finished and its region hung (the LoopIntegrationSpec timeouts).

A port is now completed when END has been processed on it
(WorkerPort.completed, set by EndChannelHandler), the same as a port
fed by a link. The startInputPortReaderThreads fixture registers its
port first, as addPort always does.
Copilot AI balanced review requested due to automatic review settings October 9, 2026 04:55

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Copilot was unable to review this pull request because the user who requested the review has reached their quota limit.

@Yicong-Huang Yicong-Huang added release/v1.3 back porting to release/v1.3 release/v1.2 back porting to release/v1.2 labels Oct 9, 2026
@github-actions
github-actions Bot requested a review from mengw15 October 9, 2026 04:56
@github-actions

github-actions Bot commented Oct 9, 2026

Copy link
Copy Markdown
Contributor

Automated Reviewer Suggestions

Based on the git blame history of the changed files, we recommend the following reviewers:

  • No candidates found from git blame history.

@github-actions
github-actions Bot requested a review from xuang7 October 9, 2026 04:56
@github-actions

github-actions Bot commented Oct 9, 2026 •

Copy link
Copy Markdown
Contributor

Backport auto-label report

This fix: PR was checked against each actively-supported release branch. A release/* label nominates a backport target; the branch's release manager approving this PR is what sends the fix there. The required Backport Approvals check stays red until every label below is approved, so each manager either approves or removes their own label — which is why the labels left on a merged PR are exactly the branches it reached.

Release branch Analysis
✅ release/v1.3 Already labeled — this fix is queued to backport here. @mengw15 decides: approving sends the fix here, removing this label declines it. The merge waits on one or the other.
✅ release/v1.2 Already labeled — this fix is queued to backport here. @xuang7 decides: approving sends the fix here, removing this label declines it. The merge waits on one or the other.

Auto-label run.

@github-actions

github-actions Bot commented Oct 9, 2026 •

Copy link
Copy Markdown
Contributor

⚠️ Benchmark changes need a look

🟢 0 better · 🔴 3 worse · ⚪ 12 noise (<±5%) · 0 without baseline

Compared against main 6a29c59 benchmarked on this same runner, so the delta is largely free of cross-runner hardware noise. The "7d avg" column still reflects the gh-pages dashboard. Treat <±5% as noise unless repeated.

Dashboard · Run

config throughput MB/s latency max Δ latest / 7d
🔴 bs=10 sw=10 sl=64 390 0.238 25,446/33,752/33,752 us 🔴 -9.2% / 🔴 +127.5%
⚪ bs=100 sw=10 sl=64 794 0.485 122,277/157,739/157,739 us ⚪ within ±5% / 🔴 +56.7%
⚪ bs=1000 sw=10 sl=64 918 0.56 1,095,180/1,160,050/1,160,050 us ⚪ within ±5% / 🔴 +21.2%
Baseline details

Latest main 6a29c59 from same runner

config metric PR latest main 7d avg Δ latest Δ 7d
bs=10 sw=10 sl=64 throughput 390 tuples/sec 429 tuples/sec 840.06 tuples/sec -9.1% -53.6%
bs=10 sw=10 sl=64 MB/s 0.238 MB/s 0.262 MB/s 0.513 MB/s -9.2% -53.6%
bs=10 sw=10 sl=64 p50 25,446 us 23,351 us 11,813 us +9.0% +115.4%
bs=10 sw=10 sl=64 p95 33,752 us 32,381 us 14,838 us +4.2% +127.5%
bs=10 sw=10 sl=64 p99 33,752 us 32,381 us 17,837 us +4.2% +89.2%
bs=100 sw=10 sl=64 throughput 794 tuples/sec 821 tuples/sec 1,087 tuples/sec -3.3% -26.9%
bs=100 sw=10 sl=64 MB/s 0.485 MB/s 0.501 MB/s 0.663 MB/s -3.2% -26.9%
bs=100 sw=10 sl=64 p50 122,277 us 117,973 us 94,074 us +3.6% +30.0%
bs=100 sw=10 sl=64 p95 157,739 us 152,228 us 100,688 us +3.6% +56.7%
bs=100 sw=10 sl=64 p99 157,739 us 152,228 us 116,015 us +3.6% +36.0%
bs=1000 sw=10 sl=64 throughput 918 tuples/sec 923 tuples/sec 1,128 tuples/sec -0.5% -18.6%
bs=1000 sw=10 sl=64 MB/s 0.56 MB/s 0.563 MB/s 0.689 MB/s -0.5% -18.7%
bs=1000 sw=10 sl=64 p50 1,095,180 us 1,086,170 us 916,643 us +0.8% +19.5%
bs=1000 sw=10 sl=64 p95 1,160,050 us 1,208,131 us 957,169 us -4.0% +21.2%
bs=1000 sw=10 sl=64 p99 1,160,050 us 1,208,131 us 978,578 us -4.0% +18.5%
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,512.88,200,128000,390,0.238,25445.79,33752.08,33752.08
1,100,10,64,20,2518.90,2000,1280000,794,0.485,122276.92,157738.96,157738.96
2,1000,10,64,20,21796.76,20000,12800000,918,0.560,1095179.64,1160050.12,1160050.12

@codecov-commenter

codecov-commenter commented Oct 9, 2026 •

Copy link
Copy Markdown

Codecov Report

✅ All modified and coverable lines are covered by tests.
✅ Project coverage is 92.61%. Comparing base (6a29c59) to head (bb46d20).
✅ All tests successful. No failed tests found.

Additional details and impacted files
@@             Coverage Diff              @@
##               main    #8938      +/-   ##
============================================
- Coverage     92.61%   92.61%   -0.01%     
+ Complexity     5059     5056       -3     
============================================
  Files          1258     1258              
  Lines         53780    53770      -10     
  Branches       6707     6705       -2     
============================================
- Hits          49811    49798      -13     
- Misses         2313     2316       +3     
  Partials       1656     1656              
Flag Coverage Δ *Carryforward flag
access-control-service 77.38% <ø> (ø) Carriedforward from 9cf43f2
agent-service 99.16% <ø> (ø) Carriedforward from 9cf43f2
amber 88.10% <100.00%> (-0.01%) ⬇️
computing-unit-managing-service 60.48% <ø> (ø) Carriedforward from 9cf43f2
config-service 87.37% <ø> (ø) Carriedforward from 9cf43f2
file-service 82.00% <ø> (ø) Carriedforward from 9cf43f2
frontend 96.59% <ø> (+<0.01%) ⬆️ Carriedforward from 9cf43f2
notebook-migration-service 83.73% <ø> (ø) Carriedforward from 9cf43f2
pyamber 98.52% <ø> (-0.07%) ⬇️ Carriedforward from 9cf43f2
workflow-compiling-service 72.43% <ø> (ø) Carriedforward from 9cf43f2

*This pull request uses carry forward flags. Click here to find out more.

☔ View full report in Codecov by Harness.
📢 Have feedback on the report? Share it here.

🚀 New features to boost your workflow:
  • 📦 JS Bundle Analysis: Save yourself from yourself by tracking and limiting bundle sizes in JS merges.

…flag

After the fix, nothing outside tests reads InputPortMaterializationReaderThread
.finished, and it is exactly the signal that must not stand for port
completion. Remove it. The tests that read it now check what it stood
for: the END_CHANNEL the reader enqueued, or the thread's own state.

@carloea2 carloea2 left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Retested bb46d20 locally on Windows with JDK 17, Python 3.12 and isolated PostgreSQL databases. All 118 focused engine tests and all 8 LoopIntegrationSpec tests pass. Formatting also passes.

sbt -batch 'WorkflowExecutionService/testOnly *InputManagerSpec *EndChannelHandlerSpec *StartHandlerSpec *DataProcessorSpec *EndHandlerSpec *StartChannelHandlerSpec *AssignPortHandlerSpec *DPThreadSpec *WorkerSpec *InputPortMaterializationReaderThreadSpec -- -oDF' 'scalafmtCheckAll' 'WorkflowExecutionService/testOnly *LoopIntegrationSpec -- -oDF'

This fixes the completion race I reproduced. No competing PR is needed. Backport approvals are still pending.

@carloea2 carloea2 left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Verified bb46d20 locally. All 118 focused tests and 8 loop tests pass, formatting is clean, and required build checks are green. The completion race is fixed. Backport approvals from the release managers are still pending.

@aglinxinyuan aglinxinyuan changed the title fix(amber): count a materialized input port as completed once its END is processed refactor(amber): count a materialized input port as completed once its END is processed Oct 14, 2026
@aglinxinyuan aglinxinyuan removed fix release/v1.2 back porting to release/v1.2 release/v1.3 back porting to release/v1.3 labels Oct 14, 2026
@aglinxinyuan
aglinxinyuan added this pull request to the merge queue Oct 14, 2026
@github-merge-queue
github-merge-queue Bot removed this pull request from the merge queue due to no response for status checks Oct 14, 2026
@carloea2

Copy link
Copy Markdown
Contributor

@Xiao-zhen-Liu, required checks now pass on Linux and macOS, and the review thread is resolved. Could you merge this when you have time? I can then refresh #8142 and #8144 to trigger CI with the loop fix.

@aglinxinyuan
aglinxinyuan added this pull request to the merge queue Oct 15, 2026
Merged via the queue into apache:main with commit cf75462 Oct 15, 2026
54 of 65 checks passed
@aglinxinyuan
aglinxinyuan deleted the fix-loop-integration-flaky branch October 15, 2026 02:54
aglinxinyuan added a commit to aglinxinyuan/texera that referenced this pull request Oct 15, 2026
Resolves the conflict with apache#8938 in InputManager.isPortCompleted: main counts a port as completed once its END is processed, which subsumes the prototype's extra check, so main's version is kept. The control-variable port's END still marks it completed before EndChannelHandler starts the data readers.
renovate-bot pushed a commit to renovate-bot/apache-_-texera that referenced this pull request Oct 15, 2026
### What changes were proposed in this PR?

The Python GlobalPortIdentity decoder now rejects invalid boolean tokens
instead of silently treating them as false. Valid mixed-case true and
false values remain supported.

### Any related issues, documentation, discussions?

Closes apache#8239

### How was this PR tested?

Retested with Python 3.12 on Windows in a fresh detached worktree from
upstream main at `7426431337`, which includes the merged loop-completion
change apache#8938. Regression before implementation: 2 failed, 48 passed.
After implementation: 50 passed.

Generate protobufs with `bash bin/python-proto-gen.sh`, then run from
`amber`:

```text
python -m pytest src/test/python/core/util/test_virtual_identity.py src/test/python/core/storage/test_vfs_uri_factory.py -q --tb=line -p no:cacheprovider
python -m ruff check src/main/python src/test/python
python -m ruff format --check src/main/python src/test/python
```

Ruff lint and formatting pass for all 217 Python files.

### Was this PR authored or co-authored using generative AI tooling?

Generated-by: Codex
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

Projects

None yet

Development

Successfully merging this pull request may close these issues.

A worker reading a materialized input can miss its port completion and hang the region

6 participants