Skip to content

Commit 67a6850

Browse files
committed
Merge remote-tracking branch 'upstream/main' into feat/gherkinmigration
2 parents 578692f + 8e23a70 commit 67a6850

File tree

11 files changed

+94
-49
lines changed

11 files changed

+94
-49
lines changed

.github/workflows/build.yml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -60,7 +60,7 @@ jobs:
6060

6161
- if: matrix.python-version == '3.11'
6262
name: Upload coverage to Codecov
63-
uses: codecov/codecov-action@v4.5.0
63+
uses: codecov/codecov-action@v5.1.2
6464
with:
6565
name: Code Coverage for ${{ matrix.package }} on Python ${{ matrix.python-version }}
6666
directory: ${{ matrix.package }}

.github/workflows/release.yml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -46,7 +46,7 @@ jobs:
4646
# IMPORTANT: this permission is mandatory for trusted publishing to pypi
4747
id-token: write
4848
container:
49-
image: "python:3.12"
49+
image: "python:3.13"
5050

5151
steps:
5252
- uses: actions/checkout@v4

.gitmodules

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@
44
[submodule "providers/openfeature-provider-flagd/test-harness"]
55
path = providers/openfeature-provider-flagd/openfeature/test-harness
66
url = [email protected]:open-feature/flagd-testbed.git
7+
branch = v0.5.18
78
[submodule "providers/openfeature-provider-flagd/spec"]
89
path = providers/openfeature-provider-flagd/openfeature/spec
910
url = https://github.com/open-feature/spec

.pre-commit-config.yaml

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,14 +1,14 @@
11
default_stages: [commit]
22
repos:
33
- repo: https://github.com/astral-sh/ruff-pre-commit
4-
rev: v0.6.3
4+
rev: v0.8.4
55
hooks:
66
- id: ruff
77
args: [--fix]
88
- id: ruff-format
99

1010
- repo: https://github.com/pre-commit/pre-commit-hooks
11-
rev: v4.6.0
11+
rev: v5.0.0
1212
hooks:
1313
- id: check-toml
1414
- id: check-yaml

