Skip to content

Commit 28023c3

Browse files
authored
App Configuration Provider - Replica Discovery on Refresh (#36717)
* Discovery at runtime * discovery testing * fixing cspell issues * Update test_discovery.py * fixes some mypy issues * Added discovery tests * fixing bug of not creating correct failover clients for endpoints * refresh clients tests with fix * format fix * Update test_configuration_client_manager.py * Fixing next check logic * Review items * Update _azureappconfigurationprovider.py * review comments * filters used missing * Update test_configuration_client_manager.py * Update _client_manager.py * Update _client_manager.py * Update _azureappconfigurationprovider.py
1 parent 61e0fce commit 28023c3

File tree

6 files changed

+704
-77
lines changed

6 files changed

+704
-77
lines changed

sdk/appconfiguration/azure-appconfiguration-provider/azure/appconfiguration/provider/_azureappconfigurationprovider.py

Lines changed: 35 additions & 49 deletions
Original file line numberDiff line numberDiff line change
@@ -50,14 +50,13 @@
5050
TIME_WINDOW_FILTER_KEY,
5151
TARGETING_FILTER_KEY,
5252
)
53-
from ._client_manager import ConfigurationClientWrapper, ConfigurationClientManager
54-
from ._discovery import find_auto_failover_endpoints
53+
from ._client_manager import ConfigurationClientManager
5554
from ._user_agent import USER_AGENT
5655

5756
if TYPE_CHECKING:
5857
from azure.core.credentials import TokenCredential
5958

60-
JSON = Mapping[str, Any] # pylint: disable=unsubscriptable-object
59+
JSON = Mapping[str, Any]
6160
_T = TypeVar("_T")
6261
logger = logging.getLogger(__name__)
6362

