session

package
v0.17.0 Latest Latest
Warning

This package is not in the latest version of its module.

Go to latest
Published: May 23, 2026 License: Apache-2.0 Imports: 12 Imported by: 0

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

View Source
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

func (l *Lock) ExpiresAt() time.Time

ExpiresAt returns the current expires_at snapshot (only updated by Refresh).

func (*Lock) HolderID

func (l *Lock) HolderID() string

HolderID returns the request_id of the current holder.

func (*Lock) Refresh

func (l *Lock) Refresh(ctx context.Context) error

Refresh extends the lock's ExpiresAt by its configured TTL.

func (*Lock) Release

func (l *Lock) Release(ctx context.Context) error

Release relinquishes the lock so the next TryAcquire succeeds immediately (without waiting for TTL expiry).

func (*Lock) SessionID

func (l *Lock) SessionID() types.SessionID

SessionID returns the Session the lock protects.

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.

Jump to

Keyboard shortcuts

? : This menu
/ : Search site
f or F : Jump to
y or Y : Canonical URL