1
1
import RedisSocket , { RedisSocketOptions } from './socket' ;
2
2
import RedisCommandsQueue , { PubSubListener , PubSubSubscribeCommands , PubSubUnsubscribeCommands , QueueCommandOptions } from './commands-queue' ;
3
- import COMMANDS from './commands' ;
3
+ import COMMANDS , { TransformArgumentsReply } from './commands' ;
4
4
import { RedisCommand , RedisModules , RedisReply } from './commands' ;
5
5
import RedisMultiCommand , { MultiQueuedCommand , RedisMultiCommandType } from './multi-command' ;
6
6
import EventEmitter from 'events' ;
@@ -62,12 +62,10 @@ export default class RedisClient<M extends RedisModules = RedisModules, S extend
62
62
) : Promise < ReturnType < typeof command [ 'transformReply' ] > > {
63
63
const { args : redisArgs , options } = transformCommandArguments < ClientCommandOptions > ( command , args ) ;
64
64
65
- const reply = command . transformReply (
66
- await this . #sendCommand( redisArgs , options ) ,
67
- redisArgs . preserve
65
+ return command . transformReply (
66
+ await this . #sendCommand( redisArgs , options , command . BUFFER_MODE ) ,
67
+ redisArgs . preserve ,
68
68
) ;
69
-
70
- return reply ;
71
69
}
72
70
73
71
static async #scriptsExecutor(
@@ -77,12 +75,10 @@ export default class RedisClient<M extends RedisModules = RedisModules, S extend
77
75
) : Promise < typeof script [ 'transformArguments' ] > {
78
76
const { args : redisArgs , options } = transformCommandArguments < ClientCommandOptions > ( script , args ) ;
79
77
80
- const reply = script . transformReply (
81
- await this . executeScript ( script , redisArgs , options ) ,
78
+ return script . transformReply (
79
+ await this . executeScript ( script , redisArgs , options , script . BUFFER_MODE ) ,
82
80
redisArgs . preserve
83
81
) ;
84
-
85
- return reply ;
86
82
}
87
83
88
84
static create < M extends RedisModules , S extends RedisLuaScripts > ( options ?: RedisClientOptions < M , S > ) : RedisClientType < M , S > {
@@ -182,10 +178,7 @@ export default class RedisClient<M extends RedisModules = RedisModules, S extend
182
178
}
183
179
184
180
#initiateQueue( ) : RedisCommandsQueue {
185
- return new RedisCommandsQueue (
186
- this . #options?. commandsQueueMaxLength ,
187
- encodedCommands => this . #socket. write ( encodedCommands )
188
- ) ;
181
+ return new RedisCommandsQueue ( this . #options?. commandsQueueMaxLength ) ;
189
182
}
190
183
191
184
#legacyMode( ) : void {
@@ -299,54 +292,72 @@ export default class RedisClient<M extends RedisModules = RedisModules, S extend
299
292
300
293
QUIT ( ) : Promise < void > {
301
294
return this . #socket. quit ( ( ) => {
302
- const promise = this . #queue. addEncodedCommand ( encodeCommand ( [ 'QUIT' ] ) ) ;
295
+ const promise = this . #queue. addCommand ( [ 'QUIT' ] ) ;
303
296
this . #tick( ) ;
304
297
return promise ;
305
298
} ) ;
306
299
}
307
300
308
301
quit = this . QUIT ;
309
302
310
- sendCommand < T = unknown > ( args : Array < string > , options ?: ClientCommandOptions ) : Promise < T > {
311
- return this . #sendCommand( args , options ) ;
303
+ sendCommand < T = RedisReply > ( args : TransformArgumentsReply , options ?: ClientCommandOptions , bufferMode ?: boolean ) : Promise < T > {
304
+ return this . #sendCommand( args , options , bufferMode ) ;
312
305
}
313
306
314
307
// using `#sendCommand` cause `sendCommand` is overwritten in legacy mode
315
- #sendCommand< T = RedisReply > ( args : Array < string > , options ?: ClientCommandOptions ) : Promise < T > {
316
- return this . sendEncodedCommand ( encodeCommand ( args ) , options ) ;
317
- }
318
-
319
- async sendEncodedCommand < T = RedisReply > ( encodedCommand : string , options ?: ClientCommandOptions ) : Promise < T > {
308
+ async #sendCommand< T = RedisReply > ( args : TransformArgumentsReply , options ?: ClientCommandOptions , bufferMode ?: boolean ) : Promise < T > {
320
309
if ( ! this . #socket. isOpen ) {
321
310
throw new ClientClosedError ( ) ;
322
311
}
323
312
324
313
if ( options ?. isolated ) {
325
314
return this . executeIsolated ( isolatedClient =>
326
- isolatedClient . sendEncodedCommand ( encodedCommand , {
315
+ isolatedClient . sendCommand ( args , {
327
316
...options ,
328
317
isolated : false
329
318
} )
330
319
) ;
331
320
}
332
321
333
- const promise = this . #queue. addEncodedCommand < T > ( encodedCommand , options ) ;
322
+ const promise = this . #queue. addCommand < T > ( args , options , bufferMode ) ;
334
323
this . #tick( ) ;
335
324
return await promise ;
336
325
}
337
326
327
+ #tick( ) : void {
328
+ if ( ! this . #socket. isSocketExists ) {
329
+ return ;
330
+ }
331
+
332
+ this . #socket. cork ( ) ;
333
+
334
+ while ( true ) {
335
+ const args = this . #queue. getCommandToSend ( ) ;
336
+ if ( args === undefined ) break ;
337
+
338
+ let writeResult ;
339
+ for ( const toWrite of encodeCommand ( args ) ) {
340
+ writeResult = this . #socket. write ( toWrite ) ;
341
+ }
342
+
343
+ if ( ! writeResult ) {
344
+ break ;
345
+ }
346
+ }
347
+ }
348
+
338
349
executeIsolated < T > ( fn : ( client : RedisClientType < M , S > ) => T | Promise < T > ) : Promise < T > {
339
350
return this . #isolationPool. use ( fn ) ;
340
351
}
341
352
342
- async executeScript ( script : RedisLuaScript , args : Array < string > , options ?: ClientCommandOptions ) : Promise < ReturnType < typeof script [ 'transformReply' ] > > {
353
+ async executeScript ( script : RedisLuaScript , args : TransformArgumentsReply , options ?: ClientCommandOptions , bufferMode ?: boolean ) : Promise < ReturnType < typeof script [ 'transformReply' ] > > {
343
354
try {
344
355
return await this . #sendCommand( [
345
356
'EVALSHA' ,
346
357
script . SHA1 ,
347
358
script . NUMBER_OF_KEYS . toString ( ) ,
348
359
...args
349
- ] , options ) ;
360
+ ] , options , bufferMode ) ;
350
361
} catch ( err : any ) {
351
362
if ( ! err ?. message ?. startsWith ?.( 'NOSCRIPT' ) ) {
352
363
throw err ;
@@ -357,14 +368,14 @@ export default class RedisClient<M extends RedisModules = RedisModules, S extend
357
368
script . SCRIPT ,
358
369
script . NUMBER_OF_KEYS . toString ( ) ,
359
370
...args
360
- ] , options ) ;
371
+ ] , options , bufferMode ) ;
361
372
}
362
373
}
363
374
364
375
#multiExecutor( commands : Array < MultiQueuedCommand > , chainId ?: symbol ) : Promise < Array < RedisReply > > {
365
376
const promise = Promise . all (
366
- commands . map ( ( { encodedCommand } ) => {
367
- return this . #queue. addEncodedCommand ( encodedCommand , RedisClient . commandOptions ( {
377
+ commands . map ( ( { args } ) => {
378
+ return this . #queue. addCommand ( args , RedisClient . commandOptions ( {
368
379
chainId
369
380
} ) ) ;
370
381
} )
@@ -438,31 +449,6 @@ export default class RedisClient<M extends RedisModules = RedisModules, S extend
438
449
await this . #isolationPool. drain ( ) ;
439
450
await this . #isolationPool. clear ( ) ;
440
451
}
441
-
442
- #isTickQueued = false ;
443
-
444
- #tick( ) : void {
445
- const { chunkRecommendedSize} = this . #socket;
446
- if ( ! chunkRecommendedSize ) {
447
- return ;
448
- }
449
-
450
- if ( ! this . #isTickQueued && this . #queue. waitingToBeSentCommandsLength < chunkRecommendedSize ) {
451
- queueMicrotask ( ( ) => this . #tick( ) ) ;
452
- this . #isTickQueued = true ;
453
- return ;
454
- }
455
-
456
- const isBuffering = this . #queue. executeChunk ( chunkRecommendedSize ) ;
457
- if ( isBuffering === true ) {
458
- this . #socket. once ( 'drain' , ( ) => this . #tick( ) ) ;
459
- } else if ( isBuffering === false ) {
460
- this . #tick( ) ;
461
- return ;
462
- }
463
-
464
- this . #isTickQueued = false ;
465
- }
466
452
}
467
453
468
454
extendWithDefaultCommands ( RedisClient , RedisClient . commandsExecutor ) ;
0 commit comments