-
Type:
Improvement
-
Resolution: Unresolved
-
Priority:
Unknown
-
None
-
Affects Version/s: None
-
Component/s: None
-
None
-
None
-
Java Drivers
-
None
-
None
-
None
-
None
-
None
-
None
The reactive ClientSessionPublisherImpl.close() method is not idempotent. When called multiple times before the first call completes, it can start multiple concurrent abortTransaction() operations.
When the second abort runs after the first one has already closed the session, it attempts to mark a dirty server session that is already closed. This triggers an IllegalStateException (state should be: open) inside the asynchronous callback chain. The exception is propagated back to the ErrorHandlingResultCallback callback and is only logged, leaving the connection from the pool unreturned - resulting in a connection leak.
Root Cause
close() is asynchronous and lacks atomic guarding.
- The first close() call starts an async abortTransaction() and returns immediately.
- Before it completes, a second close() starts another abortTransaction().
- The first abort completes, closing the session and returning its connection.
- The second abort times out or attempts to mark the same server session dirty and throws IllegalStateException. Source code: DefaultServer.java#L240-L242
- The failure is propagated to the ErrorHandlingResultCallback, leaving the connection unreleased.
Making close() idempotent would align it with other driver components (e.g., the synchronous close) and improve reliability in reactive environments where close() may be invoked multiple times unintentionally (e.g., via try-with-resources).