@@ -94,8 +94,10 @@ export default class Queue extends EventEmitter {
9494 this . _workerClients = [ ]
9595 this . _cleanupTimer = null
9696 this . _inFlight = 0
97+ this . _defaultInFlight = 0
9798 this . _pushed = 0
9899 this . _totalSettled = 0
100+ this . _inFlightTasks = new Map ( )
99101 this . _closed = false
100102 this . _localSemaphore = new LocalSemaphore ( this . _options . concurrency )
101103 this . _activeLeases = new Set ( )
@@ -126,6 +128,86 @@ export default class Queue extends EventEmitter {
126128 return this . _inFlight
127129 }
128130
131+ /**
132+ * Point-in-time snapshot of this instance's state and Redis-backed depth counts.
133+ * Safe to call from observability/devtools - hits Redis with LLEN per known group.
134+ * @returns {Promise<{
135+ * options: object,
136+ * inFlight: number,
137+ * defaultInFlight: number,
138+ * pushed: number,
139+ * settled: number,
140+ * defaultDepth: number,
141+ * workers: { default: number, group: number },
142+ * groups: Array<{ name: string, inFlight: number, depth: number, workers: number }>,
143+ * inFlightTasks: Array<{ uuid: string, group: string|null, attempts: number, startedAt: number, workerId: string, payload: any }>,
144+ * }> }
145+ */
146+ async snapshot ( { includePayload = false } = { } ) {
147+ const opts = this . _options
148+ const groupNames = new Set ( [
149+ ...this . _groupWorkers . keys ( ) ,
150+ ...this . _groupInFlight . keys ( ) ,
151+ ] )
152+
153+ let defaultDepth = 0
154+ const groupDepths = new Map ( )
155+ if ( this . _redis ?. isOpen ) {
156+ try {
157+ defaultDepth = await this . _redis . lLen ( 'queue:tasks' )
158+ } catch { }
159+ for ( const name of groupNames ) {
160+ try {
161+ groupDepths . set ( name , await this . _redis . lLen ( `queue:groups:${ name } ` ) )
162+ } catch {
163+ groupDepths . set ( name , 0 )
164+ }
165+ }
166+ }
167+
168+ const groups = Array . from ( groupNames ) . map ( ( name ) => ( {
169+ name,
170+ inFlight : this . _groupInFlight . get ( name ) || 0 ,
171+ depth : groupDepths . get ( name ) || 0 ,
172+ workers : this . _groupWorkers . get ( name ) ?. size || 0 ,
173+ } ) ) . sort ( ( a , b ) => a . name . localeCompare ( b . name ) )
174+
175+ const inFlightTasks = [ ]
176+ for ( const [ uuid , entry ] of this . _inFlightTasks ) {
177+ inFlightTasks . push ( {
178+ uuid,
179+ group : entry . group ,
180+ attempts : entry . task . attempts ,
181+ startedAt : entry . startedAt ,
182+ workerId : entry . workerId ,
183+ payload : includePayload ? entry . task . payload : undefined ,
184+ } )
185+ }
186+ inFlightTasks . sort ( ( a , b ) => a . startedAt - b . startedAt )
187+
188+ let groupWorkerTotal = 0
189+ for ( const m of this . _groupWorkers . values ( ) ) groupWorkerTotal += m . size
190+
191+ return {
192+ options : {
193+ concurrency : opts . concurrency ,
194+ globalConcurrency : opts . globalConcurrency ,
195+ delay : opts . delay ,
196+ timeout : opts . timeout ,
197+ maxRetries : opts . maxRetries ,
198+ groups : { ...opts . groups } ,
199+ } ,
200+ inFlight : this . _inFlight ,
201+ defaultInFlight : this . _defaultInFlight ,
202+ pushed : this . _pushed ,
203+ settled : this . _totalSettled ,
204+ defaultDepth,
205+ workers : { default : this . _workers . size , group : groupWorkerTotal } ,
206+ groups,
207+ inFlightTasks,
208+ }
209+ }
210+
129211 /** @param {TaskHandler } handler */
130212 process ( handler ) {
131213 this . _handler = handler
@@ -430,15 +512,21 @@ export default class Queue extends EventEmitter {
430512 this . _inFlight ++
431513 if ( opts . group ) {
432514 this . _groupInFlight . set ( opts . group , ( this . _groupInFlight . get ( opts . group ) || 0 ) + 1 )
515+ } else {
516+ this . _defaultInFlight ++
433517 }
518+ this . _inFlightTasks . set ( task . uuid , { task, startedAt : Date . now ( ) , workerId, group : opts . group ?? null } )
434519
435520 try {
436521 await this . _processTask ( task , opts )
437522 } finally {
523+ this . _inFlightTasks . delete ( task . uuid )
438524 if ( opts . group ) {
439525 const count = ( this . _groupInFlight . get ( opts . group ) || 1 ) - 1
440526 if ( count <= 0 ) this . _groupInFlight . delete ( opts . group )
441527 else this . _groupInFlight . set ( opts . group , count )
528+ } else {
529+ this . _defaultInFlight = Math . max ( 0 , this . _defaultInFlight - 1 )
442530 }
443531 if ( leaseId ) await this . _releaseGlobal ( leaseId ) . catch ( ( ) => { } )
444532 }
0 commit comments