mirror of https://github.com/OpenIdentityPlatform/OpenDJ.git

Valery Kharseko
4 hours ago cdecf531161639f2f9fe98b5a8cc3facd43bb116
refs
author Valery Kharseko <vharseko@3a-systems.ru>
Thursday, October 1, 2026 15:54 +0200
committer GitHub <noreply@github.com>
Thursday, October 1, 2026 15:54 +0200
commitcdecf531161639f2f9fe98b5a8cc3facd43bb116
tree 5edf460d706c7061fad30c6dff4a7945fc90bcd6 tree | zip | gz
parent ee4d71362d092943da3d38bbff5956d785c6b758 view | diff
[#1143] Do not report a Notice of Disconnection that cannot reach an already-closed client as an unhandled error (#1146)

## Problem

The server can drop a connection with a Notice of Disconnection after
the client has already closed its end. For example,
`AuthenticatedUsers.doPostResponse` does this after a DELETE of the
bound user. The notice then cannot be written, and the failure is
reported as an uncaught RxJava error. The server prints an
`OnErrorNotImplementedException ... | java.io.EOFException` stack trace.
According to the code, on a worker thread it also logs
`ERR_UNCAUGHT_THREAD_EXCEPTION` and raises an
`ALERT_TYPE_UNCAUGHT_EXCEPTION` alert. This produces 7 to 11 traces per
run in the `build-docker-alpine` benchmark log. See #1143.

## Cause

`LDAPServerFilter.ClientConnectionImpl.disconnect(ResultCode, String)`
subscribed to the notification with a bare `.subscribe()`. In RxJava
3.1.10, `EmptyCompletableObserver.onError` does not throw. It hands the
error to `RxJavaPlugins.onError`, which prints it and passes it to the
thread's uncaught-exception handler. So the `try/catch
(OnErrorNotImplementedException)` around `s.onError()` in
`sendUnsolicitedNotification()` (added in #555) never saw anything.

## Change

- `disconnect(ResultCode, String)` subscribes with an error consumer
that only traces the failure: a client that is already gone is an
expected outcome. `doAfterTerminate(connection.closeSilently())` is
unchanged, so the connection is closed whether or not the notice was
written.
- The dead `try/catch` and its import are removed.

## Test


`ConnectionFactoryTestCase.testDisconnectWithNotificationToClosedClientIsNotReportedAsUnhandledError`
closes the client and waits until the server context reports
`isClosed()`. It then calls `disconnect(BUSY, "busy")` with a capturing
`RxJavaPlugins` error handler installed, and asserts that nothing
reached it. The write fails before `disconnect()` returns, so the
assertion needs no wait.

- Without the fix (`LDAPServerFilter` from master): fails with
`expecting empty, but was:<[OnErrorNotImplementedException ... |
java.io.EOFException]>`.
- With the fix: passes. The whole `opendj-grizzly` suite (1040 tests) is
green.

Fixes #1143
2 files modified
86 ■■■■■ changed files
opendj-grizzly/src/main/java/org/forgerock/opendj/grizzly/LDAPServerFilter.java 24 ●●●●● diff | view | raw | blame | history
opendj-grizzly/src/test/java/org/forgerock/opendj/grizzly/ConnectionFactoryTestCase.java 62 ●●●●● diff | view | raw | blame | history