@@ -315,7 +314,8 @@ def _buildprovider(
315314
# pylint:disable=protected-access
316315
if connection_string:
317316
endpoint = connection_string.split(";")[0].split("=")[1]
318-
provider = AzureAppConfigurationProvider(endpoint, **kwargs)
317+
if not endpoint:
318+
raise ValueError("No endpoint specified.")
319319
retry_total = kwargs.pop("retry_total", 2)
320320
retry_backoff_max = kwargs.pop("retry_backoff_max", 60)
321321
replica_discovery_enabled = kwargs.pop("replica_discovery_enabled", True)
@@ -325,39 +325,27 @@ def _buildprovider(
325325
else:
326326
user_agent = USER_AGENT
327327

328-
clients = []
329-
if connection_string and endpoint:
330-
clients.append(
331-
ConfigurationClientWrapper.from_connection_string(
332-
endpoint, connection_string, user_agent, retry_total, retry_backoff_max, **kwargs
333-
)
334-
)
335-
failover_endpoints = find_auto_failover_endpoints(endpoint, replica_discovery_enabled)
336-
for failover_endpoint in failover_endpoints:
337-
failover_connection_string = connection_string.replace(endpoint, failover_endpoint)
338-
clients.append(
339-
ConfigurationClientWrapper.from_connection_string(
340-
failover_endpoint, failover_connection_string, user_agent, retry_total, retry_backoff_max, **kwargs
341-
)
342-
)
343-
provider._replica_client_manager.set_clients(clients)
344-
return provider
345-
if endpoint and credential:
346-
clients.append(
347-
ConfigurationClientWrapper.from_credential(
348-
endpoint, credential, user_agent, retry_total, retry_backoff_max, **kwargs
349-
)
350-
)
351-
failover_endpoints = find_auto_failover_endpoints(endpoint, replica_discovery_enabled)
352-
for failover_endpoint in failover_endpoints:
353-
clients.append(
354-
ConfigurationClientWrapper.from_credential(
355-
endpoint, credential, user_agent, retry_total, retry_backoff_max, **kwargs
356-
)
357-
)
358-
provider._replica_client_manager.set_clients(clients)
359-
return provider
360-
raise ValueError("Please pass either endpoint and credential, or a connection string with a value.")
328+
interval: int = kwargs.get("refresh_interval", 30)
329+
if interval < 1:
330+
raise ValueError("Refresh interval must be greater than or equal to 1 second.")
331+
332+
min_backoff: int = min(kwargs.pop("min_backoff", 30), interval)
333+
max_backoff: int = min(kwargs.pop("max_backoff", 600), interval)
334+
335+
replica_client_manager = ConfigurationClientManager(
336+
connection_string,
337+
endpoint,
338+
credential,
339+
user_agent,
340+
retry_total,
341+
retry_backoff_max,
342+
replica_discovery_enabled,
343+
min_backoff,
344+
max_backoff,
345+
**kwargs
346+
)
347+
provider = AzureAppConfigurationProvider(endpoint, replica_client_manager, **kwargs)
348+
return provider
361349

362350

363351
def _resolve_keyvault_reference(
@@ -487,16 +475,9 @@ class AzureAppConfigurationProvider(Mapping[str, Union[str, JSON]]): # pylint:
487475
keys. Enables resolution of Key Vault references in configuration settings.
488476
"""
489477

490-
def __init__(self, endpoint, **kwargs) -> None:
478+
def __init__(self, endpoint, replica_client_manager, **kwargs) -> None:
491479
self._origin_endpoint = endpoint
492-
493-
interval: int = kwargs.get("refresh_interval", 30)
494-
if interval < 1:
495-
raise ValueError("Refresh interval must be greater than or equal to 1 second.")
496-
497-
min_backoff: int = kwargs.get("min_backoff", 30) if kwargs.get("min_backoff", 30) <= interval else interval
498-
max_backoff: int = 600 if 600 <= interval else interval
499-
self._replica_client_manager = ConfigurationClientManager(min_backoff, max_backoff)
480+
self._replica_client_manager = replica_client_manager
500481
self._dict: Dict[str, Any] = {}
501482
self._secret_clients: Dict[str, SecretClient] = {}
502483
self._selects: List[SettingSelector] = kwargs.pop(
@@ -546,6 +527,7 @@ def refresh(self, **kwargs) -> None:
546527
"""
547528
exception: Exception = RuntimeError(error_message)
548529
try:
530+
self._replica_client_manager.refresh_clients()
549531
active_clients = self._replica_client_manager.get_active_clients()
550532

551533
for client in active_clients:
@@ -582,9 +564,12 @@ def refresh(self, **kwargs) -> None:
582564
self._feature_filter_usage,
583565
self._uses_key_vault,
584566
)
585-
need_ff_refresh, self._refresh_on_feature_flags, feature_flags = client.refresh_feature_flags(
586-
self._refresh_on_feature_flags, self._feature_flag_selectors, headers, **kwargs
567+
need_ff_refresh, self._refresh_on_feature_flags, feature_flags, filters_used = (
568+
client.refresh_feature_flags(
569+
self._refresh_on_feature_flags, self._feature_flag_selectors, headers, **kwargs
570+
)
587571
)
572+
self._feature_filter_usage = filters_used
588573

589574
if need_refresh or need_ff_refresh:
590575
self._dict[FEATURE_MANAGEMENT_KEY] = {}
@@ -622,9 +607,10 @@ def _load_all(self, **kwargs):
622607
value = self._process_key_value(config)
623608
configuration_settings_processed[key] = value
624609
if self._feature_flag_enabled:
625-
feature_flags, feature_flag_sentinel_keys = client.load_feature_flags(
610+
feature_flags, feature_flag_sentinel_keys, used_filters = client.load_feature_flags(
626611
self._feature_flag_selectors, self._feature_flag_refresh_enabled, **kwargs
627612
)
613+
self._feature_filter_usage = used_filters
628614
configuration_settings_processed[FEATURE_MANAGEMENT_KEY] = {}
629615
configuration_settings_processed[FEATURE_MANAGEMENT_KEY][FEATURE_FLAG_KEY] = feature_flags
630616
self._refresh_on_feature_flags = feature_flag_sentinel_keys

0 commit comments

Comments
 (0)