Skip to content

fix: avoid StackOverflowError in PersistBarrier.awaitPersisted for large steps#1336

Open
zhangxiangnan wants to merge 1 commit into
google:mainfrom
zhangxiangnan:fix/persist-barrier-stackoverflow
Open

fix: avoid StackOverflowError in PersistBarrier.awaitPersisted for large steps#1336
zhangxiangnan wants to merge 1 commit into
google:mainfrom
zhangxiangnan:fix/persist-barrier-stackoverflow

Conversation

@zhangxiangnan

Copy link
Copy Markdown

Problem

PersistBarrier.awaitPersisted folds a step's per-event barriers into a left-nested Completable.andThen(...) chain:

Completable result = Completable.complete();
for (Event event : events) {
  String eventId = event.id();
  if (eventId != null) {
    result = result.andThen(barrier(context, eventId));
  }
}
return result;

A single step can carry a large number of events — e.g. an agent transfer folds the sub-agent's events into the parent step. The nested andThen chain recurses once per element on both subscription and completion, so long sessions throw StackOverflowError:

java.lang.StackOverflowError
    at io.reactivex.rxjava3.internal.operators.completable.CompletableAndThenCompletable.subscribeActual(...)
    at io.reactivex.rxjava3.core.Completable.subscribe(...)
    ...

Fix

Await the per-event barriers with Completable.concat(Iterable) instead. concat drains its sources iteratively, so it stays stack-safe, while keeping the same await semantics (order is irrelevant — each CompletableSubject retains its terminal state).

Testing

Added a regression test largeStep_awaitsAllWithoutStackOverflow that awaits 50,000 events in a single step; it fails with StackOverflowError on the old implementation and passes with the fix.

mvn -pl core test -Dtest=PersistBarrierTestTests run: 10, Failures: 0, Errors: 0, Skipped: 0.

Made with Cursor

@google-cla

google-cla Bot commented Jul 8, 2026

Copy link
Copy Markdown

Thanks for your pull request! It looks like this may be your first contribution to a Google open source project. Before we can look at your pull request, you'll need to sign a Contributor License Agreement (CLA).

View this failed invocation of the CLA check for more information.

For the most up to date status, view the checks section at the bottom of the pull request.

…rge steps

awaitPersisted folded a step's per-event barriers into a left-nested
Completable.andThen(...) chain. A single step can carry many events (an agent
transfer folds the sub-agent's events into the parent step), and the nested
chain recurses once per element on both subscription and completion, throwing
StackOverflowError for long sessions.

Await the barriers with Completable.concat instead, which drains its sources
iteratively and stays stack-safe while preserving the same await semantics
(order is irrelevant, as each subject retains its terminal state).

Adds a regression test that awaits 50k events in a single step.
@zhangxiangnan zhangxiangnan force-pushed the fix/persist-barrier-stackoverflow branch from 9afba60 to b475909 Compare July 8, 2026 10:04
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