Skip to content

Fix session shutdown diagnostics race#1790

Merged
kevinherron merged 1 commit into
mainfrom
codex/server-shutdown-diagnostics-race
Jul 1, 2026
Merged

Fix session shutdown diagnostics race#1790
kevinherron merged 1 commit into
mainfrom
codex/server-shutdown-diagnostics-race

Conversation

@kevinherron

Copy link
Copy Markdown
Contributor

Summary

Make server shutdown the synchronization point for session listener quiescence so diagnostics and namespace teardown no longer race with session callbacks.

  • Stop accepting new sessions as soon as shutdown begins so new CreateSession work cannot enqueue diagnostics callbacks during teardown.
  • Drain in-flight session listener callbacks before namespace and diagnostics shutdown, while still avoiding self-deadlock when shutdown is requested from a listener callback.
  • Make session close idempotent so concurrent shutdown, timeout, and close paths notify lifecycle listeners only once.
  • Shut down managed lifecycle children before unregistering their node managers, keeping diagnostics nodes valid during child teardown.
  • Remove sleep-based shutdown ordering from examples and integration test cleanup.

Key Changes

  • Server shutdown ownership: OpcUaServer.shutdown() now uses a shared shutdown future so concurrent callers observe the same teardown instead of running namespace and diagnostics shutdown multiple times.
  • Session listener quiescence: SessionManager tracks shutdown state, rejects new sessions with Bad_Shutdown, drains listener work, and skips queued callbacks once shutdown starts.
  • Re-entrant shutdown handling: Session listener dispatch marks callback threads so shutdown requested from inside a listener does not wait on itself, while external callers still wait for the active shutdown to finish.
  • Lifecycle ordering: Managed namespace/address-space lifecycle managers now shut down in inverse registration order so child diagnostics and subscription lifecycles run before node managers are unregistered.
  • Test cleanup: Sleep-based waits were removed because server.shutdown() now provides the ordering guarantee.

Testing

  • SessionTest covers idempotent Session.close(...) behavior and verifies lifecycle listeners are notified once.
  • ServerShutdownSessionDiagnosticsRaceTest covers blocked session listener shutdown, concurrent shutdown callers, and shutdown requested from inside a session listener callback.
  • mvn -q spotless:apply
  • mvn -q -pl opc-ua-sdk/sdk-server -am test -Dtest=SessionTest -Dsurefire.failIfNoSpecifiedTests=false
  • mvn -q -pl opc-ua-sdk/integration-tests -am test -Dtest=ServerShutdownSessionDiagnosticsRaceTest -Dsurefire.failIfNoSpecifiedTests=false
  • mvn -q clean compile

Make server shutdown the synchronization point for session listener callbacks so diagnostics and namespace lifecycles are not torn down while session notifications are still running.

Reject new sessions once shutdown begins, make session close idempotent, and shut down managed lifecycle children before unregistering their node managers. This removes sleep-based ordering from tests and examples and covers concurrent and re-entrant shutdown paths.
@kevinherron kevinherron added this to the 1.1.5 milestone Jul 1, 2026
@kevinherron kevinherron merged commit 208f971 into main Jul 1, 2026
6 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant