1+ import { MaxRetriesPerRequestError } from 'ioredis/built/errors' ;
2+
13import { interfaces , LDLogger } from '@launchdarkly/node-server-sdk' ;
24
35import RedisClientState from './RedisClientState' ;
@@ -100,6 +102,50 @@ export default class RedisCore implements interfaces.PersistentDataStore {
100102 } ) ;
101103 }
102104
105+ #serializeItems( kind : any , itemsObj : Record < string , any > ) {
106+ const serializedItemsObj : Record < string , any > = { } ;
107+ Object . keys ( itemsObj ) . forEach ( ( key ) => {
108+ const value = itemsObj [ key ] ;
109+ serializedItemsObj [ key ] = kind . serialize ( value ) . serializedItem ;
110+ } ) ;
111+ return serializedItemsObj ;
112+ }
113+
114+ #prepareArray( values : Record < string , string > ) {
115+ const results : interfaces . KeyedItem < string , interfaces . SerializedItemDescriptor > [ ] = [ ] ;
116+ Object . keys ( values ) . forEach ( ( key ) => {
117+ const value = values [ key ] ;
118+ // When getting we do not populate version and deleted.
119+ // The SDK will have to deserialize to access these values.
120+ results . push ( { key, item : { version : 0 , deleted : false , serializedItem : value } } ) ;
121+ } ) ;
122+ return results ;
123+ }
124+
125+ #useItemsFromCodefresh(
126+ kind : interfaces . PersistentStoreDataKind ,
127+ callback : (
128+ descriptors : interfaces . KeyedItem < string , interfaces . SerializedItemDescriptor > [ ] | undefined ,
129+ ) => void ,
130+ ) {
131+ this . localFeatureStore ( ) . then (
132+ ( items : any ) => {
133+ let localResults ;
134+ if ( kind . namespace === 'features' ) {
135+ localResults = items . features ;
136+ } else {
137+ localResults = items . segments ;
138+ }
139+ const serializedItems = this . #serializeItems( kind , localResults ) ;
140+ callback ( this . #prepareArray( serializedItems ) ) ;
141+ } ,
142+ ( error : any ) => {
143+ console . log ( error ) ;
144+ callback ( undefined ) ;
145+ } ,
146+ ) ;
147+ }
148+
103149 getAll (
104150 kind : interfaces . PersistentStoreDataKind ,
105151 callback : (
@@ -108,35 +154,17 @@ export default class RedisCore implements interfaces.PersistentDataStore {
108154 ) : void {
109155 if ( ! this . state . isConnected ( ) && ! this . state . isInitialConnection ( ) ) {
110156 this . logger ?. warn ( 'Attempted to fetch all keys while Redis connection is down' ) ;
111- this . localFeatureStore ( ) . then (
112- ( items : any ) => {
113- let localResults = { } ;
114- if ( kind . namespace === 'features' ) {
115- localResults = items . features ;
116- } else {
117- localResults = items . segments ;
118- }
119- callback ( localResults as any ) ;
120- } ,
121- ( err : any ) => {
122- console . log ( err ) ;
123- callback ( undefined ) ;
124- } ,
125- ) ;
157+ this . #useItemsFromCodefresh( kind , callback ) ;
126158 }
127159
128160 this . state . getClient ( ) . hgetall ( this . state . prefixedKey ( kind . namespace ) , ( err , values ) => {
129161 if ( err ) {
130162 this . logger ?. error ( `Error fetching '${ kind . namespace } ' from Redis ${ err } ` ) ;
163+ if ( err instanceof MaxRetriesPerRequestError ) {
164+ this . #useItemsFromCodefresh( kind , callback ) ;
165+ }
131166 } else if ( values ) {
132- const results : interfaces . KeyedItem < string , interfaces . SerializedItemDescriptor > [ ] = [ ] ;
133- Object . keys ( values ) . forEach ( ( key ) => {
134- const value = values [ key ] ;
135- // When getting we do not populate version and deleted.
136- // The SDK will have to deserialize to access these values.
137- results . push ( { key, item : { version : 0 , deleted : false , serializedItem : value } } ) ;
138- } ) ;
139- callback ( results ) ;
167+ callback ( this . #prepareArray( values ) ) ;
140168 } else {
141169 callback ( undefined ) ;
142170 }
0 commit comments