@@ -5,7 +5,6 @@ import { TypeMapping, ReplyUnion, RespVersions, RedisArgument } from '../RESP/ty
55import { ChannelListeners , PubSub , PubSubCommand , PubSubListener , PubSubType , PubSubTypeListeners } from './pub-sub' ;
66import { AbortError , ErrorReply , TimeoutDuringMaintanance , TimeoutError } from '../errors' ;
77import { MonitorCallback } from '.' ;
8- import EventEmitter from 'events' ;
98import assert from 'assert' ;
109
1110export interface CommandOptions < T = TypeMapping > {
@@ -53,6 +52,13 @@ const RESP2_PUSH_TYPE_MAPPING = {
5352 [ RESP_TYPES . SIMPLE_STRING ] : Buffer
5453} ;
5554
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+
5662export default class RedisCommandsQueue {
5763 readonly #respVersion;
5864 readonly #maxLength;
@@ -62,7 +68,8 @@ export default class RedisCommandsQueue {
6268 #chainInExecution: symbol | undefined ;
6369 readonly decoder ;
6470 readonly #pubSub = new PubSub ( ) ;
65- readonly events = new EventEmitter ( ) ;
71+
72+ #pushHandlers: PushHandler [ ] = [ this . #onPush. bind ( this ) ] ;
6673
6774 // If this value is set, we are in a maintenance mode.
6875 // This means any existing commands should have their timeout
@@ -112,8 +119,6 @@ export default class RedisCommandsQueue {
112119 return this . #pubSub. isActive ;
113120 }
114121
115- #invalidateCallback?: ( key : RedisArgument | null ) => unknown ;
116-
117122 constructor (
118123 respVersion : RespVersions ,
119124 maxLength : number | null | undefined ,
@@ -155,6 +160,7 @@ export default class RedisCommandsQueue {
155160 }
156161 return true ;
157162 }
163+ return false
158164 }
159165
160166 #getTypeMapping( ) {
@@ -167,46 +173,16 @@ export default class RedisCommandsQueue {
167173 onErrorReply : err => this . #onErrorReply( err ) ,
168174 //TODO: we can shave off a few cycles by not adding onPush handler at all if CSC is not used
169175 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
202178 }
203179 } ,
204180 getTypeMapping : ( ) => this . #getTypeMapping( )
205181 } ) ;
206182 }
207183
208- setInvalidateCallback ( callback ?: ( key : RedisArgument | null ) => unknown ) {
209- this . #invalidateCallback = callback ;
184+ addPushHandler ( handler : PushHandler ) : void {
185+ this . #pushHandlers . push ( handler ) ;
210186 }
211187
212188 async waitForInflightCommandsToComplete ( ) : Promise < void > {
0 commit comments