From dba8d509ffcce7601201ec8b464e58d4db52fdca Mon Sep 17 00:00:00 2001 From: Mridul Tailor Date: Wed, 18 Feb 2026 22:46:59 -0700 Subject: [PATCH 1/3] fix(flagd): use FLAGD_SYNC_PORT for in-process provider with backwards compatibility MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - Add ENV_VAR_SYNC_PORT constant for FLAGD_SYNC_PORT - Update port resolution: FLAGD_SYNC_PORT → FLAGD_PORT → default for in-process mode - Keep RPC mode using FLAGD_PORT only - Add 5 new tests covering sync port usage, fallback, priority, and RPC isolation - Update README documentation to reflect new environment variable Fixes #318 Signed-off-by: Mridul Tailor --- .../openfeature-provider-flagd/README.md | 2 +- .../contrib/provider/flagd/config.py | 35 +++++++----- .../tests/test_config.py | 54 +++++++++++++++++++ 3 files changed, 78 insertions(+), 13 deletions(-) diff --git a/providers/openfeature-provider-flagd/README.md b/providers/openfeature-provider-flagd/README.md index 9cbb865e..23520274 100644 --- a/providers/openfeature-provider-flagd/README.md +++ b/providers/openfeature-provider-flagd/README.md @@ -81,7 +81,7 @@ The default options can be defined in the FlagdProvider constructor. |--------------------------|--------------------------------|----------------------------|-------------------------------|---------------------| | resolver_type | FLAGD_RESOLVER | enum - `rpc`, `in-process` | rpc | | | host | FLAGD_HOST | str | localhost | rpc & in-process | -| port | FLAGD_PORT | int | 8013 (rpc), 8015 (in-process) | rpc & in-process | +| port | FLAGD_SYNC_PORT (in-process), FLAGD_PORT (rpc or fallback) | int | 8013 (rpc), 8015 (in-process) | rpc & in-process | | tls | FLAGD_TLS | bool | false | rpc & in-process | | cert_path | FLAGD_SERVER_CERT_PATH | String | null | rpc & in-process | | deadline | FLAGD_DEADLINE_MS | int | 500 | rpc & in-process | 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 2a21ba36..d5aebc6e 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 @@ -42,6 +42,7 @@ class CacheType(Enum): ENV_VAR_OFFLINE_FLAG_SOURCE_PATH = "FLAGD_OFFLINE_FLAG_SOURCE_PATH" ENV_VAR_OFFLINE_POLL_MS = "FLAGD_OFFLINE_POLL_MS" ENV_VAR_PORT = "FLAGD_PORT" +ENV_VAR_SYNC_PORT = "FLAGD_SYNC_PORT" ENV_VAR_RESOLVER_TYPE = "FLAGD_RESOLVER" ENV_VAR_RETRY_BACKOFF_MS = "FLAGD_RETRY_BACKOFF_MS" ENV_VAR_RETRY_BACKOFF_MAX_MS = "FLAGD_RETRY_BACKOFF_MAX_MS" @@ -79,7 +80,7 @@ def env_or_default( @dataclasses.dataclass class Config: - def __init__( # noqa: PLR0913 + def __init__( # noqa: PLR0913, PLR0915 self, host: typing.Optional[str] = None, port: typing.Optional[int] = None, @@ -149,17 +150,27 @@ def __init__( # noqa: PLR0913 else resolver ) - default_port = ( - DEFAULT_PORT_RPC - if self.resolver is ResolverType.RPC - else DEFAULT_PORT_IN_PROCESS - ) - - self.port: int = ( - int(env_or_default(ENV_VAR_PORT, default_port, cast=int)) - if port is None - else port - ) + # Port configuration with FLAGD_SYNC_PORT support for in-process mode + if port is None: + if self.resolver is ResolverType.IN_PROCESS: + # For in-process: try FLAGD_SYNC_PORT first, then FLAGD_PORT (backwards compatibility), then default + sync_port_env = os.environ.get(ENV_VAR_SYNC_PORT) + if sync_port_env is not None: + self.port = int(sync_port_env) + else: + port_env = os.environ.get(ENV_VAR_PORT) + self.port = ( + int(port_env) + if port_env is not None + else DEFAULT_PORT_IN_PROCESS + ) + else: + # For RPC: use FLAGD_PORT only + self.port = int( + env_or_default(ENV_VAR_PORT, DEFAULT_PORT_RPC, cast=int) + ) + else: + self.port = port self.offline_flag_source_path = ( env_or_default( diff --git a/providers/openfeature-provider-flagd/tests/test_config.py b/providers/openfeature-provider-flagd/tests/test_config.py index 510009d0..a671f8c1 100644 --- a/providers/openfeature-provider-flagd/tests/test_config.py +++ b/providers/openfeature-provider-flagd/tests/test_config.py @@ -23,6 +23,7 @@ ENV_VAR_PORT, ENV_VAR_RETRY_BACKOFF_MS, ENV_VAR_STREAM_DEADLINE_MS, + ENV_VAR_SYNC_PORT, ENV_VAR_TLS, CacheType, Config, @@ -147,3 +148,56 @@ def test_uses_arguments_over_environments_and_defaults(monkeypatch, resolver_typ assert config.retry_backoff_ms == retry_backoff assert config.stream_deadline_ms == stream_deadline assert config.tls is tls + + +def test_in_process_uses_sync_port(monkeypatch): + """Test that FLAGD_SYNC_PORT is used for in-process mode when set.""" + sync_port = 9999 + monkeypatch.setenv(ENV_VAR_SYNC_PORT, str(sync_port)) + + config = Config(resolver=ResolverType.IN_PROCESS) + assert config.port == sync_port + assert config.resolver == ResolverType.IN_PROCESS + + +def test_in_process_fallback_to_port(monkeypatch): + """Test that FLAGD_PORT is used as fallback when FLAGD_SYNC_PORT is not set.""" + port = 7777 + monkeypatch.setenv(ENV_VAR_PORT, str(port)) + + config = Config(resolver=ResolverType.IN_PROCESS) + assert config.port == port + assert config.resolver == ResolverType.IN_PROCESS + + +def test_in_process_sync_port_priority(monkeypatch): + """Test that FLAGD_SYNC_PORT takes priority over FLAGD_PORT when both are set.""" + sync_port = 9999 + port = 7777 + monkeypatch.setenv(ENV_VAR_SYNC_PORT, str(sync_port)) + monkeypatch.setenv(ENV_VAR_PORT, str(port)) + + config = Config(resolver=ResolverType.IN_PROCESS) + assert config.port == sync_port # FLAGD_SYNC_PORT should win + assert config.resolver == ResolverType.IN_PROCESS + + +def test_rpc_ignores_sync_port(monkeypatch): + """Test that RPC mode uses FLAGD_PORT and ignores FLAGD_SYNC_PORT.""" + sync_port = 9999 + port = 7777 + monkeypatch.setenv(ENV_VAR_SYNC_PORT, str(sync_port)) + monkeypatch.setenv(ENV_VAR_PORT, str(port)) + + config = Config(resolver=ResolverType.RPC) + assert config.port == port # RPC should use FLAGD_PORT + assert config.resolver == ResolverType.RPC + + +def test_in_process_default_port_when_no_env_var(monkeypatch): + """Test that in-process mode uses default port when neither env var is set.""" + monkeypatch.delenv(ENV_VAR_SYNC_PORT, raising=False) + monkeypatch.delenv(ENV_VAR_PORT, raising=False) + config = Config(resolver=ResolverType.IN_PROCESS) + assert config.port == DEFAULT_PORT_IN_PROCESS + assert config.resolver == ResolverType.IN_PROCESS From 91d4766a89628af58e5d3b2179f64687c7824a44 Mon Sep 17 00:00:00 2001 From: Mridul Tailor <71081929+MridulTailor@users.noreply.github.com> Date: Thu, 19 Feb 2026 13:47:59 -0700 Subject: [PATCH 2/3] Update providers/openfeature-provider-flagd/README.md Co-authored-by: gemini-code-assist[bot] <176961590+gemini-code-assist[bot]@users.noreply.github.com> Signed-off-by: Mridul Tailor <71081929+MridulTailor@users.noreply.github.com> --- providers/openfeature-provider-flagd/README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/providers/openfeature-provider-flagd/README.md b/providers/openfeature-provider-flagd/README.md index 23520274..fbade51f 100644 --- a/providers/openfeature-provider-flagd/README.md +++ b/providers/openfeature-provider-flagd/README.md @@ -81,7 +81,7 @@ The default options can be defined in the FlagdProvider constructor. |--------------------------|--------------------------------|----------------------------|-------------------------------|---------------------| | resolver_type | FLAGD_RESOLVER | enum - `rpc`, `in-process` | rpc | | | host | FLAGD_HOST | str | localhost | rpc & in-process | -| port | FLAGD_SYNC_PORT (in-process), FLAGD_PORT (rpc or fallback) | int | 8013 (rpc), 8015 (in-process) | rpc & in-process | +| port | FLAGD_SYNC_PORT (in-process), FLAGD_PORT (rpc or fallback) | int | 8013 (rpc), 8015 (in-process) | rpc & in-process | | tls | FLAGD_TLS | bool | false | rpc & in-process | | cert_path | FLAGD_SERVER_CERT_PATH | String | null | rpc & in-process | | deadline | FLAGD_DEADLINE_MS | int | 500 | rpc & in-process | From 5a7cb21168a533700430e685ed4b5be3353aa6df Mon Sep 17 00:00:00 2001 From: Mridul Tailor Date: Fri, 20 Feb 2026 13:25:32 -0700 Subject: [PATCH 3/3] fix(flagd): simplify in-process port resolution logic Refactor port env var resolution for in-process mode to use os.environ.get() chaining instead of nested if/else, as suggested in code review. Logic and behavior are unchanged. Signed-off-by: Mridul Tailor --- .../contrib/provider/flagd/config.py | 20 +++++++++---------- 1 file changed, 9 insertions(+), 11 deletions(-) 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 d5aebc6e..f2feb648 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 @@ -153,17 +153,15 @@ def __init__( # noqa: PLR0913, PLR0915 # Port configuration with FLAGD_SYNC_PORT support for in-process mode if port is None: if self.resolver is ResolverType.IN_PROCESS: - # For in-process: try FLAGD_SYNC_PORT first, then FLAGD_PORT (backwards compatibility), then default - sync_port_env = os.environ.get(ENV_VAR_SYNC_PORT) - if sync_port_env is not None: - self.port = int(sync_port_env) - else: - port_env = os.environ.get(ENV_VAR_PORT) - self.port = ( - int(port_env) - if port_env is not None - else DEFAULT_PORT_IN_PROCESS - ) + # For in-process: try FLAGD_SYNC_PORT, then FLAGD_PORT (backwards compatibility), then default + port_from_env = os.environ.get(ENV_VAR_SYNC_PORT) or os.environ.get( + ENV_VAR_PORT + ) + self.port = ( + int(port_from_env) + if port_from_env is not None + else DEFAULT_PORT_IN_PROCESS + ) else: # For RPC: use FLAGD_PORT only self.port = int(