@@ -28,6 +28,7 @@ class Manager extends EventEmitter implements types.EventsMixin {
2828 queueCacheInterval : NodeJS . Timeout | undefined
2929 timekeeper : Timekeeper | undefined
3030 queues : Record < string , types . QueueResult > | null
31+ pendingOffWorkCleanups : Set < Promise < void > >
3132
3233 constructor ( db : types . IDatabase , config : types . ResolvedConstructorOptions ) {
3334 super ( )
@@ -37,6 +38,7 @@ class Manager extends EventEmitter implements types.EventsMixin {
3738 this . wipTs = Date . now ( )
3839 this . workers = new Map ( )
3940 this . queues = null
41+ this . pendingOffWorkCleanups = new Set ( )
4042 }
4143
4244 async start ( ) {
@@ -80,11 +82,11 @@ class Manager extends EventEmitter implements types.EventsMixin {
8082
8183 clearInterval ( this . queueCacheInterval )
8284
83- for ( const worker of this . workers . values ( ) ) {
84- if ( ! INTERNAL_QUEUES [ worker . name ] ) {
85- await this . offWork ( worker . name )
86- }
87- }
85+ await Promise . allSettled (
86+ [ ... this . workers . values ( ) ]
87+ . filter ( worker => ! INTERNAL_QUEUES [ worker . name ] )
88+ . map ( async worker => await this . offWork ( worker . name , { wait : false } ) )
89+ )
8890 }
8991
9092 async failWip ( ) {
@@ -132,11 +134,15 @@ class Manager extends EventEmitter implements types.EventsMixin {
132134
133135 const data = this . getWorkers ( )
134136 . map ( i => i . toWipData ( ) )
135- . filter ( i => i . count > 0 && ( ! INTERNAL_QUEUES [ i . name ] || includeInternal ) )
137+ . filter ( i => i . state !== 'stopped' && ( ! INTERNAL_QUEUES [ i . name ] || includeInternal ) )
136138
137139 return data
138140 }
139141
142+ hasPendingCleanups ( ) : boolean {
143+ return this . pendingOffWorkCleanups . size > 0
144+ }
145+
140146 private async watch < T > ( name : string , options : types . ResolvedWorkOptions , callback : types . WorkHandler < T > ) : Promise < string > {
141147 if ( this . stopped ) {
142148 throw new Error ( 'Workers are disabled. pg-boss is stopped' )
@@ -190,18 +196,13 @@ class Manager extends EventEmitter implements types.EventsMixin {
190196 return id
191197 }
192198
193- async offWork ( value : string | types . OffWorkOptions ) : Promise < void > {
194- assert ( value , 'Missing required argument' )
199+ async offWork ( name : string , options : types . OffWorkOptions = { wait : true } ) : Promise < void > {
200+ assert ( name , 'queue name is required' )
201+ assert ( typeof name === 'string' , 'queue name must be a string' )
195202
196- const query = ( typeof value === 'string' )
197- ? { filter : ( i : Worker < any > ) => i . name === value }
198- : ( typeof value === 'object' && value . id )
199- ? { filter : ( i : Worker < any > ) => i . id === value . id }
200- : null
203+ const query = ( i : Worker < any > ) => options ?. id ? i . id === options . id : i . name === name
201204
202- assert ( query , 'Invalid argument. Expected string or object: { id }' )
203-
204- const workers = this . getWorkers ( ) . filter ( i => query . filter ( i ) && ! i . stopping && ! i . stopped )
205+ const workers = this . getWorkers ( ) . filter ( i => query ( i ) && ! i . stopping && ! i . stopped )
205206
206207 if ( workers . length === 0 ) {
207208 return
@@ -211,15 +212,22 @@ class Manager extends EventEmitter implements types.EventsMixin {
211212 worker . stop ( )
212213 }
213214
214- setImmediate ( async ( ) => {
215+ const cleanupPromise = ( async ( ) => {
215216 while ( ! workers . every ( w => w . stopped ) ) {
216217 await delay ( 1000 )
217218 }
218219
219220 for ( const worker of workers ) {
220221 this . removeWorker ( worker )
221222 }
222- } )
223+ } ) ( )
224+
225+ if ( options . wait ) {
226+ await cleanupPromise
227+ } else {
228+ this . pendingOffWorkCleanups . add ( cleanupPromise )
229+ cleanupPromise . finally ( ( ) => this . pendingOffWorkCleanups . delete ( cleanupPromise ) )
230+ }
223231 }
224232
225233 notifyWorker ( workerId : string ) : void {
0 commit comments