Documentation
¶
Overview ¶
Package session provides service-layer helpers on top of the session.Session model: activity lock service, session resolver, etc.
The chat-session-redesign spec mandates that lock state live in the Session document itself (Session.Lock) so the pre-existing Session-level transactions double as lock transactions. LockService is a thin facade over the Repository's AcquireSessionLock / RefreshSessionLock / ReleaseSessionLock methods that returns an ergonomic *Lock handle.
Index ¶
- Constants
- type Lock
- type LockService
- type LockServiceOption
- type Resolver
- func (r *Resolver) CreateFreshSession(ctx context.Context, ticketID types.TicketID, source sessModel.SessionSource, ...) (*sessModel.Session, error)
- func (r *Resolver) LookupSlackSession(ctx context.Context, ticketID *types.TicketID, thread slackModel.Thread) (*sessModel.Session, bool, error)
- func (r *Resolver) ResolveSlackSession(ctx context.Context, ticketID *types.TicketID, thread slackModel.Thread, ...) (sess *sessModel.Session, created bool, err error)
Constants ¶
const DefaultLockTTL = 3 * time.Minute
DefaultLockTTL is the TTL applied to Slack Session activity locks when a caller does not specify one explicitly. Three minutes matches the spec requirement of roughly matching a user's patience for a stuck chat while still allowing crash recovery to kick in within a short window.
Variables ¶
This section is empty.
Functions ¶
This section is empty.
Types ¶
type Lock ¶
type Lock struct {
// contains filtered or unexported fields
}
Lock is a runtime handle to an acquired Session activity lock. The persistent state lives in Session.Lock (Firestore / memory); the handle only carries the identifiers needed to refresh/release and so that test code can inspect the holder.
func (*Lock) ExpiresAt ¶
ExpiresAt returns the current expires_at snapshot (only updated by Refresh).
type LockService ¶
type LockService struct {
// contains filtered or unexported fields
}
LockService manufactures Lock handles by acquiring Session activity locks via the Repository.
func NewLockService ¶
func NewLockService(repo interfaces.Repository, opts ...LockServiceOption) *LockService
NewLockService constructs a LockService bound to repo.
func (*LockService) TryAcquire ¶
func (s *LockService) TryAcquire(ctx context.Context, sessionID types.SessionID) (*Lock, bool, error)
TryAcquire attempts to grab the activity lock for sessionID. On success, the returned *Lock must eventually be passed to Release (typically via defer). On contention (lock already held and not expired), returns (nil, false, nil). Returns error only on infrastructure failure.
holderID is taken from ctx (request_id). If no request_id is present, TryAcquire returns an error — an anonymous lock would make diagnosis impossible.
type LockServiceOption ¶
type LockServiceOption func(*LockService)
LockServiceOption configures optional behavior on the LockService.
func WithLockTTL ¶
func WithLockTTL(ttl time.Duration) LockServiceOption
WithLockTTL overrides the default 3-minute TTL used by TryAcquire.
type Resolver ¶
type Resolver struct {
// contains filtered or unexported fields
}
Resolver creates or looks up Sessions for the new chat-session-redesign lifecycle. It uses deterministic IDs for Slack Sessions so that a thread maps to exactly one Session across all Warren instances; Web/CLI Sessions use random IDs since they are ephemeral per-invocation.
Resolver holds no per-Session state; it only carries the Repository dependency that it uses to read/write Sessions.
func NewResolver ¶
func NewResolver(repo interfaces.Repository) *Resolver
NewResolver constructs a Resolver bound to repo.
func (*Resolver) CreateFreshSession ¶
func (r *Resolver) CreateFreshSession( ctx context.Context, ticketID types.TicketID, source sessModel.SessionSource, userID types.UserID, ) (*sessModel.Session, error)
CreateFreshSession creates a new Session with a random ID. This is the Web/CLI path: each invocation is independent, so no deterministic lookup is needed. ticketID is required for Web/CLI flows.
func (*Resolver) LookupSlackSession ¶
func (r *Resolver) LookupSlackSession( ctx context.Context, ticketID *types.TicketID, thread slackModel.Thread, ) (*sessModel.Session, bool, error)
LookupSlackSession returns the Session bound to (ticketID, thread) if one exists, or (nil, false, nil) when not. **Never creates** a new Session — used by dry-run migration paths that must not mutate state.
func (*Resolver) ResolveSlackSession ¶
func (r *Resolver) ResolveSlackSession( ctx context.Context, ticketID *types.TicketID, thread slackModel.Thread, userID types.UserID, ) (sess *sessModel.Session, created bool, err error)
ResolveSlackSession returns the Session associated with the given Slack thread, creating it transactionally if it does not exist.
ticketID may be nil for ticketless threads (e.g. @warren mention on a thread that has not yet been escalated into a Ticket). The Session document's ID is derived from ticketID+thread so repeated calls from any instance return the same Session.
The (session, created) tuple distinguishes "found existing" from "created new" so callers that need to emit "starting a new investigation" notices only do so on first mention.