Documentation
¶
Overview ¶
Package sessionsync assembles the session / cross-replica-sync layer behind one Handle: the externalized session store (memory or postgres), the per-session enrichment-dedup cache, the client-facing MCP notification broadcaster, and the dedicated cross-replica reload bus (its own broadcaster channel plus the publish/subscribe machinery).
Construction takes explicit inputs — a *sql.DB, the resolved session / broadcast config values, an optional injected session store, and the reload handlers Platform re-materializes local state through — so the subsystem is constructible and testable without a Platform. It imports pkg/session, pkg/session/postgres, and pkg/middleware, never pkg/platform. The *sql.DB and the config values back many other subsystems, so they stay owned by Platform and are passed in rather than owned here.
Construction is two-phase: New builds the store + both broadcasters + reload bus (owning their cleanup and subscriber goroutines), and StartCache builds the enrichment-dedup cache during middleware assembly (gated by config on the Platform side). The reload re-materialization handlers stay on Platform (they reach into the connection store, toolkit registry, persona registry, and API-key store — state this package does not own) and are injected as callbacks. Close is the shutdown seam Platform wires into its own lifecycle.
Index ¶
- type Config
- type Handle
- func (h *Handle) Broadcaster() session.Broadcaster
- func (h *Handle) Close() error
- func (h *Handle) PublishAPIKeyReload(ctx context.Context)
- func (h *Handle) PublishCatalogReload(ctx context.Context, catalogID string)
- func (h *Handle) PublishConnectionReload(ctx context.Context, kind, name, op string)
- func (h *Handle) PublishPersonaReload(ctx context.Context)
- func (h *Handle) SessionCache() *middleware.SessionEnrichmentCache
- func (h *Handle) SessionStore() session.Store
- func (h *Handle) StartCache(entryTTL, sessionTimeout time.Duration) *middleware.SessionEnrichmentCache
- func (h *Handle) StatelessForced() bool
- type ReloadHandlers
Constants ¶
This section is empty.
Variables ¶
This section is empty.
Functions ¶
This section is empty.
Types ¶
type Config ¶
type Config struct {
// Store selects the session store backend: "database", "memory", or ""
// (memory). Ignored when an injected store is supplied to New.
Store string
// TTL is the resolved session lifetime; CleanupInterval is how often the
// store's cleanup routine runs. Both are already defaulted by the caller.
TTL time.Duration
CleanupInterval time.Duration
// DSN is the database connection string; empty disables the postgres
// broadcasters (memory fan-out only). BroadcastChannel overrides the
// postgres LISTEN/NOTIFY channel; empty uses the package default.
DSN string
BroadcastChannel string
}
Config carries the resolved session / broadcast values the owner needs to assemble the layer. Platform resolves defaults (TTL, cleanup interval) before passing them so this package stays free of the platform's defaulting rules.
type Handle ¶
type Handle struct {
// contains filtered or unexported fields
}
Handle owns the assembled session / cross-replica-sync layer: the session store (and its cleanup goroutine), the enrichment-dedup cache (and its cleanup goroutine, started by StartCache), the client-facing broadcaster, and the dedicated reload broadcaster + bus (and the subscriber goroutine). The read accessors expose the store / broadcaster / cache that Platform surfaces through its SessionStore() / Broadcaster() accessors, the HTTP session resolver, session-handle minting, and the admin session export/restore; the Publish*Reload delegators back the Platform wrappers admin handlers call. Close is the shutdown seam Platform wires into its own lifecycle.
func New ¶
func New(db *sql.DB, cfg Config, injectedStore session.Store, handlers ReloadHandlers) (*Handle, error)
New assembles the session store, both broadcasters, and the reload bus from an explicit *sql.DB, the resolved config, an optional injected store, and the reload handlers. When injectedStore is non-nil it is used verbatim (the admin SessionStore override path) — store selection, the cleanup routine, and stateless forcing are all skipped, but the broadcasters and reload bus are still wired so Broadcaster() is non-nil and cross-replica reload still works.
It returns an error when Config.Store is "database" but db is nil, or when Config.Store is an unknown value; otherwise the returned Handle is non-nil and its Broadcaster is guaranteed non-nil (memory fallback).
func (*Handle) Broadcaster ¶
func (h *Handle) Broadcaster() session.Broadcaster
Broadcaster returns the client-facing MCP notification broadcaster. Non-nil after a successful New (memory fallback guarantees it); nil only on a nil Handle.
func (*Handle) Close ¶
Close tears down the layer in order: stop the enrichment cache, close the session store, close the client broadcaster, then cancel the reload subscriber and close the reload broadcaster. The broadcasters must close before Platform closes its *sql.DB because the postgres broadcasters hold their own dedicated LISTEN connections. Returns the joined store + client-broadcaster close errors; the reload-broadcaster close error is best-effort (the reload channel is a control-plane convenience, not a data path). No-op on a nil Handle.
func (*Handle) PublishAPIKeyReload ¶
PublishAPIKeyReload announces that API keys changed so peers re-sync their in-memory key set. No-op on a nil Handle.
func (*Handle) PublishCatalogReload ¶
PublishCatalogReload announces that an API catalog's specs changed so peers rebuild every connection referencing it. No-op on a nil Handle.
func (*Handle) PublishConnectionReload ¶
PublishConnectionReload announces that the (kind, name) connection changed so peers rebuild it. op is an opaque intent string ("upsert", "delete" or "schema") the bus carries verbatim to the peer handler. No-op on a nil Handle.
func (*Handle) PublishPersonaReload ¶
PublishPersonaReload announces that persona definitions changed so peers reconcile their persona registry. No-op on a nil Handle.
func (*Handle) SessionCache ¶
func (h *Handle) SessionCache() *middleware.SessionEnrichmentCache
SessionCache returns the enrichment-dedup cache, or nil on a nil Handle or when StartCache was never called (session_dedup disabled).
func (*Handle) SessionStore ¶
SessionStore returns the externalized session store, or nil on a nil Handle.
func (*Handle) StartCache ¶
func (h *Handle) StartCache(entryTTL, sessionTimeout time.Duration) *middleware.SessionEnrichmentCache
StartCache builds the per-session enrichment-dedup cache and starts its cleanup goroutine. Callers gate this on config (session_dedup enabled); when not called the cache stays nil and SessionCache returns nil — the disabled no-op. No-op on a nil Handle or a repeat call, so a second call cannot leak the first cache's goroutine. Returns the cache for the caller to wire into the enrichment middleware config.
func (*Handle) StatelessForced ¶
StatelessForced reports whether the database store was selected and the SDK's built-in session map must therefore be bypassed. Platform applies this to its Server.Streamable config after New.
type ReloadHandlers ¶
type ReloadHandlers struct {
// Connection receives (kind, name, op) where op is the opaque intent string
// the publisher passed to PublishConnectionReload ("upsert", "delete" or
// "schema", empty for a legacy pre-op event). The bus does not interpret
// op; the handler does.
Connection func(kind, name, op string)
Catalog func(catalogID string)
Persona func()
APIKey func()
}
ReloadHandlers carries the local re-materialization callbacks the reload subscriber invokes when a peer replica announces a configuration change. They stay on Platform (they reach into Platform-owned state) and are injected here so the bus is unit-testable in isolation. Any nil handler means "this subsystem does not participate in cross-replica reload"; the event is ignored. This is also the reloadBus's handler type, so New passes it straight through.