Skip to content

Commit 31cf487

Browse files
authored
fix: Address potential race condition in FeatureStore update_availability (#391)
1 parent 81db4fb commit 31cf487

File tree

1 file changed

+21
-19
lines changed

1 file changed

+21
-19
lines changed

ldclient/impl/datasystem/fdv2.py

Lines changed: 21 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -170,38 +170,40 @@ def __wrapper(self, fn: Callable):
170170
raise
171171

172172
def __update_availability(self, available: bool):
173+
state_changed = False
174+
poller_to_stop = None
175+
task_to_start = None
176+
177+
self.__lock.lock()
173178
try:
174-
self.__lock.lock()
175179
if available == self.__last_available:
176180
return
181+
182+
state_changed = True
177183
self.__last_available = available
184+
185+
if available:
186+
poller_to_stop = self.__poller
187+
self.__poller = None
188+
elif self.__poller is None:
189+
task_to_start = RepeatingTask("ldclient.check-availability", 0.5, 0, self.__check_availability)
190+
self.__poller = task_to_start
178191
finally:
179192
self.__lock.unlock()
180193

181194
if available:
182195
log.warning("Persistent store is available again")
196+
else:
197+
log.warning("Detected persistent store unavailability; updates will be cached until it recovers")
183198

184199
status = DataStoreStatus(available, True)
185200
self.__store_update_sink.update_status(status)
186201

187-
if available:
188-
try:
189-
self.__lock.lock()
190-
if self.__poller is not None:
191-
self.__poller.stop()
192-
self.__poller = None
193-
finally:
194-
self.__lock.unlock()
195-
196-
return
202+
if poller_to_stop is not None:
203+
poller_to_stop.stop()
197204

198-
log.warning("Detected persistent store unavailability; updates will be cached until it recovers")
199-
task = RepeatingTask("ldclient.check-availability", 0.5, 0, self.__check_availability)
200-
201-
self.__lock.lock()
202-
self.__poller = task
203-
self.__poller.start()
204-
self.__lock.unlock()
205+
if task_to_start is not None:
206+
task_to_start.start()
205207

206208
def __check_availability(self):
207209
try:
@@ -487,7 +489,7 @@ def synchronizer_loop(self: 'FDv2'):
487489

488490
log.info("Recovery condition met, returning to primary synchronizer")
489491
except Exception as e:
490-
log.error("Failed to build primary synchronizer: %s", e)
492+
log.error("Failed to build synchronizer: %s", e)
491493
break
492494

493495
except Exception as e:

0 commit comments

Comments
 (0)