Skip to content

feat: add supervision strategy support for delayWith#3182

Open
He-Pin wants to merge 1 commit into
apache:mainfrom
He-Pin:feat/stream-delay-supervision
Open

feat: add supervision strategy support for delayWith#3182
He-Pin wants to merge 1 commit into
apache:mainfrom
He-Pin:feat/stream-delay-supervision

Conversation

@He-Pin

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

Copy link
Copy Markdown
Member

Motivation

Per the stream error handling docs, operators that apply user-provided functions should consult the configured SupervisionStrategy. The delayWith operator computes each element's delay via a user-provided DelayStrategy.nextDelay, but it was called without a try-catch, so any exception failed the stream unconditionally, even under Supervision.Resume/Restart.

This is part of the meta-issue #3110 (add supervisor strategy support to stream operators that accept user functions). One operator per PR.

Modification

  • Wrap delayStrategy.nextDelay(element) in Delay.grabAndPull() with a try/catch (NonFatal) that consults the SupervisionStrategy decider:
    • Stop → fail the stage (unchanged fail-fast behavior)
    • Resume → drop the offending element, keep already-buffered elements and the current strategy
    • Restart → recreate the (potentially stateful) delay strategy from the supplier; already-buffered elements keep their computed delays
  • delayStrategy became a var so Restart can recreate it.
  • Buffer-underflow guard: because a dropped element no longer enqueues, onPush and onTimer now guard their buffer access with a non-empty check. In particular, onTimer could previously hit a NullPointerException (the delay buffer is an unchecked fixed-size buffer) when an overflow handler emptied the buffer while a timer was still armed and a nextDelay exception was then skipped. A dedicated regression test reproduces this (it fails without the guard).
  • decider is a lazy val → zero overhead on the happy path.
  • Document supervision adherence on delayWith in the Scala/Java DSL scaladoc and the operator reference page (plain delay is unaffected — it uses a fixed internal strategy that never throws).

Result

delayWith now adheres to the SupervisionStrategy attribute with well-defined Resume/Restart semantics and no buffer underflow on the supervised paths.

Tests

  • sbt "stream-tests/Test/testOnly org.apache.pekko.stream.scaladsl.FlowDelaySpec"26/26 passed, including 6 new tests: Stop, default Stop, Resume (drops element), Restart (recreates the stateful strategy — verified via an instance counter), Resume (keeps the stateful strategy — inverted mirror), and an overflow-handler + throw regression that guards the onTimer underflow fix.
  • sbt "stream/mimaReportBinaryIssues" — clean (binary compatible)

References

Refs #3110

This is a clean-room implementation written directly for Apache Pekko.

Motivation:
The delayWith operator computes each element's delay via a user-provided
DelayStrategy.nextDelay, but it was called without a try-catch. Any exception
failed the stream unconditionally, ignoring the configured SupervisionStrategy.

Modification:
Wrap delayStrategy.nextDelay(element) in Delay.grabAndPull() with a try-catch
that consults the SupervisionStrategy decider. Stop fails the stage, Resume
drops the offending element while keeping buffered elements and the strategy,
and Restart recreates the (potentially stateful) delay strategy from the
supplier. The delayStrategy field became a var to allow recreation. Because a
dropped element no longer enqueues, onPush and onTimer now guard their buffer
access with a non-empty check so a skip cannot dequeue/peek an empty buffer
(onTimer previously could NPE when an overflow handler emptied the buffer while
a timer was still armed). The decider is a lazy val for zero overhead on the
happy path. Update the delayWith Scala/Java DSL scaladoc and the operator
reference page.

Result:
delayWith now adheres to the SupervisionStrategy attribute with well-defined
Resume and Restart semantics, with no buffer-underflow on the supervised paths.

Tests:
- sbt "stream-tests/Test/testOnly org.apache.pekko.stream.scaladsl.FlowDelaySpec" -- 26/26 passed

References:
Refs apache#3110
@He-Pin He-Pin marked this pull request as ready for review June 26, 2026 20:34
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant