Class SessionRegistry
java.lang.Object
ai.singlr.runtime.SessionRegistry
In-memory registry of live sessions. The HTTP service holds one per process; route handlers
lookup sessions by id to dispatch send / interrupt / events / close.
Sessions are created via create(SessionOptions) — a Function factory wired at
construction (typically AgentSession::create) builds the impl. The factory is injectable
so tests can substitute a stub session.
Sessions remain in the registry until close(String) is called, even after they reach
a terminal ResultMessage — keeping them around lets late
SSE subscribers fetch the final LoopEnded event after termination, and lets the
DELETE /sessions/{id} route be the explicit cleanup boundary.
Retention
The registry can keep terminal sessions indefinitely; for long-running services that creates a slow leak. Two opt-in eviction surfaces address this:purgeTerminalOlderThan(Duration)— sweep terminal sessions older than the supplied age. Live sessions are never touched. Best called periodically (every minute or so) from the deployer's scheduler.SessionRegistry.newBuilder().withMaxSessions(int)— cap on registered sessions. Whencreate(SessionOptions)would push the count over the cap, the registry evicts the oldest terminal session first; if none is available, the create call throwsIllegalStateException. Live sessions are never evicted.
Thread-safety
Thread-safe. All routes share one registry; concurrent create / get / close are common. Backed byConcurrentHashMap; create(SessionOptions) rejects duplicate ids. The cap check
is best-effort under contention — under a flood of concurrent creates the count may briefly
exceed the cap before evictions catch up; the cap is an SLA hint, not a hard barrier.-
Nested Class Summary
Nested Classes -
Method Summary
Modifier and TypeMethodDescriptionbooleanClose and unregister the session.voidcloseAll()Close and unregister every session.ai.singlr.session.AgentSessioncreate(ai.singlr.session.SessionOptions options) Create a new session from the given options and register it under its session id.Optional<ai.singlr.session.AgentSession> Look up a registered session by id.static SessionRegistryinMemory()Registry that constructs sessions viaAgentSession.create(SessionOptions)with system clock and no cap.static SessionRegistry.BuilderStart building a registry.intSweep every terminal session whose termination instant is older thanagerelative to the registry'sClock.Snapshot of currently-registered session ids.intsize()Number of registered sessions.static SessionRegistrywithFactory(Function<ai.singlr.session.SessionOptions, ai.singlr.session.AgentSession> factory) Registry that constructs sessions via a custom factory, system clock, no cap.
-
Method Details
-
inMemory
Registry that constructs sessions viaAgentSession.create(SessionOptions)with system clock and no cap.- Returns:
- a fresh registry
-
withFactory
public static SessionRegistry withFactory(Function<ai.singlr.session.SessionOptions, ai.singlr.session.AgentSession> factory) Registry that constructs sessions via a custom factory, system clock, no cap. Intended for tests; production sessions useinMemory()ornewBuilder().- Parameters:
factory- non-null function mapping options to a fresh session- Returns:
- a fresh registry
- Throws:
NullPointerException- iffactoryis null
-
newBuilder
Start building a registry. Set any of factory / clock / maxSessions; defaults areAgentSession::create,Clock.systemUTC(), and no cap.- Returns:
- a fresh builder
-
create
Create a new session from the given options and register it under its session id.- Parameters:
options- the composition record; non-null- Returns:
- the freshly-created, unstarted session
- Throws:
NullPointerException- ifoptionsis nullIllegalStateException- if a session with the same id is already registered, or if the registry is at its configuredmaxSessionscap and no terminal session is available to evict
-
get
Look up a registered session by id.- Parameters:
sessionId- non-null id- Returns:
- the session if present
- Throws:
NullPointerException- ifsessionIdis null
-
close
Close and unregister the session. If no session is registered undersessionIdthis is a no-op.- Parameters:
sessionId- non-null id- Returns:
trueif a session was found and closed;falseif no session was registered- Throws:
NullPointerException- ifsessionIdis null
-
sessionIds
Snapshot of currently-registered session ids. Stable point-in-time view; mutations after this call are not reflected.- Returns:
- defensive snapshot
-
size
-
closeAll
Close and unregister every session. Idempotent. -
purgeTerminalOlderThan
Sweep every terminal session whose termination instant is older thanagerelative to the registry'sClock. Live sessions are not touched, even if the registry has held them far longer thanage. Returns the count of sessions closed + unregistered.A session is "terminal" once its
AgentSession.result()future has completed — the registry captures the wall-clock instant of completion when the future settles, and this method compares that instant againstnow - age.- Parameters:
age- non-null, non-negative; sessions terminated at-or-beforenow - ageare purged- Returns:
- number of sessions purged
- Throws:
NullPointerException- ifageis nullIllegalArgumentException- ifageis negative
-