@@ -3,6 +3,7 @@ import { getConfig } from '../../config'
3
3
import { BaseEvent , BasePayload } from '../../storage/events'
4
4
import { QueueJobRetryFailed , QueueJobCompleted , QueueJobError } from '../monitoring/metrics'
5
5
import { logger , logSchema } from '../monitoring'
6
+ import { ERRORS } from '@internal/errors'
6
7
7
8
//eslint-disable-next-line @typescript-eslint/no-explicit-any
8
9
type SubclassOfBaseClass = ( new ( payload : any ) => BaseEvent < any > ) & {
@@ -13,11 +14,19 @@ export abstract class Queue {
13
14
protected static events : SubclassOfBaseClass [ ] = [ ]
14
15
private static pgBoss ?: PgBoss
15
16
16
- static async init ( ) {
17
+ static async start ( opts : {
18
+ signal ?: AbortSignal
19
+ onMessage ?: ( job : Job ) => void
20
+ registerWorkers ?: ( ) => void
21
+ } ) {
17
22
if ( Queue . pgBoss ) {
18
23
return Queue . pgBoss
19
24
}
20
25
26
+ if ( opts . signal ?. aborted ) {
27
+ throw ERRORS . Aborted ( 'Cannot start queue with aborted signal' )
28
+ }
29
+
21
30
const {
22
31
isMultitenant,
23
32
databaseURL,
@@ -26,6 +35,7 @@ export abstract class Queue {
26
35
pgQueueDeleteAfterDays,
27
36
pgQueueArchiveCompletedAfterSeconds,
28
37
pgQueueRetentionDays,
38
+ pgQueueEnableWorkers,
29
39
} = getConfig ( )
30
40
31
41
let url = pgQueueConnectionURL ?? databaseURL
@@ -59,7 +69,36 @@ export abstract class Queue {
59
69
} )
60
70
61
71
await Queue . pgBoss . start ( )
62
- await Queue . startWorkers ( )
72
+
73
+ if ( opts . registerWorkers && pgQueueEnableWorkers ) {
74
+ opts . registerWorkers ( )
75
+ }
76
+
77
+ await Queue . startWorkers ( opts . onMessage )
78
+
79
+ if ( opts . signal ) {
80
+ opts . signal . addEventListener (
81
+ 'abort' ,
82
+ async ( ) => {
83
+ logSchema . info ( logger , '[Queue] Stopping' , {
84
+ type : 'queue' ,
85
+ } )
86
+ return Queue . stop ( )
87
+ . then ( ( ) => {
88
+ logSchema . info ( logger , '[Queue] Exited' , {
89
+ type : 'queue' ,
90
+ } )
91
+ } )
92
+ . catch ( ( e ) => {
93
+ logSchema . error ( logger , '[Queue] Error while stopping queue' , {
94
+ error : e ,
95
+ type : 'queue' ,
96
+ } )
97
+ } )
98
+ } ,
99
+ { once : true }
100
+ )
101
+ }
63
102
64
103
return Queue . pgBoss
65
104
}
@@ -85,25 +124,29 @@ export abstract class Queue {
85
124
86
125
await boss . stop ( {
87
126
timeout : 20 * 1000 ,
127
+ graceful : true ,
128
+ destroy : true ,
88
129
} )
89
130
90
131
await new Promise ( ( resolve ) => {
91
- boss . once ( 'stopped' , ( ) => resolve ( null ) )
132
+ boss . once ( 'stopped' , ( ) => {
133
+ resolve ( null )
134
+ } )
92
135
} )
93
136
94
137
Queue . pgBoss = undefined
95
138
}
96
139
97
- protected static startWorkers ( ) {
140
+ protected static startWorkers ( onMessage ?: ( job : Job ) => void ) {
98
141
const workers : Promise < string > [ ] = [ ]
99
142
100
143
Queue . events . forEach ( ( event ) => {
101
- workers . push ( Queue . registerTask ( event . getQueueName ( ) , event , true ) )
144
+ workers . push ( Queue . registerTask ( event . getQueueName ( ) , event , true , onMessage ) )
102
145
103
146
const slowRetryQueue = event . withSlowRetryQueue ( )
104
147
105
148
if ( slowRetryQueue ) {
106
- workers . push ( Queue . registerTask ( event . getSlowRetryQueueName ( ) , event , false ) )
149
+ workers . push ( Queue . registerTask ( event . getSlowRetryQueueName ( ) , event , false , onMessage ) )
107
150
}
108
151
} )
109
152
@@ -113,14 +156,18 @@ export abstract class Queue {
113
156
protected static registerTask (
114
157
queueName : string ,
115
158
event : SubclassOfBaseClass ,
116
- slowRetryQueueOnFail ?: boolean
159
+ slowRetryQueueOnFail ?: boolean ,
160
+ onMessage ?: ( job : Job ) => void
117
161
) {
118
162
const hasSlowRetryQueue = event . withSlowRetryQueue ( )
119
163
return Queue . getInstance ( ) . work (
120
164
queueName ,
121
165
event . getWorkerOptions ( ) ,
122
166
async ( job : Job < BasePayload > ) => {
123
167
try {
168
+ if ( onMessage ) {
169
+ onMessage ( job )
170
+ }
124
171
const res = await event . handle ( job )
125
172
126
173
QueueJobCompleted . inc ( {
0 commit comments