@@ -5,7 +5,6 @@ import { TypeMapping, ReplyUnion, RespVersions, RedisArgument } from '../RESP/ty
5
5
import { ChannelListeners , PubSub , PubSubCommand , PubSubListener , PubSubType , PubSubTypeListeners } from './pub-sub' ;
6
6
import { AbortError , ErrorReply , TimeoutDuringMaintanance , TimeoutError } from '../errors' ;
7
7
import { MonitorCallback } from '.' ;
8
- import EventEmitter from 'events' ;
9
8
import assert from 'assert' ;
10
9
11
10
export interface CommandOptions < T = TypeMapping > {
@@ -53,6 +52,13 @@ const RESP2_PUSH_TYPE_MAPPING = {
53
52
[ RESP_TYPES . SIMPLE_STRING ] : Buffer
54
53
} ;
55
54
55
+ // Try to handle a push notification. Return whether you
56
+ // successfully consumed the notification or not. This is
57
+ // important in order for the queue to be able to pass the
58
+ // notification to another handler if the current one did not
59
+ // succeed.
60
+ type PushHandler = ( pushItems : Array < any > ) => boolean ;
61
+
56
62
export default class RedisCommandsQueue {
57
63
readonly #respVersion;
58
64
readonly #maxLength;
@@ -62,7 +68,8 @@ export default class RedisCommandsQueue {
62
68
#chainInExecution: symbol | undefined ;
63
69
readonly decoder ;
64
70
readonly #pubSub = new PubSub ( ) ;
65
- readonly events = new EventEmitter ( ) ;
71
+
72
+ #pushHandlers: PushHandler [ ] = [ this . #onPush. bind ( this ) ] ;
66
73
67
74
// If this value is set, we are in a maintenance mode.
68
75
// This means any existing commands should have their timeout
@@ -112,8 +119,6 @@ export default class RedisCommandsQueue {
112
119
return this . #pubSub. isActive ;
113
120
}
114
121
115
- #invalidateCallback?: ( key : RedisArgument | null ) => unknown ;
116
-
117
122
constructor (
118
123
respVersion : RespVersions ,
119
124
maxLength : number | null | undefined ,
@@ -155,6 +160,7 @@ export default class RedisCommandsQueue {
155
160
}
156
161
return true ;
157
162
}
163
+ return false
158
164
}
159
165
160
166
#getTypeMapping( ) {
@@ -167,46 +173,16 @@ export default class RedisCommandsQueue {
167
173
onErrorReply : err => this . #onErrorReply( err ) ,
168
174
//TODO: we can shave off a few cycles by not adding onPush handler at all if CSC is not used
169
175
onPush : push => {
170
- if ( ! this . #onPush( push ) ) {
171
- // currently only supporting "invalidate" over RESP3 push messages
172
- switch ( push [ 0 ] . toString ( ) ) {
173
- case "invalidate" : {
174
- if ( this . #invalidateCallback) {
175
- if ( push [ 1 ] !== null ) {
176
- for ( const key of push [ 1 ] ) {
177
- this . #invalidateCallback( key ) ;
178
- }
179
- } else {
180
- this . #invalidateCallback( null ) ;
181
- }
182
- }
183
- break ;
184
- }
185
- case 'MOVING' : {
186
- const [ _ , afterMs , url ] = push ;
187
- const [ host , port ] = url . toString ( ) . split ( ':' ) ;
188
- this . events . emit ( 'moving' , afterMs , host , Number ( port ) ) ;
189
- break ;
190
- }
191
- case 'MIGRATING' :
192
- case 'FAILING_OVER' : {
193
- this . events . emit ( 'migrating' ) ;
194
- break ;
195
- }
196
- case 'MIGRATED' :
197
- case 'FAILED_OVER' : {
198
- this . events . emit ( 'migrated' ) ;
199
- break ;
200
- }
201
- }
176
+ for ( const pushHandler of this . #pushHandlers) {
177
+ if ( pushHandler ( push ) ) return
202
178
}
203
179
} ,
204
180
getTypeMapping : ( ) => this . #getTypeMapping( )
205
181
} ) ;
206
182
}
207
183
208
- setInvalidateCallback ( callback ?: ( key : RedisArgument | null ) => unknown ) {
209
- this . #invalidateCallback = callback ;
184
+ addPushHandler ( handler : PushHandler ) : void {
185
+ this . #pushHandlers . push ( handler ) ;
210
186
}
211
187
212
188
async waitForInflightCommandsToComplete ( ) : Promise < void > {
0 commit comments