Commit 214c90b
Replace async-disabling mechanism with retry backoff on refresh failure (#696)
## Summary
Replace the cache's staleness tracking with a cached `staleAfter`
timestamp and preserve the legacy `staleDuration` builder path. Async
refresh failures now use a short retry backoff instead of suppressing
background refresh until the token expires.
## Why
`CachedTokenSource` previously mixed relative stale-window calculations
with token expiry checks, which made the cache state harder to reason
about and made it easier to regress callers that explicitly configure
`staleDuration` through the builder. At the same time, a failed async
refresh effectively disabled further async refreshes until a blocking
refresh happened on expiry, which meant a brief transient failure could
prevent the SDK from recovering proactively for the rest of the token
lifetime.
This PR moves the cache to an absolute `staleAfter` threshold that is
computed whenever a token is stored. That makes the state model much
clearer: callers now classify tokens by comparing the current time
against `staleAfter` and the expiry buffer. It also preserves the legacy
fixed-window behavior for callers that set `staleDuration`, and replaces
the old async-failure suppression behavior with a one-minute retry
backoff so transient failures can recover without waiting for full
expiry.
## What changed
### Interface changes
None.
### Behavioral changes
Calls that set `staleDuration` through
`CachedTokenSource.Builder#setStaleDuration(...)` continue to get the
legacy fixed-window behavior. The cache now recomputes `staleAfter` from
that configured duration each time a token is stored, so both the
initial cached token and later refreshed tokens honor the same
caller-provided setting.
Failed async refreshes no longer block future async refresh attempts
until a blocking refresh on expiry. Instead, the cache moves
`staleAfter` one minute into the future, treats the token as fresh
during that cooldown, and retries async refresh the next time the token
becomes stale again.
Older async refresh results are also ignored when the cache already
holds a newer token. This prevents a late async refresh from overwriting
a token with a later expiry that was installed by another refresh path.
### Internal changes
`CachedTokenSource` now stores an absolute `staleAfter` instant rather
than reasoning about staleness from relative durations at read time.
When callers do not provide `staleDuration`, the stale threshold is
derived from the token's remaining TTL at the moment the token is stored
and capped at 20 minutes. This centralizes stale-threshold computation
in `updateToken()` and reduces token-state checks to direct time
comparisons.
The implementation adds `_ASYNC_REFRESH_RETRY_BACKOFF`-equivalent
behavior for Java via `ASYNC_REFRESH_RETRY_BACKOFF`, introduces
`handleFailedAsyncRefresh()` to apply the retry cooldown, and adds
`cachedTokenIsNewer()` to discard async refresh results that would
otherwise roll the cache back to an older token.
`CachedTokenSourceTest` was updated to replace the old async-failure
fallback coverage with parameterized `staleAfter` initialization
coverage and explicit retry-backoff tests.
## How is this tested?
Ran the focused unit test suite for `CachedTokenSource` and the module
formatting check locally:
- `mvn --errors -pl databricks-sdk-java -Dtest=CachedTokenSourceTest
test`
- `mvn --errors -pl databricks-sdk-java spotless:check`
Test coverage now includes:
- Existing async refresh state coverage in
`testAsyncRefreshParametrized`
- `testStaleAfterComputationParametrized` for `staleAfter`
initialization across legacy builder-provided `staleDuration`, default
computed thresholds, null initial tokens, and expired tokens
- `testGetTokenDoesNotRetryBeforeAsyncBackoffElapses` to verify repeated
reads during the cooldown do not trigger additional refreshes
- `testGetTokenRetriesAfterAsyncBackoffElapsesAndUpdatesToken` to verify
a read after the cooldown elapses starts a new async refresh and updates
the cached token
---------
Co-authored-by: Claude Opus 4.6 (1M context) <noreply@anthropic.com>1 parent f518c27 commit 214c90b
File tree
3 files changed
+391
-156
lines changed- databricks-sdk-java/src
- main/java/com/databricks/sdk/core/oauth
- test/java/com/databricks/sdk/core/oauth
3 files changed
+391
-156
lines changed| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
11 | 11 | | |
12 | 12 | | |
13 | 13 | | |
| 14 | + | |
14 | 15 | | |
15 | 16 | | |
Lines changed: 109 additions & 70 deletions
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
38 | 38 | | |
39 | 39 | | |
40 | 40 | | |
| 41 | + | |
| 42 | + | |
41 | 43 | | |
42 | 44 | | |
43 | 45 | | |
44 | 46 | | |
45 | 47 | | |
46 | | - | |
| 48 | + | |
47 | 49 | | |
48 | 50 | | |
49 | 51 | | |
50 | 52 | | |
51 | 53 | | |
52 | 54 | | |
53 | | - | |
54 | | - | |
55 | | - | |
| 55 | + | |
| 56 | + | |
| 57 | + | |
56 | 58 | | |
57 | 59 | | |
58 | 60 | | |
| |||
62 | 64 | | |
63 | 65 | | |
64 | 66 | | |
65 | | - | |
66 | | - | |
67 | 67 | | |
68 | 68 | | |
69 | 69 | | |
70 | 70 | | |
71 | 71 | | |
72 | | - | |
| 72 | + | |
73 | 73 | | |
74 | 74 | | |
75 | | - | |
76 | 75 | | |
77 | | - | |
78 | | - | |
79 | | - | |
80 | | - | |
81 | | - | |
| 76 | + | |
82 | 77 | | |
83 | 78 | | |
84 | 79 | | |
| |||
91 | 86 | | |
92 | 87 | | |
93 | 88 | | |
94 | | - | |
| 89 | + | |
95 | 90 | | |
96 | 91 | | |
97 | 92 | | |
| |||
139 | 134 | | |
140 | 135 | | |
141 | 136 | | |
142 | | - | |
| 137 | + | |
| 138 | + | |
| 139 | + | |
| 140 | + | |
143 | 141 | | |
144 | 142 | | |
145 | 143 | | |
146 | 144 | | |
147 | 145 | | |
148 | 146 | | |
149 | 147 | | |
150 | | - | |
| 148 | + | |
151 | 149 | | |
152 | 150 | | |
153 | 151 | | |
| |||
190 | 188 | | |
191 | 189 | | |
192 | 190 | | |
| 191 | + | |
| 192 | + | |
| 193 | + | |
| 194 | + | |
| 195 | + | |
| 196 | + | |
| 197 | + | |
| 198 | + | |
| 199 | + | |
| 200 | + | |
| 201 | + | |
| 202 | + | |
| 203 | + | |
| 204 | + | |
| 205 | + | |
| 206 | + | |
| 207 | + | |
| 208 | + | |
| 209 | + | |
| 210 | + | |
| 211 | + | |
| 212 | + | |
| 213 | + | |
| 214 | + | |
| 215 | + | |
| 216 | + | |
| 217 | + | |
| 218 | + | |
| 219 | + | |
| 220 | + | |
| 221 | + | |
| 222 | + | |
| 223 | + | |
| 224 | + | |
| 225 | + | |
| 226 | + | |
| 227 | + | |
| 228 | + | |
| 229 | + | |
| 230 | + | |
| 231 | + | |
| 232 | + | |
| 233 | + | |
| 234 | + | |
| 235 | + | |
| 236 | + | |
| 237 | + | |
| 238 | + | |
| 239 | + | |
| 240 | + | |
| 241 | + | |
| 242 | + | |
| 243 | + | |
| 244 | + | |
| 245 | + | |
| 246 | + | |
| 247 | + | |
| 248 | + | |
| 249 | + | |
| 250 | + | |
| 251 | + | |
| 252 | + | |
| 253 | + | |
| 254 | + | |
| 255 | + | |
193 | 256 | | |
194 | 257 | | |
195 | 258 | | |
| |||
206 | 269 | | |
207 | 270 | | |
208 | 271 | | |
209 | | - | |
210 | | - | |
211 | | - | |
212 | | - | |
213 | | - | |
214 | | - | |
215 | | - | |
216 | | - | |
217 | | - | |
218 | | - | |
219 | | - | |
220 | | - | |
221 | | - | |
222 | | - | |
223 | | - | |
224 | 272 | | |
225 | 273 | | |
226 | 274 | | |
| |||
234 | 282 | | |
235 | 283 | | |
236 | 284 | | |
237 | | - | |
238 | | - | |
| 285 | + | |
| 286 | + | |
239 | 287 | | |
240 | 288 | | |
241 | | - | |
242 | | - | |
| 289 | + | |
243 | 290 | | |
244 | 291 | | |
245 | 292 | | |
| |||
265 | 312 | | |
266 | 313 | | |
267 | 314 | | |
268 | | - | |
269 | 315 | | |
270 | 316 | | |
271 | 317 | | |
272 | 318 | | |
273 | 319 | | |
274 | 320 | | |
275 | 321 | | |
276 | | - | |
277 | 322 | | |
278 | | - | |
279 | | - | |
280 | | - | |
281 | | - | |
282 | | - | |
283 | | - | |
284 | | - | |
| 323 | + | |
285 | 324 | | |
286 | 325 | | |
287 | 326 | | |
| |||
316 | 355 | | |
317 | 356 | | |
318 | 357 | | |
319 | | - | |
320 | | - | |
321 | | - | |
322 | | - | |
323 | | - | |
324 | | - | |
325 | | - | |
326 | | - | |
327 | | - | |
328 | | - | |
329 | | - | |
330 | | - | |
331 | | - | |
332 | | - | |
333 | | - | |
334 | | - | |
335 | | - | |
336 | | - | |
337 | | - | |
338 | | - | |
339 | | - | |
340 | | - | |
341 | | - | |
342 | | - | |
| 358 | + | |
| 359 | + | |
| 360 | + | |
| 361 | + | |
| 362 | + | |
| 363 | + | |
| 364 | + | |
| 365 | + | |
| 366 | + | |
| 367 | + | |
| 368 | + | |
| 369 | + | |
| 370 | + | |
| 371 | + | |
| 372 | + | |
343 | 373 | | |
344 | 374 | | |
345 | | - | |
346 | | - | |
| 375 | + | |
| 376 | + | |
| 377 | + | |
| 378 | + | |
| 379 | + | |
| 380 | + | |
| 381 | + | |
| 382 | + | |
| 383 | + | |
| 384 | + | |
| 385 | + | |
347 | 386 | | |
348 | 387 | | |
0 commit comments