diff --git a/providers/openfeature-provider-flagd/src/openfeature/contrib/provider/flagd/config.py b/providers/openfeature-provider-flagd/src/openfeature/contrib/provider/flagd/config.py index 59b86e2..e4f69dd 100644 --- a/providers/openfeature-provider-flagd/src/openfeature/contrib/provider/flagd/config.py +++ b/providers/openfeature-provider-flagd/src/openfeature/contrib/provider/flagd/config.py @@ -100,6 +100,7 @@ class Config: cert_path: typing.Optional[str] = None, default_authority: typing.Optional[str] = None, channel_credentials: typing.Optional[grpc.ChannelCredentials] = None, + sync_metadata_disabled: typing.Optional[bool] = None, ): self.host = env_or_default(ENV_VAR_HOST, DEFAULT_HOST) if host is None else host @@ -248,3 +249,11 @@ class Config: ) self.channel_credentials = channel_credentials + + # TODO: remove the metadata call entirely after https://github.com/open-feature/flagd/issues/1584 + # This is a temporary stop-gap solutions to support servers that don't implement sync.GetMetadata + # (see: https://buf.build/open-feature/flagd/docs/main:flagd.sync.v1#flagd.sync.v1.FlagSyncService.GetMetadata). + # Using this option disables call to sync.GetMetadata + # Disabling will prevent static context from flagd being used in evaluations. + # GetMetadata and this option will be removed. + self.sync_metadata_disabled = sync_metadata_disabled diff --git a/providers/openfeature-provider-flagd/src/openfeature/contrib/provider/flagd/provider.py b/providers/openfeature-provider-flagd/src/openfeature/contrib/provider/flagd/provider.py index 59bad1c..3fb2374 100644 --- a/providers/openfeature-provider-flagd/src/openfeature/contrib/provider/flagd/provider.py +++ b/providers/openfeature-provider-flagd/src/openfeature/contrib/provider/flagd/provider.py @@ -64,6 +64,7 @@ class FlagdProvider(AbstractProvider): cert_path: typing.Optional[str] = None, default_authority: typing.Optional[str] = None, channel_credentials: typing.Optional[grpc.ChannelCredentials] = None, + sync_metadata_disabled: typing.Optional[bool] = None, ): """ Create an instance of the FlagdProvider @@ -106,6 +107,7 @@ class FlagdProvider(AbstractProvider): cert_path=cert_path, default_authority=default_authority, channel_credentials=channel_credentials, + sync_metadata_disabled=sync_metadata_disabled, ) self.enriched_context: dict = {} 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 7b611dd..6642966 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 @@ -6,6 +6,7 @@ import typing import grpc from google.protobuf.json_format import MessageToDict +from google.protobuf.struct_pb2 import Struct from openfeature.evaluation_context import EvaluationContext from openfeature.event import ProviderEventDetails @@ -162,24 +163,36 @@ class GrpcWatcher(FlagStateConnector): self.active = False self.channel.close() - def listen(self) -> None: - call_args = ( - {"timeout": self.streamline_deadline_seconds} - if self.streamline_deadline_seconds > 0 - else {} - ) + def _create_request_args(self) -> dict: request_args = {} if self.selector is not None: request_args["selector"] = self.selector if self.provider_id is not None: request_args["provider_id"] = self.provider_id + return request_args + + def listen(self) -> None: + call_args = ( + {"timeout": self.streamline_deadline_seconds} + if self.streamline_deadline_seconds > 0 + else {} + ) + request_args = self._create_request_args() + while self.active: try: - context_values_request = sync_pb2.GetMetadataRequest() - context_values_response: sync_pb2.GetMetadataResponse = ( - self.stub.GetMetadata(context_values_request, wait_for_ready=True) - ) + context_values_response: sync_pb2.GetMetadataResponse + if self.config.sync_metadata_disabled: + context_values_response = sync_pb2.GetMetadataResponse( + metadata=Struct() + ) + else: + context_values_request = sync_pb2.GetMetadataRequest() + context_values_response = self.stub.GetMetadata( + context_values_request, wait_for_ready=True + ) + context_values = MessageToDict(context_values_response) request = sync_pb2.SyncFlagsRequest(**request_args)