From c66ecf200666601944cb2efd2f94c6b65778cda0 Mon Sep 17 00:00:00 2001 From: "christian.lutnik" Date: Fri, 16 Jan 2026 10:19:14 +0100 Subject: [PATCH] Use time.monotonic to avoid endless loop when using time machine Signed-off-by: christian.lutnik --- providers/openfeature-provider-flagd/pyproject.toml | 2 +- .../openfeature/contrib/provider/flagd/resolvers/grpc.py | 7 ++----- .../flagd/resolvers/process/connector/grpc_watcher.py | 7 ++----- 3 files changed, 5 insertions(+), 11 deletions(-) diff --git a/providers/openfeature-provider-flagd/pyproject.toml b/providers/openfeature-provider-flagd/pyproject.toml index c46d27b3..97456e11 100644 --- a/providers/openfeature-provider-flagd/pyproject.toml +++ b/providers/openfeature-provider-flagd/pyproject.toml @@ -18,7 +18,7 @@ classifiers = [ keywords = [] dependencies = [ "openfeature-sdk>=0.8.2", - "grpcio>=1.68.1", + "grpcio>=1.76.0", "protobuf>=6.30.0,<7.0.0", "mmh3>=5.0.0,<6.0.0", "panzi-json-logic>=1.0.1", diff --git a/providers/openfeature-provider-flagd/src/openfeature/contrib/provider/flagd/resolvers/grpc.py b/providers/openfeature-provider-flagd/src/openfeature/contrib/provider/flagd/resolvers/grpc.py index 13c2c013..4a9dab8e 100644 --- a/providers/openfeature-provider-flagd/src/openfeature/contrib/provider/flagd/resolvers/grpc.py +++ b/providers/openfeature-provider-flagd/src/openfeature/contrib/provider/flagd/resolvers/grpc.py @@ -72,8 +72,6 @@ def __init__( self.thread: typing.Optional[threading.Thread] = None self.timer: typing.Optional[threading.Timer] = None - self.start_time = time.time() - def _generate_channel(self, config: Config) -> grpc.Channel: target = f"{config.host}:{config.port}" # Create the channel with the service config @@ -163,8 +161,8 @@ def connect(self) -> None: ) self.monitor_thread.start() ## block until ready or deadline reached - timeout = self.deadline + time.time() - while not self.connected and time.time() < timeout: + timeout = self.deadline + time.monotonic() + while not self.connected and time.monotonic() < timeout: time.sleep(0.05) logger.debug("Finished blocking gRPC state initialization") @@ -201,7 +199,6 @@ def _state_change_callback(self, new_state: ChannelConnectivity) -> None: message="gRPC sync disconnected, reconnecting", ) ) - self.start_time = time.time() # adding a timer, so we can emit the error event after time self.timer = threading.Timer(self.retry_grace_period, self.emit_error) diff --git a/providers/openfeature-provider-flagd/src/openfeature/contrib/provider/flagd/resolvers/process/connector/grpc_watcher.py b/providers/openfeature-provider-flagd/src/openfeature/contrib/provider/flagd/resolvers/process/connector/grpc_watcher.py index 15cdfc06..e557466f 100644 --- a/providers/openfeature-provider-flagd/src/openfeature/contrib/provider/flagd/resolvers/process/connector/grpc_watcher.py +++ b/providers/openfeature-provider-flagd/src/openfeature/contrib/provider/flagd/resolvers/process/connector/grpc_watcher.py @@ -53,8 +53,6 @@ def __init__( self.thread: typing.Optional[threading.Thread] = None self.timer: typing.Optional[threading.Timer] = None - self.start_time = time.time() - def _generate_channel(self, config: Config) -> grpc.Channel: target = f"{config.host}:{config.port}" # Create the channel with the service config @@ -144,8 +142,8 @@ def connect(self) -> None: ) self.monitor_thread.start() ## block until ready or deadline reached - timeout = self.deadline + time.time() - while not self.connected and time.time() < timeout: + timeout = self.deadline + time.monotonic() + while not self.connected and time.monotonic() < timeout: time.sleep(0.05) logger.debug("Finished blocking gRPC state initialization") @@ -182,7 +180,6 @@ def _state_change_callback(self, new_state: grpc.ChannelConnectivity) -> None: message="gRPC sync disconnected, reconnecting", ) ) - self.start_time = time.time() # adding a timer, so we can emit the error event after time self.timer = threading.Timer(self.retry_grace_period, self.emit_error)