-
Notifications
You must be signed in to change notification settings - Fork 116
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
Config Lifecycle Events #526
Comments
While all of these features could be implemented in one way or another, looking closing a lot of these operations match Config Lifecycle Events:
Maybe we can implement this API Lifecycle support, which will make the API more flexible to implement these and maybe other use cases. |
Since this issue is really about a possible way to solve the use cases, I've tagged it with |
A very rough idea just to start the discussion :) public interface ConfigLifecycle {
void beforeLookup(ConfigSource configSource, String propertyName);
void afterLookup(ConfigSource configSource, String propertyName, String value);
<T> void beforeConversion(Class<T> type, Converter<T> converter, String value);
<T> void afterConversion(T value);
} |
For property expansion, you'd need some means to replace the value. An interceptor-style approach works well in this case. I'm not really sold that conversion and config source should be bundled up in this way (particularly if conversion gets hoisted off to its own API), given that they're different mechanisms. The only reason to have this grouping is because there is a general correlation to the "shape" of the API, but it's not really clear that there would be any actual practical benefit to putting them together. |
In that particular case, the Converter lifecycle events would be extracted to their own API (if that moves forward somehow). Or, we could keep things more simple, and just have the beforeLookup and afterLookup. The problem with the Converters is that for property replacement, you do need to perform it before Conversion, no? Probably we can have afterLookup to return a String and then you can do the property replacement over there. |
Right, property replacement is really best done at the config source level. In Quarkus we wrap the config source so it is essentially "interceptor style"; this works well. Validation is best done at the converter level. In SmallRye Config, we wrap converters and this is a very effective solution. A challenge with before/after callbacks is that the Config implementation has to coordinate them, which is fairly complex. What if the This principle applies just as easily to conversion as it applies to config sources. Wrapping just works better. |
So for the config source case, I'd recommend an API like this: public interface ConfigSourceInterceptorContext {
String proceed(String key);
}
public interface ConfigSourceInterceptor {
String getConfigValue(ConfigSourceInterceptorContext ctxt, String key);
} The context is implemented by the MP Config implementation, and the interceptor is implemented by the user. The interceptor can apply any policy it likes and use the context to retrieve any number of additional values. It can also transform the key arbitrarily. |
If we determined to add things like information about the config source, that would go on the context API - the challenge though is that it may be to say what config source a property came from if it is composed of expressions whose expansions come from many sources! |
I guess it will depend on how you implement the lookup. If you go from outer to inner, composed expressions are going to be in the same context of the main one you are looking for, so you should get the main ConfigSource, plus all other ConfigSources that composed the original value. |
Yeah ultimately it seems like a solvable problem. The crux of it would be to return information about the source from that public interface ConfigSourceInterceptorContext {
ConfigValue proceed(String key);
} ...where |
Well, do we see any use case here for having the actual instance of ConfigSource? What are you going to do with it? So far, the only use case is for logging / info purposes I believe. |
You already got the key and value. We could just give you the Class of the ConfigSource that sourced the value. If you really want the instance, you could get it from Config.getConfigSources. Just trying to figure out if there is any value to expose it there. |
Right it's mainly going to be for logging, and as I said I hope we don't have to expose the For example I should be able to tell a user something like |
Hum... this is quite interesting. In your last comment we are now mixing validation, right? So, in the case a config exist, but is not valid (by whatever means we perform validation), should we just error it out, or search another ConfigSource that may have a valid value? |
I'm just thinking ahead: the main use case of knowing the original
For Quarkus we determined that if a user has made a configuration mistake, it's possible (maybe even likely) that starting the container anyway could result in problems - maybe catastrophic problems. Imagine if the system defaulted to accessing the production database, and the database name for the development database was misspelled in the user's configuration, causing the production database to be overwritten... For this reason we decided that in this case the application should stop with a descriptive error message. The user should always have exact control over what they're doing, and we should prevent them from shooting themselves in the foot to the maximum practical extent. |
Understood. Still on that particular sample, due to semantics, it may be impossible to determine if there is an issue or not, unless you add profiles into the mix (like Quarkus does) and compare them with each other. Anyway, using this interceptor approach, I guess we to support it via ServiceLoader, and then allow developers to implement it as a regular CDI Interceptor? |
Yeah seems doable, though maybe we want to do it in a "provider" style like
This I don't know about. What would it look like? |
Related to #125 Sorry, I probably used the wrong term there with CDI Interceptor. It couldn't be a CDI interceptor, since the API would be different. But have a CDI way to create the Config Interceptor without using the Service Loader. This, if you rely only on CDI. |
Ah! Yes, I think this it is a good/useful idea for CDI to be able to produce instances of this interface. |
…lipse#526. Signed-off-by: Roberto Cortez <[email protected]>
Hi dmlloyd, I disagree. In our case we have multiple config sources each can contain variables or their actual values. I implemented a solution that collects all key/values whereas higher order config sources have precedence of course and than search for placeholders and replace them. |
Hi radcortez, imho, if there is an invalid config (with higher prio) and a valid config with lower prio, it should fail. |
I guess that you are looking to have something like this supported: |
Indeed that's very interesting. However, I simply created my own ConfigSource with high order, read all other ConfigSource's (ConfigProvider.getConfig().getConfigSources()) and then expand variables on all the properties. So basically this ConfigSource contains the final truth (all replaced keys). |
Yes, the ideia here it to come up with a solution that supports that out of the box, so users don't have to implement it :) |
What I mean is "better done at the config source level than at the converter level", which was the context of the discussion (I probably could have been more clear). But what you're describing is a third option. There's a couple of problems with this idea that would make me conclude it's not the best general approach for the specification:
The approach you describe can be useful for certain situations, but I believe it's not the best general approach for the specification for these reasons. |
After having processed all of the conversations, I think there can be treated as imlementation details (ConfigSourceInterceptorContext). I don't feel we need to expose such an spi as they are not bootstrapping and end users don't need to do anything with it. Anyway, I think based on the conversation on PR, this should be moved to smallRye to experiment and then come back. |
Yes, we are working on something in SmallRye. Maybe we don't need to expose anything, but the idea was to have some way to allows users to implement / intercept the config lifecycle, so they can do logging, property replacement, composition etc... |
I think it is much better to provide property replacement, composition out of box. |
We can. These can just be a couple of interceptors that the API provides. |
For now, we will leave this for the implementation to handle. |
As a user, I'm interested in being able to:
The text was updated successfully, but these errors were encountered: