ProtectedconstructorReadonlyShutdownIdentifier surfaced in graceful-shutdown logs.
StaticInstanceProcess-wide singleton accessor (Global Object Store backed via BaseSingleton).
Overrides default tuning. Safe to call before or after Start. Every value given must be a
finite number greater than zero: a NaN or non-positive duration would otherwise build an invalid
cutoff date and make every later sweep throw. All-or-nothing: on an invalid value it throws, naming
the field and value, and applies nothing. undefined values are ignored.
The Global Object Store is a place to store global objects that need to be shared across the application. Depending on the execution environment, this could be the window object in a browser, or the global object in a node environment, or something else in other contexts. The key here is that in some cases static variables are not truly shared because it is possible that a given class might have copies of its code in multiple paths in a deployed application. This approach ensures that no matter how many code copies might exist, there is only one instance of the object in question by using the Global Object Store.
Server-authoritative MAX-DURATION enforcement (public web-widget voice cap, public-web-widget.md
W4). Closes any Active/Idle session whose stored absolute deadline (Config_.maxSessionDeadlineIso)
has passed — a hard wall-clock ceiling that fires regardless of activity, so a public voice guest
cannot run a session indefinitely (cost-bombing) even if the client ignores its own abuse guard.
Only sessions that CARRY a deadline are loaded (a cheap Config_ LIKE pre-filter), then the exact
ISO deadline is parsed and compared in JS (Config_ is JSON, not a queryable column). Stamped
CloseReason = 'Janitor', idempotent + concurrency-safe like the other sweeps. Returns the count closed.
Backstop for client-direct recordings on the shard ledger: assembles the recording of Closed
sessions that closed between the lookback window and the grace period and are still
Pending (shards, or a terminal signal, with no assembly since: the browser died before its
terminal request, or the in-process assembly request was lost with its host),Assembling with no write for recordingRecoveryAttemptTimeoutMinutes (the assembler died, or
it hit a transient error and left the claim for a re-claim), orEach candidate is claimed with the ledger's atomic, stale-aware claim (a lost claim is skipped: another
assembler has it) and assembled with ForcePartial, so missing shards become silence. An attempt is
bounded by recordingRecoveryAttemptTimeoutMinutes and shares the legacy sweep's abandoned-attempt
pause; failures back off and are given up on exactly like legacy recovery, in their own tracker.
At most MAX_RECOVERIES_PER_SWEEP assemblies per call. Never throws for a single bad session.
Returns the number of recordings assembled (Complete or Partial).
Rebuilds the recording of sessions whose end-of-call upload never arrived (browser died, tab
closed). A session is a candidate when it is Closed, has RecordingStartedAt (consent is implied:
recording only starts after the guest agreed), still has no RecordingFileID, and closed between
the lookback window and the grace period (see SessionJanitorConfig.recordingRecoveryGraceMinutes).
Work is bounded: candidates are handled sequentially, at most MAX_RECOVERIES_PER_SWEEP
recovery attempts per call, and a failing session backs off exponentially (min(2^k * 5 min, 6 h))
and is abandoned after MAX_RECOVERY_ATTEMPTS failures with one LogError. Backoff entries of
sessions that left the candidate set are pruned, but only after a pass that saw every candidate, so
a capped pass never forgets sessions it did not reach.
Sessions on the shard ledger (a RecordingStatus, or any ledger row) are left to
RunRecordingLedgerSweep: their audio is in SQL, not in storage segments.
Never throws for a single bad session. Returns the number of recordings recovered.
Close every Active/Idle session owned by this exact host instance (current boot),
stamping CloseReason = 'Shutdown'. Invoked from Shutdown during the graceful
shutdown drain; exposed publicly for tests and for hosts that want to drain explicitly.
Returns the number of sessions closed.
Force-close any Active/Idle session whose LastActiveAt is older than the configured
close threshold, regardless of host. Idempotent and concurrency-safe. Returns the count closed.
Force-close any Active/Idle session left behind by an earlier boot of this MJAPI instance: its
HostInstanceID has this instance's prefix (hostname:port:) and another boot. The sessions of another
MJAPI on the same host carry another port and stay open. Returns the number of sessions closed.
The metadata provider for the reads and writes.
The user the closes run as.
The instance whose earlier boots to close. Defaults to this process's (GetCurrentHostInstance).
IShutdownable: stop the timer, then drain this host's own live sessions so a
graceful stop never strands Active/Idle rows for the next boot's janitor to mop up, then wait
(at most RECOVERY_SHUTDOWN_WAIT_MS) for an in-flight recording recovery pass.
Drained sessions are stamped CloseReason = 'Shutdown' (vs. 'Janitor' for crash orphans),
so the dashboards can tell a clean redeploy from a reconciled crash. Never throws; the drain
is skipped when Start was never called (no captured provider/user).
Run own-host startup recovery once, then schedule the periodic tick (staleness and max-duration
close sweeps, then recording recovery). Idempotent: a second call does not stack a second timer.
Captures the provider + system user so the timer callback can run without re-supplying them, and
re-enables recording recovery after a Stop. Throws, before doing any work, when
intervalMs is invalid (see Configure). Takes the server's database provider because
recording recovery calls the shard ledger's stored procedures.
OptionalintervalMs: numberStops the periodic tick and keeps any new recording recovery pass from starting until the next Start, including one a tick already in progress would have started. A pass that is already running is not interrupted (Shutdown waits for it). Idempotent. Part of IShutdownable.
Protected StaticgetReturns the singleton instance of the class. If the instance does not exist, it is created and stored in the Global Object Store. If className is provided it will be used as part of the key in the Global Object Store, otherwise the actual class name will be used. NOTE: the class name used by default is the lowest level of the object hierarchy, so if you have a class that extends another class, the lowest level class name will be used.
OptionalclassName: string
BaseSingletonbackground reconciler that keeps the durableAIAgentSessionstate from drifting away from volatile process reality. A crash/redeploy vaporizes a host's in-memory sockets but leaves its session rows readingActive/Idleforever; the janitor force-closes those orphans.Three close sweeps, all writing through SessionManager.CloseSession so Record Changes captures each transition and channel rows are disconnected consistently:
Active/Idlesession whoseHostInstanceIDbelongs to an earlier boot of this MJAPI instance (same host and port, different boot; see HostInstanceIdentity). Another MJAPI on the same host serves on another port, so its live sessions are left alone. Primary defense against the "Active forever" leak after a restart.Active/Idlesession whoseLastActiveAtis older thancloseThresholdMinutes, regardless of host. Catches sessions whose owner died without a clean reboot (OOM, scaled-down pod).The close sweeps stamp
CloseReason = 'Janitor'. A shutdown-time path — RunShutdownDrain, invoked from Shutdown during the graceful ShutdownRegistry drain — closes this exact host instance's own live sessions withCloseReason = 'Shutdown'.Separately from closing, a recording recovery pass runs after the close sweeps on every periodic tick, without blocking them, and closes nothing. It purges shard-ledger rows past the lookback window, then RunRecordingLedgerSweep assembles the recordings of
Closedsessions on the shard ledger that no terminal signal (or a dead assembler) left unassembled, then RunRecordingRecoverySweep rebuilds, from legacy storage segments, the recording ofClosedsessions not on the ledger whose end-of-call upload never arrived.The close sweeps are idempotent and safe to run concurrently on every instance: closing an already-
Closedsession is a no-op, and the close path is last-writer-wins. Ledger assembly is arbitrated by the ledger's atomic claim. Legacy recovery is not: two instances can recover the same session at once (there is no claim column for it). Each attempt uploads its own file and defers to an already-stamped recording on a best-effort basis, so the cost is duplicate work and an extra file, not a lost recording. The extra file is an orphan when the second attempt's re-check sees the first stamp; when both re-checks pass first, both files are stamped in turn and both are linked to the session (the later stamp winsRecordingFileID). Every sweep pages with keyset (AfterKey) pagination per the deep-pagination guide so a large backlog can't blow up memory.