Skip to content

Race condition on values injecting configuration bean into @Refreshable bean #11753

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

Open
sdedic opened this issue Apr 16, 2025 · 1 comment
Open

Comments

@sdedic
Copy link

sdedic commented Apr 16, 2025

Expected Behavior

I have a configuration bean, marked with @ConfigurationProperties and a @Refreshable bean which is injected with the config bean in its constructor, and remembers configuration value, i.e. name (originally it happened to me with a refreshable DataSource factory that was called with the configuration bean).

Since the refresh, and discard of an old bean instance is initiated by configuration change in the beans' specific property subset, I would expect that the bean gets new configuration injected into its constructor (or factory for the bean), so when the @Refreshable bean is re-created after RefreshEvent, it remembers the new values from the @ConfigurationProperties bean.

Actual Behaviour

There's race condition between

  1. the time the @Refreshable bean is destroyed and
  2. the time the @ConfigurationReader bean values are re-read from the property values.

If a service happens to dereference @Refreshable proxy between (1) and (2), for example during processing of an incoming request, a new instance of @Refreshable bean
is created, but the Config bean values are still old, not updated at the time of bean creation. Should the bean configure itself or act upon the Config bean values in the constructor, or @PostCreate, its state becomes inconsistent with the ApplicationContext properties - as they were not yet loaded info the Config bean.

The demo application demonstrates that, creating race condition by using DestroyedBean listener (to act timely between (1) and (2)). Two calues are reported. "Initial" is a value from RacebugConfig bean captured in the constructor; "fresh" is the value directly read from the bean.

This is a snippet from the demo application:

14:17:32.268 [scheduled-executor-thread-9] INFO  com.example.racebug.EagerService - Periodic check: of racebug initial name: "foobar", current name "foobar", from refreshable #2
14:18:02.269 [scheduled-executor-thread-10] INFO  com.example.racebug.EagerService - Periodic check: of racebug initial name: "foobar", current name "foobar", from refreshable #2
14:18:02.270 [scheduled-executor-thread-4] INFO  c.e.c.PeriodicConfigRefresh - Start periodic config refresh
14:18:02.272 [scheduled-executor-thread-4] INFO  c.e.c.PeriodicConfigRefresh - Keys of changed properties: [racebug-config.name]
14:18:02.273 [scheduled-executor-thread-4] INFO  com.example.racebug.EagerTrigger - Reloaded racebug property name DURING refresh: Optional["foo"]
14:18:02.274 [scheduled-executor-thread-4] INFO  com.example.racebug.EagerTrigger - Racebug name DURING refresh: initial "foobar", fresh "foobar"
14:18:02.275 [scheduled-executor-thread-4] INFO  com.example.racebug.EagerTrigger - Reloaded racebug property nameAFTER refresh: Optional["foo"]
14:18:02.275 [scheduled-executor-thread-4] INFO  com.example.racebug.EagerTrigger - Reloaded racebug CONFIG name AFTER refresh: "foo"
14:18:02.275 [scheduled-executor-thread-4] INFO  com.example.racebug.EagerTrigger - Racebug name AFTER refresh initial: "foobar", fresh: "foo"
14:18:32.270 [scheduled-executor-thread-11] INFO  com.example.racebug.EagerService - Periodic check: of racebug initial name: "foobar", current name "foo", from refreshable #3

Initially the refreshable bean reports initial/fresh name "foobar", as it was originally configured. After change in the config file and re-load, the @Refreshable bean is re-created, but now reports different initial and fresh names (see the last line).

Steps To Reproduce

  1. Checkout the repository https://github.com/sdedic/micronaut-dbbugs2, branch refreshable-config
  2. Start the application
  3. Change the racebugConfig.name in config/application.properties
  4. Wait for the periodic refresh, observe logs

Environment Information

  • Ubuntu Linux 22.04
  • Micronaut 4.7.6

Example Application

https://github.com/sdedic/micronaut-dbbugs2

Version

4.7.6

@dstepanov
Copy link
Contributor

I don't think those events are supposted to be synchronized

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

2 participants