Session Store Options¶
SessionStoreOptions controls resumable-session retention and the automatic
persistence policy used when connections leave ConnectionHub.
Source Mapping¶
src/Nalix.Network/Options/SessionStoreOptions.cssrc/Nalix.Network/Sessions/SessionStoreBase.cssrc/Nalix.Network/Sessions/InMemorySessionStore.cssrc/Nalix.Network/Connections/Connection.Hub.cssrc/Nalix.Hosting/Bootstrap.cs
Defaults and Validation¶
| Property | Default | Validation | Runtime consumer |
|---|---|---|---|
SessionTtl |
00:30:00 |
Required and > TimeSpan.Zero |
SessionStoreBase.CreateSession(...) sets ExpiresAtUnixMilliseconds. |
AutoSaveOnUnregister |
true |
None | ConnectionHub.TryUnregisterCore(...) gates automatic persistence. |
MinAttributesForPersistence |
4 |
0..int.MaxValue |
SessionStoreBase.StoreAsync(IConnection) skips low-value sessions. |
Validate() uses manual range checks and throws ArgumentOutOfRangeException when constraints are violated. It rejects non-positive SessionTtl values and negative MinAttributesForPersistence.
Hosting Initialization¶
Bootstrap.Initialize() materializes this option set during server startup:
This ensures the active configuration file contains the resumable-session retention and persistence policy alongside the other network-level options.
Session Creation Flow¶
flowchart TD
A["ConnectionHub unregisters connection"] --> B{"AutoSaveOnUnregister?"}
B -->|No| Z["Skip session persistence"]
B -->|Yes| C["TryUnregisterCore(...) starts background StoreAsync(connection)"]
C --> D{"HandshakeEstablished attribute == true?"}
D -->|No| Z
D -->|Yes| E{"Attributes.Count > MinAttributesForPersistence?"}
E -->|No| Z
E -->|Yes| F["CreateSession copies connection attributes"]
F --> G["ExpiresAt = now + SessionTtl"]
G --> H["StoreAsync(session)"]
SessionStoreBase.CreateSession(...) snapshots the connection into a SessionEntry:
SessionTokenis derived fromconnection.ID.Toulong().CreatedAtUnixMillisecondsusesClock.UnixMillisecondsNow().ExpiresAtUnixMillisecondsisnow + SessionTtl.TotalMilliseconds.Secret,Algorithm, andLevelare copied from the connection.- Connection attributes are copied into a rented
ObjectMap<string, object>.
Automatic Persistence Contract¶
ConnectionHub.TryUnregisterCore(...) attempts persistence before disposing the
removed connection. Persistence is intentionally guarded:
- automatic persistence must be enabled;
- the hub and connection must still be active;
ConnectionAttributes.HandshakeEstablishedmust exist and betrue;connection.Attributes.Countmust be greater thanMinAttributesForPersistence.
The attribute threshold is an anti-abuse filter. It avoids retaining handshake-only or nearly empty sessions that could otherwise be created in bulk by short-lived connections.
If StoreAsync(...) completes synchronously and successfully, the session is owned
by the store. If storing throws immediately, the newly created SessionEntry is
returned. If storing completes asynchronously, PersistSessionAsync(...) awaits it
without blocking unregistration and returns the session only if persistence fails.
In-Memory Store Behavior¶
InMemorySessionStore is the default store used by ConnectionHub when no custom
ISessionStore is injected.
Storage and Replacement¶
StoreAsync(...) uses a ConcurrentDictionary<ulong, SessionEntry> keyed by the
session token:
- first insert wins when the token is absent;
- storing the same
SessionEntryreference again is a no-op; - replacing an existing token uses
TryUpdate(...)and returns the old entry.
Expiration¶
Expiration is enforced in two places:
- a background scavenger runs every minute and removes expired entries;
RetrieveAsync(...)andConsumeAsync(...)also perform lazy TTL checks.
Expired entries are removed from the dictionary and returned to their backing pools
through SessionEntry.Return().
Consume Semantics¶
ConsumeAsync(...) uses ConcurrentDictionary.TryRemove(...), so a session token is
atomic one-shot state: only one concurrent caller can successfully consume and resume
it. Expired consumed entries are returned and reported as null.
Disposal¶
InMemorySessionStore.Dispose() cancels the scavenger token, cancels the scheduled
cleanup worker through TaskManager, disposes the worker handle, and suppresses
finalization. Cleanup errors are handled best-effort for non-fatal exceptions.
Memory Management Notes¶
- Session snapshots own a rented
ObjectMap<string, object>containing copied connection attributes. - Store implementations must return replaced, removed, expired, or failed-to-store
SessionEntryinstances. - The default in-memory store returns entries on replacement, removal, lazy expiration, consumption expiration, and background scavenging.
- Automatic persistence avoids blocking connection unregistration on asynchronous stores.
Tuning Guidance¶
- Keep
SessionTtlaligned with authentication token lifetime and key rotation. - Lower
SessionTtlto reduce retained state and replay-token lifetime. - Raise
MinAttributesForPersistencewhen public endpoints see many handshake-only disconnects. - Lower
MinAttributesForPersistenceonly if legitimate resumable sessions carry few attributes. - Disable
AutoSaveOnUnregisterwhen session persistence is handled explicitly or by a custom lifecycle policy. - Use a distributed
ISessionStorefor multi-node deployments and preserve the same TTL and one-shot consume semantics.