Skip to content

fix(amber): report an uninitialized execution instead of NPEing, and map unparseable frames - #7802

Open
aglinxinyuan wants to merge 1 commit into
apache:mainfrom
aglinxinyuan:fix/websocket-uninitialized-execution
Open

fix(amber): report an uninitialized execution instead of NPEing, and map unparseable frames#7802
aglinxinyuan wants to merge 1 commit into
apache:mainfrom
aglinxinyuan:fix/websocket-uninitialized-execution

Conversation

@aglinxinyuan

Copy link
Copy Markdown
Contributor

What changes were proposed in this PR?

Three defects in WorkflowWebsocketResource, all previously characterized without being cemented (#7303, #7676) so a fix would not have to fight a test asserting the broken behaviour.

1 & 2. A workflow with no execution NPEs instead of reporting "not initialized".

WorkflowService.executionService is a BehaviorSubject with no initial value (WorkflowService.scala:140), so getValue is null until an execution is published.

  • case other => used workflowStateOpt.map(_.executionService.getValue), which wraps that null into Some(null) — walking past the case None arm that exists to report the friendly error, then NPEing on value.wsInput. Now uses the already-computed executionStateOpt, which is built with Option(...), so Some(null) cannot form and the existing None arm actually fires.
  • The ModifyLogicRequest arm had the same gap in a different shape: its guard tested the workflow where it meant the execution. Now executionStateOpt.getOrElse(throw new IllegalStateException("workflow execution is not initialized")).

Line 89 of this file already used Option(...) correctly, as does WorkflowService at its lines 208 and 349 — the fix adopts the established in-tree idiom rather than inventing one.

A shape decision worth reviewing. For the ModifyLogicRequest arm I did not simply swap the outer condition to executionStateOpt.isDefined. That variant makes a workflow-without-execution silently do nothing instead of reporting, which is not the intent — and it would collide with the pre-existing test "ignore a ModifyLogicRequest that arrives before any workflow is attached", which pins the no-workflow case as noException plus sent shouldBe empty. Keeping the workflow guard and reporting the absent execution satisfies both.

3. An unparseable frame no longer escapes the error mapper. objectMapper.readValue moved from above the try to its first statement, so a frame the mapper cannot bind is reported like any handler failure. sessionState and executionStateOpt stay outside, because the catch arm needs them — both routing arms still work.

All messages use the existing wording, "workflow execution is not initialized".

The fixes are pinned

Four new tests. Verified in both directions, with the production file reverted and restored:

production reverted with fixes
WorkflowWebsocketResourceSpec 15 passed, 4 failed 19 passed, 0 failed

The before-state failures are the right ones, from the JUnit XML (sbt's only reporter here is -u, so the console shows no per-test lines):

new test failure without the fix
runtime command with a workflow but no execution Expected java.lang.IllegalStateException … java.lang.NullPointerException was thrown
ModifyLogicRequest before any execution exists Expected java.lang.IllegalStateException … java.lang.NullPointerException was thrown
unparseable frame instead of escaping unmapped List() was not equal to List("WorkflowErrorEvent")
unparseable frame recorded in the metadata store List() was not equal to List(COMPILATION_ERROR)

None of the 15 pre-existing tests regressed.

Spec comments were updated, not just tests added

The spec's header paragraph on malformed frames, its "deliberately not covered" entry for ModifyLogicRequest, and two in-test notes all documented these as known-and-unpinned. Leaving them would have left the spec asserting one thing and explaining the opposite, so they are rewritten to match.

Trap avoidance, all previously encountered in this file: no assertions on ClusterListener.numWorkerNodesInCluster (its default is 0, so such an assertion passes even against a hard-coded literal); PrivilegeEnum.WRITE is fed rather than the NONE default; and the new tests use TestWorkflowService, which overrides disconnect(), so afterEach never reaches the null AmberRuntime._actorSystem — the same pattern the existing tests use.

Verification

  • WorkflowWebsocketResourceSpec: 19/19.
  • Blast radius: TexeraWebSocketRequestSpec, SessionStateSpec, ServletAwareConfiguratorSpec, WebsocketInputSpec — 28/28 across 4 suites. TexeraWebSocketRequestSpec pins InvalidTypeIdException at the mapper level, which these changes leave untouched.
  • scalafmtCheck, Test/scalafmtCheck, scalafixAll --check all pass.
  • Production diff is 15 lines in one file.

Any related issues, documentation, discussions?

Closes #7801

How was this PR tested?

STORAGE_ICEBERG_CATALOG_TYPE=postgres sbt "WorkflowExecutionService/testOnly org.apache.texera.web.resource.WorkflowWebsocketResourceSpec"
[info] Suites: completed 1, aborted 0
[info] Tests: succeeded 19, failed 0, canceled 0, ignored 0, pending 0

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

Generated-by: Claude Code (Opus 5)

Copilot AI lite review requested due to automatic review settings August 20, 2026 05:36

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 the release/v1.2 back porting to release/v1.2 label Aug 20, 2026
@github-actions
github-actions Bot requested a review from xuang7 August 20, 2026 05:36
@github-actions

Copy link
Copy Markdown
Contributor

Backport auto-label report

This fix: PR was checked against each actively-supported release branch. release/* labels drive the post-merge backport, so add or remove one to change where this fix lands.

Release branch Analysis
release/v1.2 Change detected on this branch — label added; this fix is queued to backport here. Requested review from @xuang7.

Auto-label run.

@github-actions

Copy link
Copy Markdown
Contributor

Automated Reviewer Suggestions

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

  • Contributors with relevant context: @Yicong-Huang
    You can notify them by mentioning @Yicong-Huang in a comment.

@github-actions

Copy link
Copy Markdown
Contributor

⚠️ Benchmark changes need a look

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

Compared against main 875aa72 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 353 0.215 29,694/34,152/34,152 us 🔴 +23.7% / 🔴 +132.9%
🔴 bs=100 sw=10 sl=64 783 0.478 125,795/166,881/166,881 us 🔴 +9.7% / 🔴 +56.3%
bs=1000 sw=10 sl=64 893 0.545 1,117,591/1,197,216/1,197,216 us ⚪ within ±5% / 🔴 +18.2%
Baseline details

Latest main 875aa72 from same runner

config metric PR latest main 7d avg Δ latest Δ 7d
bs=10 sw=10 sl=64 throughput 353 tuples/sec 410 tuples/sec 771.02 tuples/sec -13.9% -54.2%
bs=10 sw=10 sl=64 MB/s 0.215 MB/s 0.25 MB/s 0.471 MB/s -14.0% -54.3%
bs=10 sw=10 sl=64 p50 29,694 us 24,003 us 12,749 us +23.7% +132.9%
bs=10 sw=10 sl=64 p95 34,152 us 33,028 us 15,594 us +3.4% +119.0%
bs=10 sw=10 sl=64 p99 34,152 us 33,028 us 19,320 us +3.4% +76.8%
bs=100 sw=10 sl=64 throughput 783 tuples/sec 813 tuples/sec 997.05 tuples/sec -3.7% -21.5%
bs=100 sw=10 sl=64 MB/s 0.478 MB/s 0.496 MB/s 0.609 MB/s -3.6% -21.5%
bs=100 sw=10 sl=64 p50 125,795 us 121,768 us 100,339 us +3.3% +25.4%
bs=100 sw=10 sl=64 p95 166,881 us 152,064 us 106,781 us +9.7% +56.3%
bs=100 sw=10 sl=64 p99 166,881 us 152,064 us 113,101 us +9.7% +47.6%
bs=1000 sw=10 sl=64 throughput 893 tuples/sec 919 tuples/sec 1,037 tuples/sec -2.8% -13.9%
bs=1000 sw=10 sl=64 MB/s 0.545 MB/s 0.561 MB/s 0.633 MB/s -2.9% -13.9%
bs=1000 sw=10 sl=64 p50 1,117,591 us 1,077,876 us 971,388 us +3.7% +15.1%
bs=1000 sw=10 sl=64 p95 1,197,216 us 1,142,830 us 1,013,249 us +4.8% +18.2%
bs=1000 sw=10 sl=64 p99 1,197,216 us 1,142,830 us 1,039,879 us +4.8% +15.1%
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,566.72,200,128000,353,0.215,29693.77,34151.93,34151.93
1,100,10,64,20,2553.69,2000,1280000,783,0.478,125795.45,166881.02,166881.02
2,1000,10,64,20,22392.18,20000,12800000,893,0.545,1117591.01,1197216.02,1197216.02

@codecov-commenter

codecov-commenter commented Aug 20, 2026

Copy link
Copy Markdown

Codecov Report

✅ All modified and coverable lines are covered by tests.
✅ Project coverage is 91.33%. Comparing base (c8b9495) to head (e2fd7c6).
⚠️ Report is 1 commits behind head on main.

Additional details and impacted files
@@             Coverage Diff              @@
##               main    #7802      +/-   ##
============================================
- Coverage     91.34%   91.33%   -0.01%     
+ Complexity     4479     4477       -2     
============================================
  Files          1171     1171              
  Lines         47199    47200       +1     
  Branches       5303     5303              
============================================
- Hits          43114    43112       -2     
- Misses         2428     2429       +1     
- Partials       1657     1659       +2     
Flag Coverage Δ *Carryforward flag
access-control-service 81.00% <ø> (ø) Carriedforward from c8b9495
agent-service 98.62% <ø> (ø) Carriedforward from c8b9495
amber 88.08% <100.00%> (-0.02%) ⬇️
computing-unit-managing-service 73.67% <ø> (ø) Carriedforward from c8b9495
config-service 86.73% <ø> (ø) Carriedforward from c8b9495
file-service 68.90% <ø> (ø) Carriedforward from c8b9495
frontend 92.84% <ø> (ø) Carriedforward from c8b9495
notebook-migration-service 79.13% <ø> (ø) Carriedforward from c8b9495
pyamber 97.57% <ø> (ø) Carriedforward from c8b9495
workflow-compiling-service 77.19% <ø> (ø) Carriedforward from c8b9495

*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.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

engine fix release/v1.2 back porting to release/v1.2

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Websocket handlers NPE before an execution exists, and unparseable frames are never reported

4 participants