Skip to content

[Dataflow Streaming] [MultiKey] Handle work cancellation exceptions in WorkFailureProcessor. - #40955

Open
arunpandianp wants to merge 1 commit into
apache:masterfrom
arunpandianp:handle_work_cancellation_exception
Open

arunpandianp wants to merge 1 commit into
apache:masterfrom
arunpandianp:handle_work_cancellation_exception

Conversation

@arunpandianp

Copy link
Copy Markdown
Contributor

When processing a multi-key bundle, if one key fails due to a Windmill work cancellation (WorkCancellingException or WorkItemCancelledException), unaffected sibling keys in the batch must not be misclassified as uncaught user exceptions.

This change adds WorkItemCancelledException.isWorkItemCancelledException(), updates WorkFailureProcessor.evaluateRetry() to return RetryEvaluation.RETRY_LOCALLY without reporting the failure or sleeping, and prevents infinite loops on circular causal chains in both isWorkCancellingException and isWorkItemCancelledException.

@github-actions github-actions Bot added runners dataflow size/s S: 10-49 lines changed labels Nov 2, 2026

@github-actions github-actions Bot 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.

📋 Review Summary

This PR handles cyclic causal chains when inspecting exceptions in WorkCancellingException, WorkItemCancelledException, and WorkFailureProcessor, preventing StackOverflowErrors or infinite loops during failure processing. The implementation using identity-based Sets (Collections.newSetFromMap(new IdentityHashMap<>())) and the accompanying unit tests are clean, idiomatic, and thorough.

🔍 General Feedback

  • The use of IdentityHashMap-backed sets avoids invoking potentially expensive or state-dependent equals/hashCode methods on Throwable instances while accurately detecting reference cycles.
  • Loop termination conditions in WorkCancellingException, WorkItemCancelledException, and WorkFailureProcessor.tryUnwrapException are safe and preserve existing unwrapping semantics.
  • Unit tests in WorkFailureProcessorTest cover both cyclic unwrapping and cyclic cause inspection for the cancellation exceptions.

💡 Tip: Comment /gemini review on this pull request to trigger a new Gemini code review.

@arunpandianp
arunpandianp force-pushed the handle_work_cancellation_exception branch 2 times, most recently from 99df0c2 to 6c2679b Compare November 2, 2026 23:52
When processing a multi-key bundle, if one key fails due to a Windmill work cancellation (WorkCancellingException or WorkItemCancelledException), unaffected sibling keys in the batch must not be misclassified as uncaught user exceptions.

This change adds WorkItemCancelledException.isWorkItemCancelledException(), updates WorkFailureProcessor.evaluateRetry() to return RetryEvaluation.RETRY_LOCALLY without reporting the failure or sleeping, and prevents infinite loops on circular causal chains in both isWorkCancellingException and isWorkItemCancelledException.
@arunpandianp
arunpandianp force-pushed the handle_work_cancellation_exception branch from 6c2679b to 25d1573 Compare November 2, 2026 23:54
@github-actions github-actions Bot added size/m M: 50-249 lines changed and removed size/s S: 10-49 lines changed labels Nov 2, 2026
@arunpandianp

Copy link
Copy Markdown
Contributor Author

R: @scwhittle

@github-actions

github-actions Bot commented Nov 2, 2026

Copy link
Copy Markdown
Contributor

Stopping reviewer notifications for this pull request: review requested by someone other than the bot, ceding control. If you'd like to restart, comment assign set of reviewers

Set<Throwable> seen = Collections.newSetFromMap(new IdentityHashMap<>());
@Nullable Throwable throwable = t;
while (throwable != null) {
while (throwable != null && seen.add(throwable)) {

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.

do we actually have such cycles or is this more theoretical?

Is it worth avoiding the allocation in the case the input throwable doesn't have a cause?

I think there are other such cases where we iterate a throwable chain. Maybe we should have a helper taking the throwable class and doing this iteration, and use it in other cases too.

}

if (WorkCancellingException.isWorkCancellingException(parsedException)
|| WorkItemCancelledException.isWorkItemCancelledException(parsedException)) {

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.

Should we have a helper that checks both? We won't have to iterate the throwable chain twice

Or should we change WorkCancellingException to WorkItemCancelledException after setting failed in the Work.java?

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

Labels

dataflow runners size/m M: 50-249 lines changed

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants