@@ -25,19 +25,35 @@ let exportClient: RedisSB = {
25
25
quit : ( ) => new Promise ( ( resolve ) => resolve ( null ) ) ,
26
26
} ;
27
27
28
+ let lastClientFail = 0 ;
29
+ let lastReadFail = 0 ;
30
+
28
31
if ( config . redis ?. enabled ) {
29
32
Logger . info ( "Connected to redis" ) ;
30
33
const client = createClient ( config . redis ) ;
34
+ const readClient = config . redisRead ?. enabled ? createClient ( config . redisRead ) : null ;
31
35
void client . connect ( ) ; // void as we don't care about the promise
36
+ void readClient ?. connect ( ) ;
32
37
exportClient = client as RedisSB ;
33
38
39
+
34
40
const get = client . get . bind ( client ) ;
41
+ const getRead = readClient ?. get ?. bind ( readClient ) ;
35
42
exportClient . get = ( key ) => new Promise ( ( resolve , reject ) => {
36
43
const timeout = config . redis . getTimeout ? setTimeout ( ( ) => reject ( ) , config . redis . getTimeout ) : null ;
37
- get ( key ) . then ( ( reply ) => {
44
+ const chosenGet = pickChoice ( get , getRead ) ;
45
+ chosenGet ( key ) . then ( ( reply ) => {
38
46
if ( timeout !== null ) clearTimeout ( timeout ) ;
39
47
resolve ( reply ) ;
40
- } ) . catch ( ( err ) => reject ( err ) ) ;
48
+ } ) . catch ( ( err ) => {
49
+ if ( chosenGet === get ) {
50
+ lastClientFail = Date . now ( ) ;
51
+ } else {
52
+ lastReadFail = Date . now ( ) ;
53
+ }
54
+
55
+ reject ( err ) ;
56
+ } ) ;
41
57
} ) ;
42
58
exportClient . increment = ( key ) => new Promise ( ( resolve , reject ) =>
43
59
void client . multi ( )
@@ -48,11 +64,31 @@ if (config.redis?.enabled) {
48
64
. catch ( ( err ) => reject ( err ) )
49
65
) ;
50
66
client . on ( "error" , function ( error ) {
67
+ lastClientFail = Date . now ( ) ;
51
68
Logger . error ( `Redis Error: ${ error } ` ) ;
52
69
} ) ;
53
70
client . on ( "reconnect" , ( ) => {
54
71
Logger . info ( "Redis: trying to reconnect" ) ;
55
72
} ) ;
73
+ readClient ?. on ( "error" , function ( error ) {
74
+ lastReadFail = Date . now ( ) ;
75
+ Logger . error ( `Redis Read-Only Error: ${ error } ` ) ;
76
+ } ) ;
77
+ readClient ?. on ( "reconnect" , ( ) => {
78
+ Logger . info ( "Redis Read-Only: trying to reconnect" ) ;
79
+ } ) ;
80
+ }
81
+
82
+ function pickChoice < T > ( client : T , readClient : T ) : T {
83
+ const readAvailable = ! ! readClient ;
84
+ const ignoreReadDueToFailure = lastReadFail > Date . now ( ) - 1000 * 30 ;
85
+ const readDueToFailure = lastClientFail > Date . now ( ) - 1000 * 30 ;
86
+ if ( readAvailable && ! ignoreReadDueToFailure && ( readDueToFailure ||
87
+ Math . random ( ) > 1 / ( config . redisRead ?. weight + 1 ) ) ) {
88
+ return readClient ;
89
+ } else {
90
+ return client ;
91
+ }
56
92
}
57
93
58
94
export default exportClient ;
0 commit comments