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 59b86e2a..e4f69dd7 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 @@ def __init__( # noqa: PLR0913 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 @@ def __init__( # noqa: PLR0913 ) 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 59bad1c3..3fb23744 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 @@ def __init__( # noqa: PLR0913 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 @@ def __init__( # noqa: PLR0913 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 7b611dd4..66429666 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 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 @@ def shutdown(self) -> None: self.active = False self.channel.close() + 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 = {} - 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 + 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)