Skip to content

Commit

Permalink
feat: implement provider status
Browse files Browse the repository at this point in the history
Signed-off-by: Federico Bond <federicobond@gmail.com>
  • Loading branch information
federicobond committed Mar 4, 2024
1 parent ae26217 commit 9add52e
Show file tree
Hide file tree
Showing 2 changed files with 39 additions and 6 deletions.
9 changes: 9 additions & 0 deletions openfeature/provider/__init__.py
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
import typing
from enum import Enum

from openfeature.evaluation_context import EvaluationContext
from openfeature.flag_evaluation import FlagResolutionDetails
Expand All @@ -7,6 +8,14 @@
from .metadata import Metadata


class ProviderStatus(Enum):
NOT_READY = "NOT_READY"
READY = "READY"
ERROR = "ERROR"
STALE = "STALE"
FATAL = "FATAL"


class FeatureProvider(typing.Protocol): # pragma: no cover
def initialize(self, evaluation_context: EvaluationContext) -> None:
...
Expand Down
36 changes: 30 additions & 6 deletions openfeature/provider/registry.py
Original file line number Diff line number Diff line change
Expand Up @@ -2,17 +2,20 @@

from openfeature.evaluation_context import EvaluationContext
from openfeature.exception import GeneralError
from openfeature.provider import FeatureProvider
from openfeature.provider import FeatureProvider, ProviderStatus
from openfeature.provider.no_op_provider import NoOpProvider


class ProviderRegistry:
_default_provider: FeatureProvider
_providers: typing.Dict[str, FeatureProvider]
_provider_status: typing.Dict[FeatureProvider, ProviderStatus]

def __init__(self) -> None:
self._default_provider = NoOpProvider()
self._providers = {}
self._provider_status = {}
self._set_provider_status(self._default_provider, ProviderStatus.NOT_READY)

def set_provider(self, domain: str, provider: FeatureProvider) -> None:
if provider is None:
Expand All @@ -22,9 +25,9 @@ def set_provider(self, domain: str, provider: FeatureProvider) -> None:
old_provider = providers[domain]
del providers[domain]
if old_provider not in providers.values():
old_provider.shutdown()
self._shutdown_provider(old_provider)
if provider not in providers.values():
provider.initialize(self._get_evaluation_context())
self._initialize_provider(provider)
providers[domain] = provider

def get_provider(self, domain: typing.Optional[str]) -> FeatureProvider:
Expand All @@ -36,9 +39,9 @@ def set_default_provider(self, provider: FeatureProvider) -> None:
if provider is None:
raise GeneralError(error_message="No provider")
if self._default_provider:
self._default_provider.shutdown()
self._shutdown_provider(self._default_provider)
self._default_provider = provider
provider.initialize(self._get_evaluation_context())
self._initialize_provider(provider)

def get_default_provider(self) -> FeatureProvider:
return self._default_provider
Expand All @@ -50,10 +53,31 @@ def clear_providers(self) -> None:

def shutdown(self) -> None:
for provider in {self._default_provider, *self._providers.values()}:
provider.shutdown()
self._shutdown_provider(provider)

def _get_evaluation_context(self) -> EvaluationContext:
# imported here to avoid circular imports
from openfeature.api import get_evaluation_context

return get_evaluation_context()

def _initialize_provider(self, provider: FeatureProvider) -> None:
try:
if hasattr(provider, "initialize"):
provider.initialize(self._get_evaluation_context())
self._set_provider_status(provider, ProviderStatus.READY)
except Exception:
self._set_provider_status(provider, ProviderStatus.ERROR)

Check warning on line 70 in openfeature/provider/registry.py

View check run for this annotation

Codecov / codecov/patch

openfeature/provider/registry.py#L69-L70

Added lines #L69 - L70 were not covered by tests

def _shutdown_provider(self, provider: FeatureProvider) -> None:
try:
if hasattr(provider, "shutdown"):
provider.shutdown()
self._set_provider_status(provider, ProviderStatus.NOT_READY)
except Exception:
self._set_provider_status(provider, ProviderStatus.FATAL)

Check warning on line 78 in openfeature/provider/registry.py

View check run for this annotation

Codecov / codecov/patch

openfeature/provider/registry.py#L77-L78

Added lines #L77 - L78 were not covered by tests

def _set_provider_status(
self, provider: FeatureProvider, status: ProviderStatus
) -> None:
self._provider_status[provider] = status

0 comments on commit 9add52e

Please sign in to comment.