@@ -3,7 +3,7 @@ import encodeCommand from '../RESP/encoder';
3
3
import { Decoder , PUSH_TYPE_MAPPING , RESP_TYPES } from '../RESP/decoder' ;
4
4
import { TypeMapping , ReplyUnion , RespVersions , RedisArgument } from '../RESP/types' ;
5
5
import { ChannelListeners , PubSub , PubSubCommand , PubSubListener , PubSubType , PubSubTypeListeners } from './pub-sub' ;
6
- import { AbortError , ErrorReply } from '../errors' ;
6
+ import { AbortError , ErrorReply , TimeoutError } from '../errors' ;
7
7
import { MonitorCallback } from '.' ;
8
8
9
9
export interface CommandOptions < T = TypeMapping > {
@@ -14,6 +14,10 @@ export interface CommandOptions<T = TypeMapping> {
14
14
* Maps between RESP and JavaScript types
15
15
*/
16
16
typeMapping ?: T ;
17
+ /**
18
+ * Timeout for the command in milliseconds
19
+ */
20
+ timeout ?: number ;
17
21
}
18
22
19
23
export interface CommandToWrite extends CommandWaitingForReply {
@@ -23,6 +27,10 @@ export interface CommandToWrite extends CommandWaitingForReply {
23
27
signal : AbortSignal ;
24
28
listener : ( ) => unknown ;
25
29
} | undefined ;
30
+ timeout : {
31
+ signal : AbortSignal ;
32
+ listener : ( ) => unknown ;
33
+ } | undefined ;
26
34
}
27
35
28
36
interface CommandWaitingForReply {
@@ -80,7 +88,7 @@ export default class RedisCommandsQueue {
80
88
#onPush( push : Array < any > ) {
81
89
// TODO: type
82
90
if ( this . #pubSub. handleMessageReply ( push ) ) return true ;
83
-
91
+
84
92
const isShardedUnsubscribe = PubSub . isShardedUnsubscribe ( push ) ;
85
93
if ( isShardedUnsubscribe && ! this . #waitingForReply. length ) {
86
94
const channel = push [ 1 ] . toString ( ) ;
@@ -144,6 +152,7 @@ export default class RedisCommandsQueue {
144
152
if ( this . #maxLength && this . #toWrite. length + this . #waitingForReply. length >= this . #maxLength) {
145
153
return Promise . reject ( new Error ( 'The queue is full' ) ) ;
146
154
} else if ( options ?. abortSignal ?. aborted ) {
155
+ console . log ( 'eeeeeeeee' , args )
147
156
return Promise . reject ( new AbortError ( ) ) ;
148
157
}
149
158
@@ -153,17 +162,35 @@ export default class RedisCommandsQueue {
153
162
args,
154
163
chainId : options ?. chainId ,
155
164
abort : undefined ,
165
+ timeout : undefined ,
156
166
resolve,
157
167
reject,
158
168
channelsCounter : undefined ,
159
169
typeMapping : options ?. typeMapping
160
170
} ;
161
171
172
+ const timeout = options ?. timeout ;
173
+ if ( timeout ) {
174
+ console . log ( 'set timeout' , timeout ) ;
175
+ const signal = AbortSignal . timeout ( timeout ) ;
176
+ value . timeout = {
177
+ signal,
178
+ listener : ( ) => {
179
+ console . log ( 'TIMEOUT OCCURRED' , node ) ;
180
+ this . #toWrite. remove ( node ) ;
181
+ value . reject ( new TimeoutError ( ) ) ;
182
+ }
183
+ } ;
184
+ signal . addEventListener ( 'abort' , value . timeout . listener , { once : true } ) ;
185
+ }
186
+
162
187
const signal = options ?. abortSignal ;
163
188
if ( signal ) {
189
+ console . log ( 'signal' , signal )
164
190
value . abort = {
165
191
signal,
166
192
listener : ( ) => {
193
+ console . log ( 'ABORT OCCURRED' , node ) ;
167
194
this . #toWrite. remove ( node ) ;
168
195
value . reject ( new AbortError ( ) ) ;
169
196
}
@@ -181,6 +208,7 @@ export default class RedisCommandsQueue {
181
208
args : command . args ,
182
209
chainId,
183
210
abort : undefined ,
211
+ timeout : undefined ,
184
212
resolve ( ) {
185
213
command . resolve ( ) ;
186
214
resolve ( ) ;
@@ -202,7 +230,7 @@ export default class RedisCommandsQueue {
202
230
this . decoder . onReply = ( reply => {
203
231
if ( Array . isArray ( reply ) ) {
204
232
if ( this . #onPush( reply ) ) return ;
205
-
233
+
206
234
if ( PONG . equals ( reply [ 0 ] as Buffer ) ) {
207
235
const { resolve, typeMapping } = this . #waitingForReply. shift ( ) ! ,
208
236
buffer = ( ( reply [ 1 ] as Buffer ) . length === 0 ? reply [ 0 ] : reply [ 1 ] ) as Buffer ;
@@ -250,7 +278,7 @@ export default class RedisCommandsQueue {
250
278
if ( ! this . #pubSub. isActive ) {
251
279
this . #resetDecoderCallbacks( ) ;
252
280
}
253
-
281
+
254
282
resolve ( ) ;
255
283
} ;
256
284
}
@@ -299,6 +327,7 @@ export default class RedisCommandsQueue {
299
327
args : [ 'MONITOR' ] ,
300
328
chainId : options ?. chainId ,
301
329
abort : undefined ,
330
+ timeout : undefined ,
302
331
// using `resolve` instead of using `.then`/`await` to make sure it'll be called before processing the next reply
303
332
resolve : ( ) => {
304
333
// after running `MONITOR` only `MONITOR` and `RESET` replies are expected
@@ -317,7 +346,7 @@ export default class RedisCommandsQueue {
317
346
reject,
318
347
channelsCounter : undefined ,
319
348
typeMapping
320
- } , options ?. asap ) ;
349
+ } , options ?. asap ) ;
321
350
} ) ;
322
351
}
323
352
@@ -340,18 +369,19 @@ export default class RedisCommandsQueue {
340
369
this . #resetDecoderCallbacks( ) ;
341
370
this . #resetFallbackOnReply = undefined ;
342
371
this . #pubSub. reset ( ) ;
343
-
372
+
344
373
this . #waitingForReply. shift ( ) ! . resolve ( reply ) ;
345
374
return ;
346
375
}
347
-
376
+
348
377
this . #resetFallbackOnReply! ( reply ) ;
349
378
} ) as Decoder [ 'onReply' ] ;
350
379
351
380
this . #toWrite. push ( {
352
381
args : [ 'RESET' ] ,
353
382
chainId,
354
383
abort : undefined ,
384
+ timeout : undefined ,
355
385
resolve,
356
386
reject,
357
387
channelsCounter : undefined ,
@@ -376,7 +406,7 @@ export default class RedisCommandsQueue {
376
406
continue ;
377
407
}
378
408
379
- // TODO reuse `toSend` or create new object?
409
+ // TODO reuse `toSend` or create new object?
380
410
( toSend as any ) . args = undefined ;
381
411
if ( toSend . abort ) {
382
412
RedisCommandsQueue . #removeAbortListener( toSend ) ;
@@ -385,7 +415,7 @@ export default class RedisCommandsQueue {
385
415
this . #chainInExecution = toSend . chainId ;
386
416
toSend . chainId = undefined ;
387
417
this . #waitingForReply. push ( toSend ) ;
388
-
418
+
389
419
yield encoded ;
390
420
toSend = this . #toWrite. shift ( ) ;
391
421
}
@@ -406,7 +436,7 @@ export default class RedisCommandsQueue {
406
436
if ( toBeSent . abort ) {
407
437
RedisCommandsQueue . #removeAbortListener( toBeSent ) ;
408
438
}
409
-
439
+
410
440
toBeSent . reject ( err ) ;
411
441
}
412
442
0 commit comments