From 9eab4f206d85e8a7f1d9e12f19c63765fa591efa Mon Sep 17 00:00:00 2001 From: Matt Lyons Date: Fri, 6 Oct 2023 12:22:27 -0500 Subject: [PATCH] Fix network object sharing race condition within the same process --- src/shared/services/network-object.service.ts | 18 +++++++++++++----- 1 file changed, 13 insertions(+), 5 deletions(-) diff --git a/src/shared/services/network-object.service.ts b/src/shared/services/network-object.service.ts index f0c2f721cc..a484dc103e 100644 --- a/src/shared/services/network-object.service.ts +++ b/src/shared/services/network-object.service.ts @@ -160,7 +160,8 @@ class MutexMap { } } -const mutexMap: MutexMap = new MutexMap(); +const getterMutexMap: MutexMap = new MutexMap(); +const setterMutexMap: MutexMap = new MutexMap(); /** This proxy enables calling functions on a network object that exists in a different process */ const createRemoteProxy = ( @@ -287,8 +288,8 @@ const get = async ( ): Promise | undefined> => { await initialize(); - // Don't allow simultaneous gets and/or sets to run for the same network object - const lock: Mutex = mutexMap.get(id); + // Don't allow simultaneous gets to run for the same network object + const lock: Mutex = getterMutexMap.get(id); return lock.runExclusive(async () => { // If we already have this network object, return it const networkObjectRegistration = networkObjectRegistrations.get(id); @@ -299,6 +300,13 @@ const get = async ( const networkObjectFunctions = await getRemoteNetworkObjectFunctions(id); if (!networkObjectFunctions) return undefined; + // Before we create a remote proxy, see if there was a race condition for a local proxy. + // It is possible we called `get`, then while awaiting the network response something else in + // this process called `set` on the object we were looking for. + const networkObjectRegistrationSecondChance = networkObjectRegistrations.get(id); + if (networkObjectRegistrationSecondChance) + return networkObjectRegistrationSecondChance.networkObject as NetworkObject; + // At this point, the object exists remotely but does not yet exist locally. // The base object created below might need a reference to the final network object. Since the @@ -363,8 +371,8 @@ const set = async ( ): Promise> => { await initialize(); - // Don't allow simultaneous gets and/or sets to run for the same network object - const lock: Mutex = mutexMap.get(id); + // Don't allow simultaneous sets to run for the same network object + const lock: Mutex = setterMutexMap.get(id); return lock.runExclusive(async () => { // Check to see if we already know there is a network object with this id. if (hasKnown(id)) throw new Error(`Network object with id ${id} is already registered`);