symfonic.services.conversation.session¶
session ¶
The session service: identity issuance, activity, and tenant partitioning.
Policy lives here; storage lives behind :class:SessionStorePort. The legacy
manager fused the two, which is why "sessions are in-memory only" was a
property of the policy rather than a property of a store an adopter could
replace.
Three legacy behaviors are contracts, not implementation details, and are preserved exactly: tenant-partitioned storage, LRU eviction of the oldest decile at the cap, and refusal of a cross-tenant session-id collision by issuing a fresh id rather than by joining the other tenant's session.
InMemorySessionStore ¶
The default store: partitioned by tenant, with a reverse owner index.
The reverse index is what makes a cross-tenant collision detectable without scanning every tenant — the legacy manager needed the same thing and it is the reason the storage layout is two maps rather than one.
Source code in src/symfonic/services/conversation/session.py
SessionService ¶
SessionService(*, store: SessionStorePort | None = None, clock: object | None = None, max_per_tenant: int = MAX_SESSIONS_PER_TENANT)
Creates, finds, and ages session rows for one deployment.
Source code in src/symfonic/services/conversation/session.py
ensure ¶
Return the caller's session, or issue one.
A session id already owned by a different tenant is never joined: the asking tenant gets a fresh id and the owner's row is untouched. Guessing another tenant's id must not be a way into their session.
Source code in src/symfonic/services/conversation/session.py
list ¶
Newest activity first, matching the legacy listing order.
Source code in src/symfonic/services/conversation/session.py
touch ¶
Advance activity and count a message. A foreign id is a no-op.