-
Notifications
You must be signed in to change notification settings - Fork 11
implement the ability to plugin fallback values #236
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Conversation
- rename ConfigurationFallbacks to ConfigurationFallback - Change List<ConfigurationFallbacks> fallbacks to single ConfigurationFallback fallback - Make DefaultFallback final - Rename method Configuration.Builder.withFallbacks() to fallback()
|
Hi @andponlin I've push a commit that changes this from using a Can you review those changes I've made and see if you are happy with them? Thanks, Rob. |
| } else if (spi instanceof ModificationEventRunner) { | ||
| _eventRunner = (ModificationEventRunner) spi; | ||
| } else if (spi instanceof ConfigurationFallback) { | ||
| _fallback = (ConfigurationFallback) spi; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
It's probably a good idea to either fail if there are two instances of ConfigurationFallback configured; otherwise the behaviour may become unpredictable.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I think I have a use case where for Tests, it would be useful to use an alternative ConfigurationFallback.
In this case the test configuration would have values like ssm://test/myapp/some_key_of_secret
... and if a value had that special prefix it would load the value from the AWS secret store. You need aws single signon to be able to do this of course. This is to assist 2 scenarios which is (1) running locally against Dev/Test and (2) Integration tests
I think the override feature would actually support this and ideally this is only done for Testing, so the override implementation is only in maven test scope.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@rbygrave ; I think it may be good to look into throwing in this scenario because otherwise the behaviour could be confusing and difficult to track down.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I think I have a use case where for Tests, it would be useful to use an alternative ConfigurationFallback.
So in this case there would be an instance of ConfigurationFallback from the main classpath and an instance from the test classpath? It may be worth logging to stderr (at least) that this is happening because in other situation a clash will be hard to comprehend.
What is the actual use case @andponlin for this? What case are we hitting where the current behaviour isn't desirable and what are we replacing the system properties/env vars with in that case? |
What I would ultimately like to achieve is that env-vars and system properties (in that order) are overrides for config keys and not the other way around such that they are fallbacks. I want to be able to override a value via env-var regardless if it is configured via configuration files or not. I also want to use a different mapping from the configuration key to the env-var name. In my case, I would implement To implement the override behaviour, I am currently implementing Does this make sense? 🤔 |
To borrow a phrase from my stance on social media, "I don't follow". How does disabling fallback translate to env variables being treated as the override. Is it possible to provide a more concrete example? |
Right, makes sense.
Yeah. My gut is suggesting that this PR doesn't actually resolve the issue for your use case? The use case of ... "env-vars and system properties (in that order) are overrides" ... actually needs a different PR in order to achieve that ... and then if we do that do we actually need this pluggable ConfigurationFallback? Maybe but maybe not? Seems to me we should be looking at the source issue of supporting "env-vars and system properties (in that order) are overrides" first, and then seeing where that gets us. We might still want this pluggable ConfigurationFallback but we should probably solve the other issue first to make sure this still makes sense? Or said differently, I'd feel more comfortable leaving this PR un-merged until we've sorted the "overrides" issue just to make sure it still makes sense? |
Another approach might be to wrap the public class ConfigWrap {
public static String get(String key) {
String override = deriveOverride(key);
return override != null ? override : Config.get(key);
}
private static String deriveOverride(String key) {
String systemPropertiesValue = System.getProperty(key);
if (null != systemPropertiesValue) {
return systemPropertiesValue;
}
return System.getenv(mapKeyToEnvVar(key));
}
private static String mapKeyToEnvVar(String key) {
key = key.replace(".", "_");
key = key.replace("-", "");
return key.toUpperCase();
}
} |
|
A potential alternative is to modify the interface ... and a variation is to put a change into ConfigurationCore before (and after?) the call to |
Yes you're right Rob, this PR doesn't achieve the whole desired outcome. It enables only the last bit. The rest would be a follow-on.
OK, I think that would be a good extension point that sounds as if it would allow for bespoke overrides. |
- add overrideValue() method - Invoke overrideValue() on initial load and builder load
|
I've pushed a change that adds a Note that ConfigurationSource plugins like the AWS AppConfig one actually bypass the overrideValue() method. That is, the ConfigrationCode.applyChanges() method it doesn't use the fallback instance (but it could, hmm, pondering this). In theory this gives us the options we need for this use case (A) control overriding the values (B) control fallback value |
| * @param source The source of the key value pair | ||
| */ | ||
| default String overrideValue(String key, String value, String source) { | ||
| return value; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
nit: I guess the implementation of ConfigurationFallback is not able to manipulate the source as well here? That would be a nice addition if it could but likely involves returning a record, CoreEntry or similar. Maybe not worth it.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Pushed a commit that returns Entry, allows us to override the source along with the value.
According to my research, hypens are not allowed in POSIX Standard environment variable names. So we could provide a helper method that does the env var name conversion properly including the trimming out of |
In the example above, I'm mapping |
This allows us to override the source along with the value. A downside is that we need to expose more methods on the Entry interface that were otherwise internal to CoreEntry.
Yes. I think we should also trim the hypens and make that change as a [separate] bug fix. |
Rather than nullable, and thus allow the source to also be provided by the fallback method.
| import java.util.Optional; | ||
|
|
||
| /** | ||
| * Implementations of this class are able to define a fallback value when there is no |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I am wondering if the name ConfigurationFallback is the best since it has a dual purpose of providing a fallback and an overrride. Maybe ConfigurationValueInterceptor or ConfigurationOverrideAndFallback might be clearer?
Even if this name is retained as-is, the class comments would be good to update so that they describe the role of the SPI interface.
|
perhaps instead of a new fallback interface, we should change the behavior in general to prefer system/env variables over configuration files. That is, if a system property/env is set, prefer that over all else |
|
Ok, I think I'm happy with this change. In doing this, I have the thought that the behaviour being asked for is actually consistent with how Spring does it [I will see if I can confirm that today]. In that case, I'm wondering if we should actually change the default behaviour here (so as a 5.0 release actually change the default behaviour). What are you guys thinking? |
| @Override | ||
| @Nullable | ||
| public Optional<Entry> fallbackValue(String key) { | ||
| String val = System.getProperty(key); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
For testing purposes, it is better not to just simulate/mock the System.getProperty behaviour? I fear that if the tests are run concurrently that there may be clash in the runtime state of the properties as they are essentially static.
BTW; will need to drop off now -- will reply to anything this evening (NZDT). |
they make sense to me as well, but if the only usecase at the moment is solved by spring env behavior, I'm not really seeing the point in adding it |
Yeah, I'm feeling that too. Leaning to making this a behaviour change without introducing the interface/plugin at least initially and seeing how that goes. |
|
FYI: Spring Behaviour: System Properties overrides Environment Variables overrides ... property source values [So Andrew, this was a touch different in that System Properties trumps Environment Variables ... is that an issue?] I think we adjust this PR such that it matches Spring behaviour, and remove the interface/pluggable part at least initially and look at that as a |
|
I think we should use #239 |
|
Replaced by #239 |
|
@andponlin Try version |
|
Hi @rbygrave ;
It seems more logical that it would be the other way around with env-vars being precedence but for my situation specifically where I a using this it won't be a problem. Thanks both; I will try this out. |
|
Tried it out; seems to be working well 👍 |
The config system currently obtains fallback values from system properties and env-vars. This is not always desirable. This PR provides a way to make the fallbacks pluggable so that a project can opt to provide a fallback in a different way.