@@ -15,6 +15,9 @@ class LocalQueueDriverConnection {
15
15
this . toProcess = driver . toProcess ;
16
16
this . recent = driver . recent ;
17
17
this . active = driver . active ;
18
+ this . heartBeat = driver . heartBeat ;
19
+ this . processingCounter = driver . processingCounter ;
20
+ this . processingLocks = driver . processingLocks ;
18
21
}
19
22
20
23
getResultPromise ( resultListKey ) {
@@ -30,12 +33,16 @@ class LocalQueueDriverConnection {
30
33
31
34
async getResultBlocking ( queryKey ) {
32
35
const resultListKey = this . resultListKey ( queryKey ) ;
36
+ if ( ! this . queryDef [ this . redisHash ( queryKey ) ] && ! this . resultPromises [ resultListKey ] ) {
37
+ return null ;
38
+ }
33
39
const timeoutPromise = ( timeout ) => new Promise ( ( resolve ) => setTimeout ( ( ) => resolve ( null ) , timeout ) ) ;
34
40
35
41
const res = await Promise . race ( [
36
42
this . getResultPromise ( resultListKey ) ,
37
43
timeoutPromise ( this . continueWaitTimeout * 1000 ) ,
38
44
] ) ;
45
+
39
46
if ( res ) {
40
47
delete this . resultPromises [ resultListKey ] ;
41
48
}
@@ -98,36 +105,41 @@ class LocalQueueDriverConnection {
98
105
const key = this . redisHash ( queryKey ) ;
99
106
const query = this . queryDef [ key ] ;
100
107
delete this . active [ key ] ;
108
+ delete this . heartBeat [ key ] ;
101
109
delete this . toProcess [ key ] ;
102
110
delete this . recent [ key ] ;
103
111
delete this . queryDef [ key ] ;
112
+ delete this . processingLocks [ key ] ;
104
113
return [ query ] ;
105
114
}
106
115
107
- setResultAndRemoveQuery ( queryKey , executionResult ) {
116
+ async setResultAndRemoveQuery ( queryKey , executionResult , processingId ) {
108
117
const key = this . redisHash ( queryKey ) ;
118
+ if ( this . processingLocks [ key ] !== processingId ) {
119
+ return false ;
120
+ }
109
121
const promise = this . getResultPromise ( this . resultListKey ( queryKey ) ) ;
110
122
delete this . active [ key ] ;
123
+ delete this . heartBeat [ key ] ;
111
124
delete this . toProcess [ key ] ;
112
125
delete this . recent [ key ] ;
113
126
delete this . queryDef [ key ] ;
127
+ delete this . processingLocks [ key ] ;
114
128
promise . resolve ( executionResult ) ;
129
+ return true ;
115
130
}
116
131
117
- removeQuery ( queryKey ) {
118
- const key = this . redisHash ( queryKey ) ;
119
- delete this . active [ key ] ;
120
- delete this . toProcess [ key ] ;
121
- delete this . recent [ key ] ;
122
- delete this . queryDef [ key ] ;
132
+ getNextProcessingId ( ) {
133
+ this . processingCounter . counter = this . processingCounter . counter ? this . processingCounter . counter + 1 : 1 ;
134
+ return this . processingCounter . counter ;
123
135
}
124
136
125
137
getOrphanedQueries ( ) {
126
138
return this . queueArray ( this . recent , new Date ( ) . getTime ( ) - this . orphanedTimeout * 1000 ) ;
127
139
}
128
140
129
141
getStalledQueries ( ) {
130
- return this . queueArray ( this . active , new Date ( ) . getTime ( ) - this . heartBeatTimeout * 1000 ) ;
142
+ return this . queueArray ( this . heartBeat , new Date ( ) . getTime ( ) - this . heartBeatTimeout * 1000 ) ;
131
143
}
132
144
133
145
async getQueryStageState ( onlyKeys ) {
@@ -140,24 +152,43 @@ class LocalQueueDriverConnection {
140
152
141
153
updateHeartBeat ( queryKey ) {
142
154
const key = this . redisHash ( queryKey ) ;
143
- if ( this . active [ key ] ) {
144
- this . active [ key ] = { key, order : new Date ( ) . getTime ( ) } ;
155
+ if ( this . heartBeat [ key ] ) {
156
+ this . heartBeat [ key ] = { key, order : new Date ( ) . getTime ( ) } ;
145
157
}
146
158
}
147
159
148
- retrieveForProcessing ( queryKey ) {
160
+ retrieveForProcessing ( queryKey , processingId ) {
149
161
const key = this . redisHash ( queryKey ) ;
162
+ let lockAcquired = false ;
163
+ if ( ! this . processingLocks [ key ] ) {
164
+ this . processingLocks [ key ] = processingId ;
165
+ lockAcquired = true ;
166
+ }
150
167
let added = 0 ;
151
168
if ( Object . keys ( this . active ) . length < this . concurrency && ! this . active [ key ] ) {
152
- this . active [ key ] = { key, order : new Date ( ) . getTime ( ) } ;
169
+ this . active [ key ] = { key, order : processingId } ;
153
170
added = 1 ;
154
171
}
155
- return [ added , null , this . queueArray ( this . active ) , Object . keys ( this . toProcess ) . length ] ; // TODO nulls
172
+ this . heartBeat [ key ] = { key, order : new Date ( ) . getTime ( ) } ;
173
+ return [
174
+ added , null , this . queueArray ( this . active ) , Object . keys ( this . toProcess ) . length , this . queryDef [ key ] , lockAcquired
175
+ ] ; // TODO nulls
156
176
}
157
177
158
- async optimisticQueryUpdate ( queryKey , toUpdate ) {
178
+ freeProcessingLock ( queryKey , processingId ) {
159
179
const key = this . redisHash ( queryKey ) ;
180
+ if ( this . processingLocks [ key ] === processingId ) {
181
+ delete this . processingLocks [ key ] ;
182
+ }
183
+ }
184
+
185
+ async optimisticQueryUpdate ( queryKey , toUpdate , processingId ) {
186
+ const key = this . redisHash ( queryKey ) ;
187
+ if ( this . processingLocks [ key ] !== processingId ) {
188
+ return false ;
189
+ }
160
190
this . queryDef [ key ] = { ...this . queryDef [ key ] , ...toUpdate } ;
191
+ return true ;
161
192
}
162
193
163
194
release ( ) {
@@ -182,6 +213,9 @@ const queryDef = {};
182
213
const toProcess = { } ;
183
214
const recent = { } ;
184
215
const active = { } ;
216
+ const heartBeat = { } ;
217
+ const processingCounters = { } ;
218
+ const processingLocks = { } ;
185
219
186
220
class LocalQueueDriver extends BaseQueueDriver {
187
221
constructor ( options ) {
@@ -193,12 +227,18 @@ class LocalQueueDriver extends BaseQueueDriver {
193
227
toProcess [ options . redisQueuePrefix ] = toProcess [ options . redisQueuePrefix ] || { } ;
194
228
recent [ options . redisQueuePrefix ] = recent [ options . redisQueuePrefix ] || { } ;
195
229
active [ options . redisQueuePrefix ] = active [ options . redisQueuePrefix ] || { } ;
230
+ heartBeat [ options . redisQueuePrefix ] = heartBeat [ options . redisQueuePrefix ] || { } ;
231
+ processingCounters [ options . redisQueuePrefix ] = processingCounters [ options . redisQueuePrefix ] || { } ;
232
+ processingLocks [ options . redisQueuePrefix ] = processingLocks [ options . redisQueuePrefix ] || { } ;
196
233
this . results = results [ options . redisQueuePrefix ] ;
197
234
this . resultPromises = resultPromises [ options . redisQueuePrefix ] ;
198
235
this . queryDef = queryDef [ options . redisQueuePrefix ] ;
199
236
this . toProcess = toProcess [ options . redisQueuePrefix ] ;
200
237
this . recent = recent [ options . redisQueuePrefix ] ;
201
238
this . active = active [ options . redisQueuePrefix ] ;
239
+ this . heartBeat = heartBeat [ options . redisQueuePrefix ] ;
240
+ this . processingCounter = processingCounters [ options . redisQueuePrefix ] ;
241
+ this . processingLocks = processingLocks [ options . redisQueuePrefix ] ;
202
242
}
203
243
204
244
createConnection ( ) {
0 commit comments