@@ -34,6 +34,7 @@ export const hgetallAsync = client.hGetAll.bind(client)
3434export const hmgetAsync = client . hmGet . bind ( client )
3535export const existsAsync = client . exists . bind ( client )
3636export const delAsync = client . del . bind ( client )
37+ export const renameAsync = client . rename . bind ( client )
3738// Set type to `any` to avoid the TS4023 error
3839export const setAsync : any = client . set . bind ( client )
3940export const getAsync : any = client . get . bind ( client )
@@ -176,24 +177,50 @@ const syncedCurrencyCodeMaps = syncedDocument(
176177 asCurrencyCodeMaps
177178)
178179
179- syncedCurrencyCodeMaps . onChange ( currencyCodeMaps => {
180- logger ( 'Syncing currency code maps with redis cache...' )
181- for ( const key of Object . keys ( currencyCodeMaps ) ) {
182- delAsync ( key )
183- . then ( ( ) => {
180+ // Only run sync in background engine processes, not web server instances
181+ if ( process . env . ENABLE_BACKGROUND_SYNC !== 'false' ) {
182+ syncedCurrencyCodeMaps . onChange ( currencyCodeMaps => {
183+ const timestamp = new Date ( ) . toISOString ( )
184+ logger (
185+ `[${ timestamp } ] SYNC TRIGGERED: Syncing currency code maps with redis cache...`
186+ )
187+ logger (
188+ `[${ timestamp } ] SYNC TRIGGER: onChange fired for currencyCodeMaps document (PID: ${ process . pid } )`
189+ )
190+ for ( const key of Object . keys ( currencyCodeMaps ) ) {
191+ const tempKey = `${ key } _temp_${ Date . now ( ) } `
192+
193+ // Write to temporary key first, then atomically rename
194+ const writeToTemp = async ( ) : Promise < void > => {
184195 if ( Array . isArray ( currencyCodeMaps [ key ] ) ) {
185- hsetAsync ( key , Object . assign ( { } , currencyCodeMaps [ key ] ) ) . catch ( e =>
186- logger ( 'syncedCurrencyCodeMaps failed to update' , key , e )
187- )
196+ await hsetAsync ( tempKey , Object . assign ( { } , currencyCodeMaps [ key ] ) )
188197 } else {
189- hsetAsync ( key , currencyCodeMaps [ key ] ) . catch ( e =>
190- logger ( 'syncedCurrencyCodeMaps failed to update' , key , e )
191- )
198+ await hsetAsync ( tempKey , currencyCodeMaps [ key ] )
192199 }
193- } )
194- . catch ( e => logger ( 'syncedCurrencyCodeMaps delete failed' , key , e ) )
195- }
196- } )
200+ }
201+
202+ const updateKey = async ( ) : Promise < void > => {
203+ try {
204+ await writeToTemp ( )
205+ // Atomically replace the old key with the new data
206+ await renameAsync ( tempKey , key )
207+ logger ( `Successfully updated Redis key: ${ key } ` )
208+ } catch ( e ) {
209+ logger ( 'syncedCurrencyCodeMaps failed to update' , key , e )
210+ // Clean up temporary key on failure
211+ try {
212+ await delAsync ( tempKey )
213+ } catch ( cleanupError ) {
214+ logger ( 'Failed to cleanup temp key' , tempKey , cleanupError )
215+ }
216+ }
217+ }
218+
219+ // Fire and forget - don't await in the callback
220+ updateKey ( ) . catch ( e => logger ( 'Unhandled error in updateKey' , key , e ) )
221+ }
222+ } )
223+ }
197224
198225export const ratesDbSetup = {
199226 name : 'db_rates' ,
0 commit comments