@@ -4,15 +4,19 @@ import {
44} from '@codebuff/common/constants/freebuff-models'
55
66import {
7+ getInstantAdmitCapacity ,
78 getSessionGraceMs ,
9+ getSessionLengthMs ,
810 isWaitingRoomBypassedForEmail ,
911 isWaitingRoomEnabled ,
1012} from './config'
1113import {
14+ activeCountForModel ,
1215 endSession ,
1316 FreeSessionModelLockedError ,
1417 getSessionRow ,
1518 joinOrTakeOver ,
19+ promoteQueuedUser ,
1620 queueDepthsByModel ,
1721 queuePositionFor ,
1822} from './store'
@@ -35,11 +39,28 @@ export interface SessionDeps {
3539 model : string
3640 queuedAt : Date
3741 } ) => Promise < number >
42+ /** Instant-admit check: returns the number of active sessions currently
43+ * bound to a given model. Compared against the model's configured
44+ * `instantAdmitCapacity` to decide whether a new joiner skips the queue. */
45+ activeCountForModel : ( model : string ) => Promise < number >
46+ /** Instant-admit promotion: flips a specific queued row to active. Returns
47+ * the updated row or null if the row wasn't in a queued state. */
48+ promoteQueuedUser : ( params : {
49+ userId : string
50+ model : string
51+ sessionLengthMs : number
52+ now : Date
53+ } ) => Promise < InternalSessionRow | null >
54+ /** Per-model capacity lookup. Indirected through deps so tests can
55+ * force-enable / force-disable instant admit without mutating the
56+ * shared model registry. */
57+ getInstantAdmitCapacity : ( model : string ) => number
3858 isWaitingRoomEnabled : ( ) => boolean
3959 /** Plain values, not getters: these never change at runtime. The deps
4060 * interface uses values rather than thunks so tests can pass numbers
4161 * inline without wrapping. */
4262 graceMs : number
63+ sessionLengthMs : number
4364 now ?: ( ) => Date
4465}
4566
@@ -49,13 +70,19 @@ const defaultDeps: SessionDeps = {
4970 endSession,
5071 queueDepthsByModel,
5172 queuePositionFor,
73+ activeCountForModel,
74+ promoteQueuedUser,
75+ getInstantAdmitCapacity,
5276 isWaitingRoomEnabled,
5377 get graceMs ( ) {
5478 // Read-through getter so test overrides via env still work; the value
5579 // itself is materialized once per call. Cheaper than a thunk because
5680 // callers don't have to invoke a function.
5781 return getSessionGraceMs ( )
5882 } ,
83+ get sessionLengthMs ( ) {
84+ return getSessionLengthMs ( )
85+ } ,
5986}
6087
6188const nowOf = ( deps : SessionDeps ) : Date => ( deps . now ?? ( ( ) => new Date ( ) ) ) ( )
@@ -145,6 +172,33 @@ export async function requestSession(params: {
145172 }
146173 throw err
147174 }
175+
176+ // Instant-admit: if the model has spare capacity (fewer active sessions
177+ // than its configured `instantAdmitCapacity`), skip the waiting room
178+ // entirely and flip the user to active in this same request. The tick
179+ // + FIFO queue only engage once we hit the threshold, so backpressure
180+ // kicks in exactly when the deployment needs it.
181+ //
182+ // Race note: two concurrent joiners may each see `active < capacity`
183+ // and both get admitted, overshooting the cap by up to `concurrency - 1`.
184+ // Capacities are chosen with headroom for this, and the configured
185+ // value is a comfort threshold not a hard ceiling.
186+ if ( row . status === 'queued' ) {
187+ const capacity = deps . getInstantAdmitCapacity ( model )
188+ if ( capacity > 0 ) {
189+ const activeCount = await deps . activeCountForModel ( model )
190+ if ( activeCount < capacity ) {
191+ const promoted = await deps . promoteQueuedUser ( {
192+ userId : params . userId ,
193+ model,
194+ sessionLengthMs : deps . sessionLengthMs ,
195+ now : nowOf ( deps ) ,
196+ } )
197+ if ( promoted ) row = promoted
198+ }
199+ }
200+ }
201+
148202 const view = await viewForRow ( params . userId , deps , row )
149203 if ( ! view ) {
150204 throw new Error (
0 commit comments