Skip to content

Improve reactive streams compliance in InputStreamPublisher#5160

Merged
adamw merged 1 commit intomasterfrom
fix/inputstream-publisher-reactive-streams-compliance
Apr 3, 2026
Merged

Improve reactive streams compliance in InputStreamPublisher#5160
adamw merged 1 commit intomasterfrom
fix/inputstream-publisher-reactive-streams-compliance

Conversation

@adamw
Copy link
Copy Markdown
Member

@adamw adamw commented Apr 3, 2026

Summary

  • Cancel subscription after onError for invalid request(n <= 0) per reactive streams §3.9, preventing further reads/leaks
  • Use saturating addition for demand accumulation to prevent Long overflow when request() is called multiple times with large values

Note: the same fixes are applied to InputStreamSyncPublisher in #5159.

Test plan

  • Existing tests pass
  • Verified compilation

🤖 Generated with Claude Code

- Cancel subscription after onError for invalid request(n <= 0) per §3.9
- Use saturating addition for demand to prevent Long overflow

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Copilot AI review requested due to automatic review settings April 3, 2026 13:23
Copy link
Copy Markdown

Copilot AI left a comment

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 improves InputStreamPublisher reactive-streams compliance by terminating subscriptions on invalid demand requests and preventing Long overflow when accumulating demand.

Changes:

  • Cancel subscription and signal onError when request(n <= 0) is called (reactive streams §3.9).
  • Accumulate demand using saturating addition capped at Long.MaxValue to avoid overflow.

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

Comment on lines +37 to +40
if (n <= 0) {
cancel()
subscriber.onError(new IllegalArgumentException("§3.9: n must be greater than 0"))
} else {
Copy link

Copilot AI Apr 3, 2026

Choose a reason for hiding this comment

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

Calling cancel() when request(n <= 0) now forces evaluation of the lazy stream (because cancel closes it), which can unnecessarily open the underlying InputStream and potentially perform range skipping even though no data will be read. Consider avoiding stream initialization on this error path (e.g., track the opened stream in an AtomicReference/var and only close if it was already created), while still marking the subscription as terminated so no further reads happen.

Copilot uses AI. Check for mistakes.
Comment on lines 36 to +49
override def request(n: Long): Unit = {
if (n <= 0) subscriber.onError(new IllegalArgumentException("§3.9: n must be greater than 0"))
else {
demand.addAndGet(n)
if (n <= 0) {
cancel()
subscriber.onError(new IllegalArgumentException("§3.9: n must be greater than 0"))
} else {
addDemand(n)
readNextChunkIfNeeded()
}
}

/** Add demand using saturating addition, capping at Long.MaxValue to prevent overflow. */
private def addDemand(n: Long): Unit = {
demand.getAndUpdate(current => if (current > Long.MaxValue - n) Long.MaxValue else current + n)
()
Copy link

Copilot AI Apr 3, 2026

Choose a reason for hiding this comment

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

The new behaviors (saturating demand accumulation and cancelling/terminating on invalid request(n <= 0)) aren't covered by tests. Adding a focused unit test for InputStreamPublisher (e.g., verifying demand never overflows past Long.MaxValue, and that invalid request triggers onError and prevents any subsequent onNext/onComplete) would help prevent regressions and confirm reactive-streams compliance.

Copilot uses AI. Check for mistakes.
@adamw adamw merged commit 4ad51cb into master Apr 3, 2026
26 checks passed
@adamw adamw deleted the fix/inputstream-publisher-reactive-streams-compliance branch April 3, 2026 13:54
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.

2 participants