-
Notifications
You must be signed in to change notification settings - Fork 966
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
Impossible to override reference.conf #167
Comments
Right, it is specified to work this way for better or worse. https://github.com/typesafehub/config/blob/master/HOCON.md#conventional-configuration-files-for-jvm-apps It can't change without breaking back compat, which means not anytime soon. Do remember though that #164 has some loosely-related discussion. The suggestion there to put your above snippet of config in an application.conf instead of a reference.conf may be helpful. You can include an application.conf in a library, though it won't be loaded if someone chooses to use a different config file at the app level. Another option if your In the sample library I'd do that right here, after the checkValid: You could parse an inline string containing your internal config values and then merge it into the app-provided config using |
I see your point. Unfortunately using custom config looks to be problematic with Play. You are right, that this change would break compatibility. But let's imagine that we did it anyway. I.e. reference.conf is used as fallback without resolving first. This will definitely generate different config. But it seems to me that in most cases it would be what users actually wanted, no? Do you have an example when current behavior is better? Also what do you think about "late binding" variables? Let's imagine that my reference.conf has:
(or any other syntax). Do you think this could be useful? Splitting reference.conf and remembering to include parts of it into application.conf would work, but I would like to use this pattern in several reference.conf files, and I'm afraid it would quickly go out of control. |
I honestly don't remember the full rationale for how it works; I know it was discussed and considered (since the spec and implementation spell it out), but it was a while ago. A trouble with late-binding syntax is specifying what it means. ConfigFactory .load and the reference.conf/application.conf stack are currently an extremely superficial layer, not something that extends down into the syntax/semantics of the file format. Some related discussion at #100 To keep things organized, perhaps you could establish a convention |
I’m not sure which kind of “going out of control” you mean: if you just stick to |
@rkuhn Are you sure that default Config factory would load all application.conf from classpath? I was under impression that only one would be loaded. |
|
I am not not exactly sure, but this line seems to indicate that it merges resources. |
Yes, this is by design: reference.conf is the stand-alone reference, its values should not depend on other configs layered on top of it. The intention is that reference.conf is used by library authors and application.conf by application authors. You should be able to place the myapp.internal values in an application.conf shipped with your “library” instead. |
Even though this issue's closed, it's worth noting for others that I independently attempted @mikea's design and that it's not possible. The resolution documentation is clear, but the previous section that states To illustrate, I'd intended that Given
And
I'd hoped for:
But the actual is:
There's a clear workaround that isn't terrible: specify a shared value in |
I believe this should be reconsidered. It won't break backwards compatibility if we do. I know this, because Play has implemented this custom config loading behaviour for 4 years now, and nothing has broken. Play and Lagom supply a config parsed in this way to Akka, so Akka has been running on Play using this custom loaded config, and nothing has broken. The ability for Allowing the default to be based on another overridable property that makes getting the configuration right less error prone, resulting in a better user experience. |
It’s possible it doesn’t break back compat too much, but I don’t think it’s hard to write programs that would have worked before and no longer would, since attempting to use an unresolved value throws an exception. So any sort of “get values from the defaultReference() config” would presumably now have a chance to throw. I believe checkValid() is a thing which relies on getting values from the reference config, with no access to application.conf in there. I wasnt aware Play had changed this, though. I’m not really opposed to changing this though I think ideally it might be in a major version (there are several other issues with a “best done in major version” tag) ... and if it makes checkValid fundamentally not work, perhaps that API would be removed. also there would be API docs and HOCON.md to update. All of the defaultApplication, defaultReference methods would likely be made consistent. It’s some work |
But hang on, what you're describing there forwards compatibility, not backwards compatibility. If today, a reference.conf refers to a property that its expecting to set in application.conf, then today, that program will throw an exception. This change would change the behaviour such that it now doesn't throw an exception. Unless there are apps out there that depend on that exception being thrown, nothing is going to break. However, if we make this change, then someone writes a reference.conf that depends on the change and sources a config property set in application.conf, and then they downgrade to the current version of config that doesn't support this, then that will break. But that just means it's forwards incompatible, not backwards incompatible. I don't think that's a problem. As for checking validity, I'm not actually proposing that we allow for use cases where reference.conf references undefined properties, that would be bad practice to do that. What I'm saying is that reference.conf should be able to reference properties that it defines itself, and that application.conf should be able to override them, such that the references in reference.conf to them also pick the overridden value up. In this case, reference.conf is able to be parsed and resolved in isolation, and so checking validity will still work. |
I don't have a REPL working on my laptop right now (which is a good indicator of how much maintenance on this library is lacking!) but I believe with the following reference.conf:
Then this code does not throw now and would throw with this change:
and checkValid() effectively does something like that. I suppose if we did not modify checkValid could resolve the passed-in reference config instead of expecting it to be resolved already, I suppose. Anyway all these threads would need pulling if things were going to still be coherent and accurately-documented after this change |
I'm optimistic we can find a way forward (and 👍 to reopening this) but it would seem to me that part of the issue is that pre-resolved and resolved Configs are the same type, no? I think the |
Agreed that could be worth exploring (two separate types). |
Ah, I understand. I don't think we should change the behaviour of
I disagree. It would be the actual reference config. Let's take a concrete real world example, in Play we have this:
So, the resolved reference configuration returns:
That is the reference configuration. Setting anything in Now if I have an
Conceptually, I've only changed my applications configuration, which is:
Just because
There is something weird though in Typesafe config, and that is that |
If defaultReference remains resolved I think we’d want some new method that returns the unresolved reference config - load() is meant to be a fairly trivial stacking of other methods, so people can come up with their own stacking. I’d have to go digging to see when/why the reference config started to pull in system props. There may be a thread from the past. I’d like to hear from akka team or other popular library users on this change since it certainly could break someone here and there. btw I’m not reopening this since I don’t have an active plan to actually make the PR and there’s way too much open stuff already, but I’m not trying to block someone from working on it. The hard part won’t be the code code change per se but finding all the affected docs and tests and such, I believe. Could be wrong! |
Fixes lightbend#167 This only affects the output of `ConfigFactory.load`. It does not change `ConfigFactory.defaultReference`. This uses the unresolved `reference.conf` in the building of configuration in `ConfigFactory.load`, effectively allowing `application.conf` properties to override variable substitutions in `reference.conf`. However, it still requires `reference.conf` to be fully resolvable, if it isn't, an exception will be thrown. So two resolves are still done during load, it's just that the output of the resolve of `reference.conf` isn't used in building the final configuration. The documentation has been updated to reflect this behavior. The reasoning behind this change can be read about in lightbend#167, but essentially, it is not uncommon for configuration properties to depend on each other by default, a good example of this is directory hierarchies, where you might have a configuration option for a base directory, and then a configuration for the log directory that by default is under the base directory, and within that a configuration for individual log files which by default are under the log directory. Without allowing variable substitutions in `reference.conf` from `application.conf`, there is no point in defining a configuration option for the base directory since changing it won't have any impact, and each path defined that depends on it will have to be manually overridden. This limitation is contrary to convention over configuration best practices, and hence not desirable in a configuration library.
I've created a PR in #619. Where this might break is where a user might be overriding something in Looking at the Akka code base, here are some things it could impact, determined by searching for all variable references, ie, occurances of
There is a chance that something could break in the above. The most likely to break would be the Akka cluster sharding reference to distributed data, the rest are advanced configuration features that are rarely changed, and if they are changed, would likely be advantageous to override the place that references it too. The configuration element in the Akka cluster sharding reference to distributed data that would have the biggest impact is the list of durable keys, but its already overridden by the cluster sharding configuration, so that won't be a problem. The rest of the keys there, I can't imagine why you would want to change one and not the other, for example, why would you override the default durable store for distributed data, but have cluster sharding use the default one? It's possible that you might want to, but unlikely. @patriknw fyi |
@jroper @havocp The proposed behavior by James would be very useful. We have run into that "limitation" many times and had to explain to contributors and ourselves how substitution works. I have always thought it was how it was designed for some reasons and have not challenged it. I agree that it will probably not be any compatibility problems, although I might hesitate dropping it into an Akka 2.5.x patch release. Akka 2.6.0 would be a safe target. It would still be good if this change doesn't require a major release of Typesafe Config because then we might not be able to update in Akka 2.6. |
I should also mention that currently, and for years, we have been using different loading behavior for Akka and Play and that is pretty scary in itself. Would be great to align. |
If y’all were to catalog custom behavior and what would have to change in this library for everyone to use the same default behavior that’s probably a useful exercise (not in this same PR obviously) |
Here's Play's behaviour: Aside from loading
|
* Allow application.conf to override variables in reference.conf Fixes #167 This only affects the output of `ConfigFactory.load`. It does not change `ConfigFactory.defaultReference`. This uses the unresolved `reference.conf` in the building of configuration in `ConfigFactory.load`, effectively allowing `application.conf` properties to override variable substitutions in `reference.conf`. However, it still requires `reference.conf` to be fully resolvable, if it isn't, an exception will be thrown. So two resolves are still done during load, it's just that the output of the resolve of `reference.conf` isn't used in building the final configuration. The documentation has been updated to reflect this behavior. The reasoning behind this change can be read about in #167, but essentially, it is not uncommon for configuration properties to depend on each other by default, a good example of this is directory hierarchies, where you might have a configuration option for a base directory, and then a configuration for the log directory that by default is under the base directory, and within that a configuration for individual log files which by default are under the log directory. Without allowing variable substitutions in `reference.conf` from `application.conf`, there is no point in defining a configuration option for the base directory since changing it won't have any impact, and each path defined that depends on it will have to be manually overridden. This limitation is contrary to convention over configuration best practices, and hence not desirable in a configuration library. * Renamed public method to defaultReferenceUnresolved Also added the methods to ConfigFactory, as requested in code review.
Because reference.conf is fully resolved before merging with main config, the following doesn't work:
reference.conf:
aplication.conf:
file1 and file2 will not be "mydir/file1" paths but "./file1" instead.
The text was updated successfully, but these errors were encountered: