diff --git a/ldclient/impl/datasystem/fdv2.py b/ldclient/impl/datasystem/fdv2.py index b8229e6..3e2864c 100644 --- a/ldclient/impl/datasystem/fdv2.py +++ b/ldclient/impl/datasystem/fdv2.py @@ -130,6 +130,7 @@ def __init__(self, store: FeatureStore, store_update_sink: DataStoreStatusProvid self.__lock = ReadWriteLock() self.__last_available = True self.__poller: Optional[RepeatingTask] = None + self.__closed = False def init(self, all_data: Mapping[VersionedDataKind, Mapping[str, Dict[Any, Any]]]): return self.__wrapper(lambda: self.store.init(_FeatureStoreDataSetSorter.sort_all_collections(all_data))) @@ -164,6 +165,8 @@ def __update_availability(self, available: bool): task_to_start = None with self.__lock.write(): + if self.__closed: + return if available == self.__last_available: return @@ -229,6 +232,26 @@ def is_monitoring_enabled(self) -> bool: return monitoring_enabled() + def close(self): + """ + Close the wrapper and stop the repeating task poller if it's running. + Also forwards the close call to the underlying store if it has a close method. + """ + poller_to_stop = None + + with self.__lock.write(): + if self.__closed: + return + self.__closed = True + poller_to_stop = self.__poller + self.__poller = None + + if poller_to_stop is not None: + poller_to_stop.stop() + + if hasattr(self.store, "close"): + self.store.close() + class FDv2(DataSystem): """ diff --git a/ldclient/interfaces.py b/ldclient/interfaces.py index 7a030d3..29fd114 100644 --- a/ldclient/interfaces.py +++ b/ldclient/interfaces.py @@ -189,6 +189,28 @@ def initialized(self) -> bool: # :return: true if the underlying data store is reachable # """ + # WARN: This isn't a required method on a FeatureStore. The SDK will + # check if the provided store responds to this method, and if it does, + # will call it during shutdown to release any resources (such as database + # connections or connection pools) that the store may be using. + # + # @abstractmethod + # def close(self): + # """ + # Releases any resources used by the data store implementation. + # + # This method will be called by the SDK during shutdown to ensure proper + # cleanup of resources such as database connections, connection pools, + # network sockets, or other resources that should be explicitly released. + # + # Implementations should be idempotent - calling close() multiple times + # should be safe and have no additional effect after the first call. + # + # This is particularly important for persistent data stores that maintain + # connection pools or other long-lived resources that should be properly + # cleaned up when the SDK is shut down. + # """ + class FeatureStoreCore: """