Skip to content

Fix race in BatchApiOpImpl CompletionListener.start() causing flaky IllegalThreadStateException (#105) - #106

Merged
vharseko merged 1 commit into
OpenIdentityPlatform:masterfrom
vharseko:fix-batch-completion-listener-race
Jul 20, 2026
Merged

Fix race in BatchApiOpImpl CompletionListener.start() causing flaky IllegalThreadStateException (#105)#106
vharseko merged 1 commit into
OpenIdentityPlatform:masterfrom
vharseko:fix-batch-completion-listener-race

Conversation

@vharseko

Copy link
Copy Markdown
Member

Fixes#105.

Problem

AsyncRemoteSecureConnectorInfoManagerTest.testSerialBatchWithError fails intermittently in CI with IllegalThreadStateException thrown from BatchApiOpImpl$InternalRequest$CompletionListener.start().

CompletionListener.start() guarded Thread.start() with a plain, unsynchronized boolean. The listener is started from two branches of handleOperationResponseMessages — the batch-token branch and the "complete" branch — and operation responses are dispatched on a thread pool, so when the token and complete messages arrive close together, two pool threads can both observe running == false and both call super.start() (check-then-act race). The second Thread.start() throws, the exception propagates out of the message-processing task, and the batch result is lost.

Fix

  • Guard the start with an AtomicBoolean CAS — only the first caller may actually start the thread.
  • Make returnTokenvolatile and publish it fully populated (build in a local, assign last): the CompletionListener thread spins on returnToken == null, and when it lost the start() race there was no happens-before edge, so it could observe a stale null or a partially built token.

Testing

AsyncRemoteSecureConnectorInfoManagerTest (connector-server-grizzly, includes testSerialBatchWithError) run 4 times locally: Tests run: 14, Failures: 0, Errors: 0 each time.

…atform#105)
Two response-dispatch pool threads (batch-token and "complete" branches
of handleOperationResponseMessages) could both observe running == false
and both call Thread.start(), throwing IllegalThreadStateException and
losing the batch result. Guard the start with an AtomicBoolean CAS.
Also make returnToken volatile and publish it fully populated, so the
CompletionListener thread never spins on a stale null or observes a
partially built token when it lost the start() race.
@vharsekovharseko added bug Something isn't working framework OpenICF-java-framework labels Jul 20, 2026
@vharseko
vharseko merged commit b47f778 into OpenIdentityPlatform:masterJul 20, 2026
13 of 14 checks passed
@vharseko
vharseko deleted the fix-batch-completion-listener-race branch July 20, 2026 07:21
Sign up for freeto join this conversation on GitHub. Already have an account? Sign in to comment

Labels

bugSomething isn't workingframeworkOpenICF-java-framework

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Race in BatchApiOpImpl CompletionListener.start() causes flaky IllegalThreadStateException in batch tests

2 participants

@vharseko@maximthomas