providers/openfeature-provider-flagd/pyproject.toml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -40,7 +40,7 @@ dependencies = [
4040
"pytest-bdd",
4141
"testcontainers",
4242
"asserts",
43-
"grpcio-health-checking==1.60.0",
43+
"grpcio-health-checking==1.68.1",
4444
]
4545
pre-install-commands = [
4646
"hatch build",

providers/openfeature-provider-flagd/src/openfeature/contrib/provider/flagd/config.py

Lines changed: 5 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -26,7 +26,7 @@ class CacheType(Enum):
2626
DEFAULT_RESOLVER_TYPE = ResolverType.RPC
2727
DEFAULT_RETRY_BACKOFF = 1000
2828
DEFAULT_RETRY_BACKOFF_MAX = 120000
29-
DEFAULT_RETRY_GRACE_PERIOD = 5
29+
DEFAULT_RETRY_GRACE_PERIOD_SECONDS = 5
3030
DEFAULT_STREAM_DEADLINE = 600000
3131
DEFAULT_TLS = False
3232

@@ -41,7 +41,7 @@ class CacheType(Enum):
4141
ENV_VAR_RESOLVER_TYPE = "FLAGD_RESOLVER"
4242
ENV_VAR_RETRY_BACKOFF_MS = "FLAGD_RETRY_BACKOFF_MS"
4343
ENV_VAR_RETRY_BACKOFF_MAX_MS = "FLAGD_RETRY_BACKOFF_MAX_MS"
44-
ENV_VAR_RETRY_GRACE_PERIOD = "FLAGD_RETRY_GRACE_PERIOD"
44+
ENV_VAR_RETRY_GRACE_PERIOD_SECONDS = "FLAGD_RETRY_GRACE_PERIOD"
4545
ENV_VAR_STREAM_DEADLINE_MS = "FLAGD_STREAM_DEADLINE_MS"
4646
ENV_VAR_TLS = "FLAGD_TLS"
4747

@@ -118,7 +118,9 @@ def __init__( # noqa: PLR0913
118118
self.retry_grace_period: int = (
119119
int(
120120
env_or_default(
121-
ENV_VAR_RETRY_GRACE_PERIOD, DEFAULT_RETRY_GRACE_PERIOD, cast=int
121+
ENV_VAR_RETRY_GRACE_PERIOD_SECONDS,
122+
DEFAULT_RETRY_GRACE_PERIOD_SECONDS,
123+
cast=int,
122124
)
123125
)
124126
if retry_grace_period is None

providers/openfeature-provider-flagd/src/openfeature/contrib/provider/flagd/resolvers/grpc.py

Lines changed: 40 additions & 36 deletions
Original file line numberDiff line numberDiff line change
@@ -54,7 +54,11 @@ def __init__(
5454
self.emit_provider_error = emit_provider_error
5555
self.emit_provider_stale = emit_provider_stale
5656
self.emit_provider_configuration_changed = emit_provider_configuration_changed
57-
self.cache: typing.Optional[BaseCacheImpl] = self._create_cache()
57+
self.cache: typing.Optional[BaseCacheImpl] = (
58+
LRUCache(maxsize=self.config.max_cache_size)
59+
if self.config.cache == CacheType.LRU
60+
else None
61+
)
5862

5963
self.retry_grace_period = config.retry_grace_period
6064
self.streamline_deadline_seconds = config.stream_deadline_ms * 0.001
@@ -80,12 +84,10 @@ def __init__(
8084
self.timer: typing.Optional[threading.Timer] = None
8185
self.active = False
8286

83-
def _create_cache(self):
84-
return (
85-
LRUCache(maxsize=self.config.max_cache_size)
86-
if self.config.cache == CacheType.LRU
87-
else None
88-
)
87+
self.thread: typing.Optional[threading.Thread] = None
88+
self.timer: typing.Optional[threading.Timer] = None
89+
90+
self.start_time = time.time()
8991

9092
def initialize(self, evaluation_context: EvaluationContext) -> None:
9193
self.connect()
@@ -114,40 +116,41 @@ def connect(self) -> None:
114116
)
115117

116118
def monitor(self) -> None:
117-
def state_change_callback(new_state: ChannelConnectivity) -> None:
118-
logger.debug(f"gRPC state change: {new_state}")
119-
if new_state == ChannelConnectivity.READY:
120-
if not self.thread or not self.thread.is_alive():
121-
self.thread = threading.Thread(
122-
target=self.listen,
123-
daemon=True,
124-
name="FlagdGrpcServiceWorkerThread",
125-
)
126-
self.thread.start()
127-
128-
if self.timer and self.timer.is_alive():
129-
logger.debug("gRPC error timer expired")
130-
self.timer.cancel()
131-
132-
elif new_state == ChannelConnectivity.TRANSIENT_FAILURE:
133-
# this is the failed reonnect attempt so we are going into stale
134-
self.emit_provider_stale(
135-
ProviderEventDetails(
136-
message="gRPC sync disconnected, reconnecting",
137-
)
119+
self.channel.subscribe(self._state_change_callback, try_to_connect=True)
120+
121+
def _state_change_callback(self, new_state: ChannelConnectivity) -> None:
122+
logger.debug(f"gRPC state change: {new_state}")
123+
if new_state == ChannelConnectivity.READY:
124+
if not self.thread or not self.thread.is_alive():
125+
self.thread = threading.Thread(
126+
target=self.listen,
127+
daemon=True,
128+
name="FlagdGrpcServiceWorkerThread",
138129
)
139-
# adding a timer, so we can emit the error event after time
140-
self.timer = threading.Timer(self.retry_grace_period, self.emit_error)
130+
self.thread.start()
141131

142-
logger.debug("gRPC error timer started")
143-
self.timer.start()
144-
self.connected = False
132+
if self.timer and self.timer.is_alive():
133+
logger.debug("gRPC error timer expired")
134+
self.timer.cancel()
145135

146-
self.channel.subscribe(state_change_callback, try_to_connect=True)
136+
elif new_state == ChannelConnectivity.TRANSIENT_FAILURE:
137+
# this is the failed reconnect attempt so we are going into stale
138+
self.emit_provider_stale(
139+
ProviderEventDetails(
140+
message="gRPC sync disconnected, reconnecting",
141+
)
142+
)
143+
self.start_time = time.time()
144+
# adding a timer, so we can emit the error event after time
145+
self.timer = threading.Timer(self.retry_grace_period, self.emit_error)
146+
147+
logger.debug("gRPC error timer started")
148+
self.timer.start()
149+
self.connected = False
147150

148151
def emit_error(self) -> None:
149152
logger.debug("gRPC error emitted")
150-
if self.cache is not None:
153+
if self.cache:
151154
self.cache.clear()
152155
self.emit_provider_error(
153156
ProviderEventDetails(
@@ -157,12 +160,13 @@ def emit_error(self) -> None:
157160
)
158161

159162
def listen(self) -> None:
160-
logger.info("gRPC starting listener thread")
163+
logger.debug("gRPC starting listener thread")
161164
call_args = (
162165
{"timeout": self.streamline_deadline_seconds}
163166
if self.streamline_deadline_seconds > 0
164167
else {}
165168
)
169+
call_args["wait_for_ready"] = True
166170
request = evaluation_pb2.EventStreamRequest()
167171

168172
# defining a never ending loop to recreate the stream

providers/openfeature-provider-flagd/tests/e2e/flagd_container.py

Lines changed: 5 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
11
import time
2+
from pathlib import Path
23

34
import grpc
45
from grpc_health.v1 import health_pb2, health_pb2_grpc
@@ -15,8 +16,10 @@ def __init__(
1516
self,
1617
**kwargs,
1718
) -> None:
18-
image: str = "ghcr.io/open-feature/flagd-testbed:v0.5.15"
19-
super().__init__(image, **kwargs)
19+
image: str = "ghcr.io/open-feature/flagd-testbed"
20+
path = Path(__file__).parents[2] / "openfeature/test-harness/version.txt"
21+
data = path.read_text().rstrip()
22+
super().__init__(f"{image}:v{data}", **kwargs)
2023
self.rpc = 8013
2124
self.ipr = 8015
2225
self.with_exposed_ports(self.rpc, self.ipr, HEALTH_CHECK)

providers/openfeature-provider-flagd/tests/e2e/step/config_steps.py

Lines changed: 7 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -35,8 +35,13 @@ def convert_resolver_type(val: typing.Union[str, ResolverType]) -> ResolverType:
3535
}
3636

3737

38-
@pytest.fixture(autouse=True, scope="module")
39-
def setup(request):
38+
@pytest.fixture(autouse=True)
39+
def container():
40+
pass
41+
42+
43+
@pytest.fixture(autouse=True)
44+
def setup_provider(request):
4045
pass
4146

4247

0 commit comments

Comments
 (0)