Class NotificationSupervisor

java.lang.Object
com.pyranid.NotificationSupervisor

@ThreadSafe public final class NotificationSupervisor extends Object
An explicitly started, single-use supervisor for notification-driven durable reconciliation.

The supervisor registers its channels, reconciles authoritative state, then reconciles once per nonempty notification batch. A selected retry opens a new session and repeats initial reconciliation. Notifications remain lossy hints: enable NotificationSupervisor.Builder.pollEvery(Duration) for independent durable-state polling. Managed reconciliation is serialized and coalesces requests, and must be bounded and repeatable.

start() creates managed workers using named daemon threads by default; customize their creation with NotificationSupervisor.Builder.threadFactory(Function). Call requestShutdown() and await shutdown for orderly cleanup. The advanced start(Executor) mode uses an application-owned asynchronous executor with synchronous reconciliation and does not support polling or managed thread factories. The data source is always caller-owned. A listener needs a session-affine source and holds one connection; ordinary reconciliation queries acquire their own connections. See Database.withNotificationSession(Set, NotificationSessionOperation).

Completion-stage views cannot be used to cancel or complete this supervisor. Use requestShutdown() to stop it. Stage continuations may run on the completing thread: keep them short or use asynchronous continuations. Neither a receive timeout nor an NotificationSupervisor.State.ACTIVE snapshot proves that the physical connection is healthy.

Since:
4.8.0
Author:
Mark Allen
  • Method Details

    • start

      public void start()
      Starts this single-use supervisor using its own listener and reconciliation workers. Factories are resolved and threads validated before any work is allowed to begin. The default workers are named daemon threads; explicit shutdown is still required for orderly resource cleanup.
      Throws:
      IllegalStateException - if already started/stopped or a factory returns an invalid thread
    • withDatabase

      Creates a builder without opening a connection or starting work.
      Parameters:
      listenerDatabase - database whose source preserves listener-session affinity
      Returns:
      a builder
    • start

      public void start(@NonNull Executor executor)
      Submits this supervisor exactly once to an application-owned asynchronous executor.

      Inline execution, including a caller-runs rejection policy, is rejected before any JDBC or reconciliation work. A later queued invocation on the submitting thread is allowed. The executor must eventually run an accepted task; silently discarded tasks cannot be detected. Calling requestShutdown() still terminates a queued task.

      Parameters:
      executor - asynchronous executor with capacity for a long-lived listener
      Throws:
      IllegalStateException - if already started/stopped, or managed-worker options are configured
      RejectedExecutionException - if the executor rejects submission or executes inline
    • requestShutdown

      public void requestShutdown()
      Requests cooperative stop without waiting for listener I/O or cleanup. Repeated requests are harmless.

      A shutdown before worker entry prevents listener JDBC work. A running listener is interrupted. Polling is cancelled, but a decoded nonempty batch still receives one final bounded reconciliation, with an already-observed interrupt temporarily cleared and restored. Managed reconciliation is drained without interrupting user work. If listener interruption is rejected, polling cancellation and shutdown publication still proceed; the interruption failure is retained in the shutdown result while listener cleanup awaits cooperative progress. Arbitrary JDBC I/O cannot be forcibly bounded: wait on awaitShutdownAsync() with an application deadline.

    • firstReady

      Gets a read-only signal for the first successful registration and initial reconciliation.

      Retryable startup failures leave this pending. Terminal failure or stop before readiness completes it exceptionally. Later outages do not undo successful readiness; inspect snapshot() and awaitShutdownAsync() separately. Timing out while waiting does not request stop.

      Returns:
      first-readiness stage
    • awaitShutdownAsync

      Gets a read-only stage that completes normally with the terminal result, including any terminal failure.

      Completion means session cleanup and managed reconciliation have finished, including partial-start cleanup, and no more supervisor JDBC or reconciliation work can occur. It does not mean that a caller's synchronous stage continuation has returned, that a worker's uncaught-exception handler has returned, or that an application-owned executor has terminated.

      Returns:
      terminal-result stage
    • awaitShutdown

      Waits interruptibly for listener cleanup and all managed reconciliation work to finish. Interruption cancels only this wait; it does not request shutdown. Do not call from a supervisor callback.
      Returns:
      the shutdown result, including any terminal failure
      Throws:
      InterruptedException - if this waiting thread is interrupted
      IllegalStateException - if called by a supervisor worker, which cannot wait for itself
    • snapshot

      Gets an immutable snapshot of observed lifecycle state, not a physical-connection health check.
      Returns:
      current lifecycle snapshot