Commit 9aa324d
Config Server stability improvements (#1667)
* Remove duplicate tests
* Update tests using Sandbox to use MemoryFileProvider (and without delay), to reduce test flakiness
* Update existing test to verify precedence between options and appsettings
* Make ConfigServerClientOptions reactive to configuration changes
`ConfigServerClientOptions` are now re-evaluated from initial options + configuration on every settings change, instead of being mutated in-place. This prevents stale or torn reads when the provider runs concurrently (e.g. polling timer vs reload).
Key changes:
- The provider clones options on each configuration reload, starting from the initial options passed via code, then applying configuration on top. This ensures code-level defaults are restored when keys are removed from configuration.
- Client settings (spring:cloud:config:*) are no longer written into the provider's data dictionary, eliminating a circular feedback loop where the provider's own output could influence its input.
- Discovery lookup results are tracked separately and applied on top of the options snapshot at load time, rather than mutating shared state.
- Client certificate configuration is moved from the source's `Build` method into `ConfigureConfigServerClientOptions`, so it participates in the options pipeline.
- `ConfigServerClientOptions.Clone()` is introduced to produce isolated snapshots, preventing tearing when options are read during a concurrent reload. A bug was fixed that prevented using global certificates.
- An internal `HttpClientHandler` parameter is threaded through the source and builder extensions, enabling direct handler injection for tests without reflection.
- `IOptionsChangeTokenSource<ConfigServerClientOptions>` is registered in DI so that `IOptionsMonitor` properly triggers on configuration changes.
* Improve test coverage
* Fix references to Config Server in comments
* Fix threading bugs and resource leaks in Config Server provider
The provider had several concurrency and lifecycle issues:
- Vault token renewal timers were created unboundedly on every HTTP request that carried a token, leaking timers that were never disposed. Vault renewal is now managed as a single timer with the same lifecycle as the polling timer.
- Timer management, handler configuration, and disposal could race with each other without synchronization. A lifecycle lock now guards these operations, while non-blocking try-enter locks prevent timer callbacks from queueing up.
- The HTTP client handler's certificates were reconfigured on every HTTP request, racing with concurrent requests sharing the same handler. Certificate and validation configuration is now applied once per settings change under the lifecycle lock, with certificates cleared before re-adding to prevent unbounded accumulation across reloads.
- Options cloning did not copy the certificate issuer chain, losing intermediate CA certificates across reloads.
- Disposal is now coordinated via a volatile flag so that in-flight timer callbacks and Load() calls exit gracefully instead of throwing unobserved exceptions.
* Fixed: use latest options snapshot during discovery in Config Server
* Fixed: preserve original stack trace when load throws
* Fix Config Server health contributor to act on a consistent snapshot
* Fix torn reads in _lastDiscoveryLookupResult
* Fixed: act on single snapshot of _httpClientHandler
* Refresh discovery during polled reload and fix lazy initialization race
Polled configuration reloads now refresh the discovery service lookup before fetching from Config Server, enabling detection of server address changes between polling intervals. Unlike initial load, polled reload does not apply FailFast or retry semantics.
Fixed a race where concurrent calls to LoadInternalAsync could create multiple ConfigServerDiscoveryService instances, each constructing their own temporary DI container and discovery clients.
* Fix change callback accumulation on repeated configuration reloads
Each configuration reload re-registered a new change callback via RegisterChangeCallback, without disposing the previous one. Rapid reloads could accumulate stale callbacks, causing redundant OnSettingsChanged invocations on multiple threads.
Replaced with a single ChangeToken.OnChange registration in the constructor, which automatically handles re-registration and is disposed on shutdown.
* Fix HttpClientHandler mutation race and timer disposal race
Replace shared mutable HttpClientHandler with a per-request factory, eliminating the race where OnSettingsChanged reconfigured a handler concurrently in use by HTTP requests. Production code creates and disposes a fresh handler per request; tests inject a factory for mocking.
Replace _isDisposed flag with CancellationToken-based shutdown, enabling in-flight HTTP requests in timer callbacks to terminate promptly on disposal instead of running to completion.
* Fix threadpool starvation during retries
* Fix timer callbacks potentially using stale options when settings change
* Fix stale reads in ConfigServerDiscoveryService
* Add overloads to post-configure Config Server options
* Cleanup existing tests
* Various fixes
- Improved log messages (and don't log multiple times), fix exception stack traces
- Don't remote-fetch twice at startup (load + timer that immediately fired)
- Moved options bind and remote-fetch from constructor to Load, fix combination with placeholder
* Increase timeout to reduce failures in CI
* Update src/Configuration/test/ConfigServer.Test/ConfigServerConfigurationProviderTest.Loading.cs
Co-authored-by: Tim Hess <tim.hess@broadcom.com>
* Review feedback: replace overrule with override
* Review feedback: Change initial to default options
* Review feedback: remove redundant settings in test
* Review feedback: adjust test name
* Review feedback: remove duplicate configuration
* Review feedback: reformat JSON snippets in tests
---------
Co-authored-by: Tim Hess <tim.hess@broadcom.com>1 parent 972d11d commit 9aa324d
67 files changed
Lines changed: 3168 additions & 1917 deletions
File tree
- src
- Bootstrap/src/AutoConfiguration
- Common
- src/Certificates
- test
- Certificates.Test
- Common.Test
- TestResources
- Configuration
- src
- Abstractions
- ConfigServer
- test
- ConfigServer.Discovery.Test
- ConfigServer.Integration.Test
- ConfigServer.Test
- Placeholder.Test
- Connectors/test/Connectors.Test
- Discovery
- src
- Consul/Registry
- Eureka
- test
- Configuration.Test
- Eureka.Test
- HttpClients.Test
- Logging/test
- DynamicConsole.Test
- DynamicSerilog.Test
- Management
- src/Endpoint
- Configuration
- test
- Endpoint.Test
- Actuators
- CloudFoundry
- Environment
- Health
- HttpExchanges
- Hypermedia
- Loggers
- Refresh
- RouteMappings
- SpringBootAdminClient
- RazorPagesTestWebApp
Some content is hidden
Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
91 | 91 | | |
92 | 92 | | |
93 | 93 | | |
94 | | - | |
| 94 | + | |
95 | 95 | | |
96 | 96 | | |
97 | 97 | | |
| |||
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
14 | 14 | | |
15 | 15 | | |
16 | 16 | | |
17 | | - | |
18 | 17 | | |
| 18 | + | |
| 19 | + | |
| 20 | + | |
| 21 | + | |
| 22 | + | |
| 23 | + | |
| 24 | + | |
| 25 | + | |
| 26 | + | |
| 27 | + | |
| 28 | + | |
| 29 | + | |
| 30 | + | |
| 31 | + | |
| 32 | + | |
19 | 33 | | |
Lines changed: 3 additions & 3 deletions
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
148 | 148 | | |
149 | 149 | | |
150 | 150 | | |
151 | | - | |
| 151 | + | |
152 | 152 | | |
153 | 153 | | |
154 | 154 | | |
| |||
167 | 167 | | |
168 | 168 | | |
169 | 169 | | |
170 | | - | |
| 170 | + | |
171 | 171 | | |
172 | 172 | | |
173 | 173 | | |
| |||
185 | 185 | | |
186 | 186 | | |
187 | 187 | | |
188 | | - | |
| 188 | + | |
189 | 189 | | |
190 | 190 | | |
191 | 191 | | |
| |||
Lines changed: 5 additions & 8 deletions
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
7 | 7 | | |
8 | 8 | | |
9 | 9 | | |
10 | | - | |
11 | 10 | | |
12 | 11 | | |
13 | 12 | | |
| |||
24 | 23 | | |
25 | 24 | | |
26 | 25 | | |
27 | | - | |
| 26 | + | |
28 | 27 | | |
29 | 28 | | |
30 | 29 | | |
| |||
34 | 33 | | |
35 | 34 | | |
36 | 35 | | |
37 | | - | |
38 | | - | |
39 | | - | |
40 | | - | |
| 36 | + | |
| 37 | + | |
| 38 | + | |
41 | 39 | | |
42 | | - | |
43 | | - | |
| 40 | + | |
44 | 41 | | |
45 | 42 | | |
46 | 43 | | |
| |||
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
12 | 12 | | |
13 | 13 | | |
14 | 14 | | |
15 | | - | |
16 | | - | |
17 | 15 | | |
18 | 16 | | |
19 | 17 | | |
| |||
Lines changed: 36 additions & 0 deletions
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
| 1 | + | |
| 2 | + | |
| 3 | + | |
| 4 | + | |
| 5 | + | |
| 6 | + | |
| 7 | + | |
| 8 | + | |
| 9 | + | |
| 10 | + | |
| 11 | + | |
| 12 | + | |
| 13 | + | |
| 14 | + | |
| 15 | + | |
| 16 | + | |
| 17 | + | |
| 18 | + | |
| 19 | + | |
| 20 | + | |
| 21 | + | |
| 22 | + | |
| 23 | + | |
| 24 | + | |
| 25 | + | |
| 26 | + | |
| 27 | + | |
| 28 | + | |
| 29 | + | |
| 30 | + | |
| 31 | + | |
| 32 | + | |
| 33 | + | |
| 34 | + | |
| 35 | + | |
| 36 | + | |
Lines changed: 77 additions & 0 deletions
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
| 1 | + | |
| 2 | + | |
| 3 | + | |
| 4 | + | |
| 5 | + | |
| 6 | + | |
| 7 | + | |
| 8 | + | |
| 9 | + | |
| 10 | + | |
| 11 | + | |
| 12 | + | |
| 13 | + | |
| 14 | + | |
| 15 | + | |
| 16 | + | |
| 17 | + | |
| 18 | + | |
| 19 | + | |
| 20 | + | |
| 21 | + | |
| 22 | + | |
| 23 | + | |
| 24 | + | |
| 25 | + | |
| 26 | + | |
| 27 | + | |
| 28 | + | |
| 29 | + | |
| 30 | + | |
| 31 | + | |
| 32 | + | |
| 33 | + | |
| 34 | + | |
| 35 | + | |
| 36 | + | |
| 37 | + | |
| 38 | + | |
| 39 | + | |
| 40 | + | |
| 41 | + | |
| 42 | + | |
| 43 | + | |
| 44 | + | |
| 45 | + | |
| 46 | + | |
| 47 | + | |
| 48 | + | |
| 49 | + | |
| 50 | + | |
| 51 | + | |
| 52 | + | |
| 53 | + | |
| 54 | + | |
| 55 | + | |
| 56 | + | |
| 57 | + | |
| 58 | + | |
| 59 | + | |
| 60 | + | |
| 61 | + | |
| 62 | + | |
| 63 | + | |
| 64 | + | |
| 65 | + | |
| 66 | + | |
| 67 | + | |
| 68 | + | |
| 69 | + | |
| 70 | + | |
| 71 | + | |
| 72 | + | |
| 73 | + | |
| 74 | + | |
| 75 | + | |
| 76 | + | |
| 77 | + | |
Lines changed: 2 additions & 3 deletions
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
53 | 53 | | |
54 | 54 | | |
55 | 55 | | |
| 56 | + | |
| 57 | + | |
56 | 58 | | |
57 | | - | |
58 | | - | |
59 | | - | |
60 | 59 | | |
61 | 60 | | |
62 | 61 | | |
| |||
Lines changed: 56 additions & 7 deletions
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
17 | 17 | | |
18 | 18 | | |
19 | 19 | | |
20 | | - | |
21 | 20 | | |
22 | 21 | | |
23 | 22 | | |
| 23 | + | |
| 24 | + | |
| 25 | + | |
| 26 | + | |
| 27 | + | |
24 | 28 | | |
25 | 29 | | |
26 | 30 | | |
| |||
35 | 39 | | |
36 | 40 | | |
37 | 41 | | |
38 | | - | |
| 42 | + | |
39 | 43 | | |
40 | 44 | | |
41 | 45 | | |
| |||
96 | 100 | | |
97 | 101 | | |
98 | 102 | | |
99 | | - | |
| 103 | + | |
100 | 104 | | |
101 | 105 | | |
102 | 106 | | |
103 | 107 | | |
104 | | - | |
| 108 | + | |
105 | 109 | | |
106 | 110 | | |
107 | 111 | | |
108 | 112 | | |
109 | | - | |
| 113 | + | |
110 | 114 | | |
111 | 115 | | |
112 | 116 | | |
| |||
129 | 133 | | |
130 | 134 | | |
131 | 135 | | |
132 | | - | |
| 136 | + | |
133 | 137 | | |
134 | 138 | | |
135 | 139 | | |
| |||
141 | 145 | | |
142 | 146 | | |
143 | 147 | | |
144 | | - | |
| 148 | + | |
| 149 | + | |
| 150 | + | |
| 151 | + | |
| 152 | + | |
| 153 | + | |
| 154 | + | |
| 155 | + | |
| 156 | + | |
| 157 | + | |
| 158 | + | |
| 159 | + | |
| 160 | + | |
| 161 | + | |
| 162 | + | |
| 163 | + | |
| 164 | + | |
| 165 | + | |
| 166 | + | |
| 167 | + | |
| 168 | + | |
| 169 | + | |
| 170 | + | |
| 171 | + | |
| 172 | + | |
| 173 | + | |
| 174 | + | |
| 175 | + | |
| 176 | + | |
| 177 | + | |
| 178 | + | |
| 179 | + | |
| 180 | + | |
| 181 | + | |
| 182 | + | |
| 183 | + | |
| 184 | + | |
| 185 | + | |
| 186 | + | |
| 187 | + | |
| 188 | + | |
| 189 | + | |
| 190 | + | |
| 191 | + | |
| 192 | + | |
| 193 | + | |
145 | 194 | | |
146 | 195 | | |
147 | 196 | | |
| |||
0 commit comments