@@ -7,7 +7,7 @@ import { RedisArgument, RedisFunctions, RedisModules, RedisScripts, RespVersions
77import calculateSlot from 'cluster-key-slot' ;
88import { RedisSocketOptions } from '../client/socket' ;
99import { BasicPooledClientSideCache , PooledClientSideCacheProvider } from '../client/cache' ;
10- import { SMIGRATED_EVENT , dbgMaintenance } from '../client/enterprise-maintenance-manager' ;
10+ import { SMIGRATED_EVENT , SMigratedEvent , dbgMaintenance } from '../client/enterprise-maintenance-manager' ;
1111
1212interface NodeAddress {
1313 host : string ;
@@ -114,7 +114,6 @@ export default class RedisClusterSlots<
114114 readonly nodeByAddress = new Map < string , MasterNode < M , F , S , RESP , TYPE_MAPPING > | ShardNode < M , F , S , RESP , TYPE_MAPPING > > ( ) ;
115115 pubSubNode ?: PubSubNode < M , F , S , RESP , TYPE_MAPPING > ;
116116 clientSideCache ?: PooledClientSideCacheProvider ;
117- smigratedSequenceIdsSeen = new Set < number > ( ) ;
118117
119118 #isOpen = false ;
120119
@@ -254,15 +253,74 @@ export default class RedisClusterSlots<
254253 }
255254 }
256255
257- #handleSmigrated = async ( sequenceId : number ) => {
258- dbgMaintenance ( `[CLUSTER_SLOTS]: handle smigrated` )
259- if ( this . smigratedSequenceIdsSeen . has ( sequenceId ) ) {
260- dbgMaintenance ( `[CLUSTER_SLOTS]: smigrated sequence id ${ sequenceId } already seen, skipping rediscovery` ) ;
256+ #handleSmigrated = async ( event : SMigratedEvent ) => {
257+ dbgMaintenance ( `[CSlots]: handle smigrated` , event ) ;
258+
259+ // slots = new Array<Shard<M, F, S, RESP, TYPE_MAPPING>>(RedisClusterSlots.#SLOTS);
260+ // masters = new Array<MasterNode<M, F, S, RESP, TYPE_MAPPING>>();
261+ // replicas = new Array<ShardNode<M, F, S, RESP, TYPE_MAPPING>>();
262+ // readonly nodeByAddress = new Map<string, MasterNode<M, F, S, RESP, TYPE_MAPPING> | ShardNode<M, F, S, RESP, TYPE_MAPPING>>();
263+ // pubSubNode?: PubSubNode<M, F, S, RESP, TYPE_MAPPING>;
264+
265+ const sourceAddress = `${ event . source . host } :${ event . source . port } ` ;
266+ const sourceNode = this . nodeByAddress . get ( sourceAddress ) ;
267+ if ( ! sourceNode ) {
268+ dbgMaintenance ( `[CSlots]: address ${ sourceAddress } not in 'nodeByAddress', abort SMIGRATED handling` ) ;
269+ return ;
270+ }
271+
272+ // 1. Pausing
273+ //TODO - check the single pubsubnode
274+ sourceNode . client ?. _pause ( ) ;
275+ if ( 'pubSub' in sourceNode ) {
276+ sourceNode . pubSub ?. client . _pause ( ) ;
277+ }
278+
279+ const destinationAddress = `${ event . destination . host } :${ event . destination . port } ` ;
280+ let destinationNode = this . nodeByAddress . get ( destinationAddress ) ;
281+ let destinationShard : Shard < M , F , S , RESP , TYPE_MAPPING > ;
282+
283+ // 2. Create new Master
284+ if ( ! destinationNode ) {
285+ const promises : Promise < unknown > [ ] = [ ] ;
286+ destinationNode = this . #initiateSlotNode( { host : event . destination . host , port : event . destination . port , id : 'asdff' } , false , true , new Set ( ) , promises ) ;
287+ await Promise . all ( promises ) ;
288+ // 2.1 Pause
289+ destinationNode . client ?. _pause ( ) ;
290+ // In case destination node didnt exist, this means Shard didnt exist as well, so creating a new Shard is completely fine
291+ destinationShard = {
292+ master : destinationNode
293+ } ;
261294 } else {
262- dbgMaintenance ( `[CLUSTER_SLOTS]: smigrated sequence id ${ sequenceId } is new, triggering rediscovery` ) ;
263- this . smigratedSequenceIdsSeen . add ( sequenceId ) ;
264- await this . #discoverWithRootNodes( )
295+ // In case destination node existed, this means there was a Shard already, so its best if we can find it.
296+ const existingShard = this . slots . find ( shard => shard . master . host === event . destination . host && shard . master . port === event . destination . port ) ;
297+ if ( ! existingShard ) {
298+ dbgMaintenance ( "Could not find shard" ) ;
299+ throw new Error ( 'Could not find shard' ) ;
300+ }
301+ destinationShard = existingShard ;
265302 }
303+
304+ // 3. Soft update shards
305+ for ( const range of event . ranges ) {
306+ if ( typeof range === 'number' ) {
307+ this . slots [ range ] = destinationShard ;
308+ } else {
309+ for ( let slot = range [ 0 ] ; slot <= range [ 1 ] ; slot ++ ) {
310+ this . slots [ slot ] = destinationShard ;
311+ }
312+ }
313+ }
314+
315+ // 4. For all affected clients (normal, pubsub, spubsub):
316+ // 4.1 Wait for inflight commands to complete
317+ // 4.2 Extract commands, channels, sharded channels
318+ // 4.3 Kill if no slots are pointing to it
319+ //
320+
321+ // 5. Prepend extracted commands, chans
322+ // 5.1 Unpause
323+
266324 }
267325
268326 async #getShards( rootNode : RedisClusterClientOptions ) {
0 commit comments