diff --git a/aws_lambda_powertools/utilities/parameters/appconfig.py b/aws_lambda_powertools/utilities/parameters/appconfig.py index a3941489234..1b52cd96698 100644 --- a/aws_lambda_powertools/utilities/parameters/appconfig.py +++ b/aws_lambda_powertools/utilities/parameters/appconfig.py @@ -214,11 +214,12 @@ def get_app_config( # If max_age is not set, resolve it from the environment variable, defaulting to DEFAULT_MAX_AGE_SECS max_age = resolve_max_age(env=os.getenv(constants.PARAMETERS_MAX_AGE_ENV, DEFAULT_MAX_AGE_SECS), choice=max_age) - # Only create the provider if this function is called at least once - if "appconfig" not in DEFAULT_PROVIDERS: - DEFAULT_PROVIDERS["appconfig"] = AppConfigProvider(environment=environment, application=application) + # One provider per environment/application pair, created on first use + provider_key = f"appconfig:{environment}:{application}" + if provider_key not in DEFAULT_PROVIDERS: + DEFAULT_PROVIDERS[provider_key] = AppConfigProvider(environment=environment, application=application) - return DEFAULT_PROVIDERS["appconfig"].get( + return DEFAULT_PROVIDERS[provider_key].get( name, max_age=max_age, transform=transform, diff --git a/tests/functional/parameters/_boto3/test_utilities_parameters.py b/tests/functional/parameters/_boto3/test_utilities_parameters.py index 18b56b7026e..8442e4c9113 100644 --- a/tests/functional/parameters/_boto3/test_utilities_parameters.py +++ b/tests/functional/parameters/_boto3/test_utilities_parameters.py @@ -1033,7 +1033,7 @@ def _get_multiple(self, path: str, **kwargs) -> dict[str, str]: ... monkeypatch.setitem(parameters.base.DEFAULT_PROVIDERS, "ssm", TestProvider()) monkeypatch.setitem(parameters.base.DEFAULT_PROVIDERS, "secrets", TestProvider()) - monkeypatch.setitem(parameters.base.DEFAULT_PROVIDERS, "appconfig", TestProvider()) + monkeypatch.setitem(parameters.base.DEFAULT_PROVIDERS, "appconfig:test:test", TestProvider()) parameters.get_parameter(mock_name) parameters.get_secret(mock_name) @@ -3103,7 +3103,7 @@ def _get(self, name: str, **kwargs) -> bytes: def _get_multiple(self, path: str, **kwargs) -> dict[str, str]: raise NotImplementedError() - monkeypatch.setitem(parameters.base.DEFAULT_PROVIDERS, "appconfig", TestProvider()) + monkeypatch.setitem(parameters.base.DEFAULT_PROVIDERS, "appconfig:dev:myapp", TestProvider()) environment = "dev" application = "myapp" @@ -3128,7 +3128,7 @@ def _get(self, name: str, **kwargs) -> str: def _get_multiple(self, path: str, **kwargs) -> dict[str, str]: raise NotImplementedError() - monkeypatch.setitem(parameters.base.DEFAULT_PROVIDERS, "appconfig", TestProvider()) + monkeypatch.setitem(parameters.base.DEFAULT_PROVIDERS, "appconfig:dev:myapp", TestProvider()) environment = "dev" application = "myapp" @@ -3158,10 +3158,36 @@ def _get_multiple(self, path: str, **kwargs) -> dict[str, str]: value = parameters.get_app_config(mock_name, environment="dev", application="myapp") # THEN - assert parameters.appconfig.DEFAULT_PROVIDERS["appconfig"] is not None + assert parameters.appconfig.DEFAULT_PROVIDERS["appconfig:dev:myapp"] is not None assert value == mock_value +def test_appconf_get_app_config_different_environment_and_application(monkeypatch, mock_name): + # GIVEN a provider that reports which environment/application it was built for + class TestProvider(BaseProvider): + def __init__(self, environment: str, application: str): + super().__init__() + self.environment = environment + self.application = application + + def _get(self, name: str, **kwargs) -> str: + return f"{self.application}/{self.environment}" + + def _get_multiple(self, path: str, **kwargs) -> dict[str, str]: + raise NotImplementedError() + + monkeypatch.setattr(parameters.appconfig, "DEFAULT_PROVIDERS", {}) + monkeypatch.setattr(parameters.appconfig, "AppConfigProvider", TestProvider) + + # WHEN get_app_config is called with different applications and environments + first = parameters.get_app_config(mock_name, environment="dev", application="app-a", max_age=0) + second = parameters.get_app_config(mock_name, environment="prod", application="app-b", max_age=0) + + # THEN each call uses its own environment and application + assert first == "app-a/dev" + assert second == "app-b/prod" + + def test_transform_value_auto(mock_value: str): # GIVEN json_data = json.dumps({"A": mock_value})