Skip to content

Commit f36ffb4

Browse files
committed
docs: clarify sequential implementation and planned async/parallel enhancements
Address Gemini code review feedback: - Update initialize() docstring to reflect sequential (not parallel) initialization - Add documentation notes to all async methods explaining they currently delegate to sync - Clarify that parallel evaluation mode is planned but not yet implemented - Update EvaluationStrategy protocol docs to set correct expectations This brings documentation in line with actual implementation. True async and parallel execution will be added in follow-up PRs. Refs: #511 Signed-off-by: vikasrao23 <vikasrao23@users.noreply.github.com>
1 parent f558192 commit f36ffb4

File tree

1 file changed

+25
-5
lines changed

1 file changed

+25
-5
lines changed

openfeature/provider/multi_provider.py

Lines changed: 25 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -36,8 +36,9 @@ class EvaluationStrategy(typing.Protocol):
3636
"""
3737
Strategy interface for determining which provider's result to use.
3838
39-
Strategies can be 'sequential' (evaluate one at a time, stop early) or
40-
'parallel' (evaluate all simultaneously).
39+
Current implementation supports 'sequential' mode (evaluate one at a time,
40+
stop early). 'parallel' mode (evaluate all simultaneously using asyncio.gather
41+
or ThreadPoolExecutor) is planned for a future enhancement.
4142
"""
4243

4344
run_mode: typing.Literal["sequential", "parallel"]
@@ -168,7 +169,12 @@ def get_provider_hooks(self) -> list[Hook]:
168169
return hooks
169170

170171
def initialize(self, evaluation_context: EvaluationContext) -> None:
171-
"""Initialize all providers in parallel."""
172+
"""
173+
Initialize all providers sequentially.
174+
175+
Note: Parallel initialization using ThreadPoolExecutor or asyncio.gather()
176+
is planned for a future enhancement.
177+
"""
172178
errors: list[Exception] = []
173179

174180
for name, provider in self._registered_providers:
@@ -201,6 +207,10 @@ def _evaluate_with_providers(
201207
"""
202208
Core evaluation logic that delegates to providers based on strategy.
203209
210+
Current implementation evaluates providers sequentially regardless of
211+
strategy.run_mode. True concurrent evaluation for 'parallel' mode is
212+
planned for a future enhancement.
213+
204214
:param flag_key: The flag key to evaluate
205215
:param default_value: Default value for the flag
206216
:param evaluation_context: Evaluation context
@@ -229,7 +239,7 @@ def _evaluate_with_providers(
229239
)
230240
results.append((provider_name, error_result))
231241

232-
# In parallel mode or if all sequential attempts completed, pick best result
242+
# If all sequential attempts completed (or parallel mode), pick best result
233243
for provider_name, result in results:
234244
if self.strategy.should_use_result(flag_key, provider_name, result):
235245
return result
@@ -264,7 +274,13 @@ async def resolve_boolean_details_async(
264274
default_value: bool,
265275
evaluation_context: EvaluationContext | None = None,
266276
) -> FlagResolutionDetails[bool]:
267-
# For async, delegate to sync for now (async aggregation would be more complex)
277+
"""
278+
Async boolean evaluation (currently delegates to sync implementation).
279+
280+
Note: True async evaluation using await and provider-level async methods
281+
is planned for a future enhancement. The current implementation maintains
282+
API compatibility but does not provide non-blocking I/O benefits.
283+
"""
268284
return self.resolve_boolean_details(flag_key, default_value, evaluation_context)
269285

270286
def resolve_string_details(
@@ -286,6 +302,7 @@ async def resolve_string_details_async(
286302
default_value: str,
287303
evaluation_context: EvaluationContext | None = None,
288304
) -> FlagResolutionDetails[str]:
305+
"""Async string evaluation (currently delegates to sync implementation)."""
289306
return self.resolve_string_details(flag_key, default_value, evaluation_context)
290307

291308
def resolve_integer_details(
@@ -307,6 +324,7 @@ async def resolve_integer_details_async(
307324
default_value: int,
308325
evaluation_context: EvaluationContext | None = None,
309326
) -> FlagResolutionDetails[int]:
327+
"""Async integer evaluation (currently delegates to sync implementation)."""
310328
return self.resolve_integer_details(flag_key, default_value, evaluation_context)
311329

312330
def resolve_float_details(
@@ -328,6 +346,7 @@ async def resolve_float_details_async(
328346
default_value: float,
329347
evaluation_context: EvaluationContext | None = None,
330348
) -> FlagResolutionDetails[float]:
349+
"""Async float evaluation (currently delegates to sync implementation)."""
331350
return self.resolve_float_details(flag_key, default_value, evaluation_context)
332351

333352
def resolve_object_details(
@@ -349,4 +368,5 @@ async def resolve_object_details_async(
349368
default_value: Sequence[FlagValueType] | Mapping[str, FlagValueType],
350369
evaluation_context: EvaluationContext | None = None,
351370
) -> FlagResolutionDetails[Sequence[FlagValueType] | Mapping[str, FlagValueType]]:
371+
"""Async object evaluation (currently delegates to sync implementation)."""
352372
return self.resolve_object_details(flag_key, default_value, evaluation_context)

0 commit comments

Comments
 (0)