Skip to content

fix: add supervision strategy support for aggregateWithBoundary callbacks#3187

Open
He-Pin wants to merge 2 commits into
apache:mainfrom
He-Pin:feat/stream-aggregateboundary-supervision
Open

fix: add supervision strategy support for aggregateWithBoundary callbacks#3187
He-Pin wants to merge 2 commits into
apache:mainfrom
He-Pin:feat/stream-aggregateboundary-supervision

Conversation

@He-Pin

@He-Pin He-Pin commented Jun 25, 2026

Copy link
Copy Markdown
Member

Motivation

Issue #3110 tracks stream operators that should honor SupervisionStrategy for user callbacks.

aggregateWithBoundary executes several user callbacks (allocate, aggregate, harvest, timer predicate), but callback exceptions were not supervised and failed the stream unconditionally.

Modification

  • Added supervision handling in AggregateWithBoundary for all callback sites:
    • allocate / aggregate in onPush
    • timer predicate and harvest in onTimer
    • harvest in onUpstreamFinish
  • Supervision behavior:
    • Stop → fail stage
    • Resume / Restart → drop failing element or aggregate and continue
  • For aggregate callback failures under Resume, reset aggregate state to avoid retaining partially-mutated mutable state.
  • Updated Scala/Java API docs and operator docs (aggregateWithBoundary.md) to describe supervision behavior.
  • Added directional tests in AggregateWithBoundarySpec (including simulated-timer coverage) for:
    • aggregate failures (Resume / Restart)
    • allocate failure (Resume)
    • harvest failure (Resume)
    • timer predicate failure (Resume)

Result

aggregateWithBoundary now honors ActorAttributes.SupervisionStrategy across all user callback failure points with regression coverage for push/timer/finish paths.

which is now Apache licensed

Tests

  • sbt "stream-tests/Test/testOnly org.apache.pekko.stream.scaladsl.AggregateWithBoundarySpec org.apache.pekko.stream.scaladsl.AggregateWithTimeBoundaryAndSimulatedTimeSpec" (11/11 passed)
  • sbt "stream/mimaReportBinaryIssues" (clean)
  • sbt "docs/paradox" (passed)

References

Refs #3110

…acks

Motivation:
aggregateWithBoundary invokes multiple user callbacks (`allocate`, `aggregate`,
`harvest`, and timer predicate), but exceptions were not supervised and failed
the stream unconditionally.

Modification:
Add decider-based exception handling in AggregateWithBoundary for all callback
sites:
- allocate/aggregate in onPush
- timer predicate and harvest in onTimer
- harvest in onUpstreamFinish

Stop fails the stage. Resume/Restart drop failing element/aggregate and continue.
For aggregate callback failures, Resume now resets aggregate state to avoid
retaining partially-mutated mutable state.

Update Scala/Java API docs and operator docs to document supervision behavior.

Add directional regression tests in AggregateWithBoundarySpec covering:
- aggregate callback failures under Resume/Restart
- allocate callback failure under Resume
- harvest callback failure under Resume
- timer predicate failure under Resume (explicit scheduler)

Result:
aggregateWithBoundary now honors ActorAttributes.SupervisionStrategy across all
user callback failure points with deterministic regression coverage.

Tests:
- sbt "stream-tests/Test/testOnly org.apache.pekko.stream.scaladsl.AggregateWithBoundarySpec org.apache.pekko.stream.scaladsl.AggregateWithTimeBoundaryAndSimulatedTimeSpec" -- 11/11 passed
- sbt "stream/mimaReportBinaryIssues" -- clean
- sbt "docs/paradox" -- passed

References:
Refs apache#3110
@He-Pin He-Pin marked this pull request as ready for review June 26, 2026 18:07
…ision test

Motivation:
The supervision handling introduced two near-identical harvest methods
(harvestAndEmitFromOnPush / harvestAndEmitOnTimer) differing only in whether
pullIfPossible is called after recovery, and the onUpstreamFinish harvest
recovery path lacked directional test coverage.

Modification:
- Unify the two harvest methods into a single harvestAndEmit(pullOnRecover)
  that conditionally pulls on recovery; onPush passes true, onTimer passes
  false to preserve the original timer semantics of not managing pull state.
- Add a directional test for harvest failure on upstream completion (Resume):
  the failing final aggregate is dropped and the stream completes normally.

Result:
Less duplication in the supervision recovery code and regression coverage
for the previously untested onUpstreamFinish harvest path.

Tests:
- sbt "stream-tests/Test/testOnly org.apache.pekko.stream.scaladsl.AggregateWithBoundarySpec org.apache.pekko.stream.scaladsl.AggregateWithTimeBoundaryAndSimulatedTimeSpec" -- 12/12 passed
- sbt "stream/mimaReportBinaryIssues" -- clean
- scalafmt --test --mode diff-ref=origin/main -- all formatted

References:
Refs apache#3110
@He-Pin He-Pin requested a review from pjfanning June 26, 2026 18:13
@He-Pin He-Pin added the t:stream Pekko Streams label Jun 26, 2026
@He-Pin He-Pin requested a review from Copilot June 26, 2026 18:25

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.

Pull request overview

This PR updates the aggregateWithBoundary stream operator so that exceptions thrown by user callbacks (allocate, aggregate, harvest, and optional timer predicate) are handled according to the configured ActorAttributes.SupervisionStrategy, rather than unconditionally failing the stream.

Changes:

  • Added supervision-aware exception handling to all user callback invocation sites in AggregateWithBoundary (push, timer, and upstream-finish paths).
  • Updated Scala/Java API scaladoc and operator documentation to explicitly describe the supervision semantics.
  • Added regression tests covering Resume / Restart behavior across callback failure points, including a simulated-timer scenario.

Reviewed changes

Copilot reviewed 8 out of 8 changed files in this pull request and generated no comments.

Show a summary per file
File Description
stream/src/main/scala/org/apache/pekko/stream/scaladsl/Flow.scala Documents supervision support and semantics for the Scala DSL aggregateWithBoundary operator.
stream/src/main/scala/org/apache/pekko/stream/javadsl/SubSource.scala Documents supervision support and semantics for the Java DSL SubSource API surface.
stream/src/main/scala/org/apache/pekko/stream/javadsl/SubFlow.scala Documents supervision support and semantics for the Java DSL SubFlow API surface.
stream/src/main/scala/org/apache/pekko/stream/javadsl/Source.scala Documents supervision support and semantics for the Java DSL Source API surface.
stream/src/main/scala/org/apache/pekko/stream/javadsl/Flow.scala Documents supervision support and semantics for the Java DSL Flow API surface.
stream/src/main/scala/org/apache/pekko/stream/impl/fusing/AggregateWithBoundary.scala Implements supervision strategy handling for all callback sites (allocate/aggregate/harvest/timer predicate).
stream-tests/src/test/scala/org/apache/pekko/stream/scaladsl/AggregateWithBoundarySpec.scala Adds directional tests for supervised callback failures, including simulated-time timer coverage.
docs/src/main/paradox/stream/operators/Source-or-Flow/aggregateWithBoundary.md Updates operator docs to state and explain supervision behavior.

💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

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

Labels

t:stream Pekko Streams

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants