Commit d99f37e
authored
## Description
Add a two-layer cache for OverDrive collection tokens so they are
automatically refreshed as OverDrive rotates them, without requiring a
process restart or configuration change.
## Motivation and Context
OverDrive is retiring legacy collection tokens within the next 3–4
months
and moving to a model where tokens must be refreshed periodically.
`collectionToken` is embedded in the library account response
(`GET /v1/libraries/{id}`) and is required for all collection-scoped API
calls (search, product listings, availability, metadata).
Two problems existed in the prior implementation:
1. **DB cache had no TTL.** `get_library()` and
`get_advantage_accounts()`
called `Representation.get()` with no `max_age`, so the library document
(and the `collectionToken` within it) could persist in the
`representations` table indefinitely.
2. **In-memory cache was unbounded.** `_collection_token` was a plain
`str | None` set once and never cleared. Flask workers hold one
`OverdriveAPI` instance per collection for the entire process lifetime
(`CirculationManager.load_settings`), so a rotated token would never be
picked up without a full process restart or an admin config change.
### Solution: two-layer cache
| Layer | Constant | TTL | Purpose |
|---|---|---|---|
| In-memory (`_cached_collection_token`) | `COLLECTION_TOKEN_MAX_AGE` |
5 minutes | Avoids a DB hit on every request |
| DB (`representations` table) | `LIBRARY_MAX_AGE` | 30 days | Avoids a
network hit on every 5-minute miss |
A long-lived Flask worker re-checks the DB every 5 minutes and the DB
re-fetches from OverDrive every 30 days. Rotated tokens are picked up
within 5 minutes.
## How Has This Been Tested?
- `test_collection_token` — verifies the in-memory cache is populated on
first access and reused on subsequent calls within
`COLLECTION_TOKEN_MAX_AGE`.
- `test_collection_token_cache_expires` — verifies that aging the
in-memory cache past `COLLECTION_TOKEN_MAX_AGE` causes `get_library` to
be called again and returns the new token.
- `test_collection_token_error` — verifies that an `errorCode` in the
library response raises `CannotLoadConfiguration`.
- `test_get_library_passes_max_age` — verifies `LIBRARY_MAX_AGE` is
forwarded to `Representation.get()` in `get_library()`.
- `test_get_library_refreshes_stale_token` — end-to-end DB staleness
test:
ages the `Representation` record past `LIBRARY_MAX_AGE` and verifies the
next call re-fetches from the network.
- `test_get_advantage_accounts_passes_max_age` — verifies
`LIBRARY_MAX_AGE`
is also forwarded in the advantage accounts `Representation.get()` call.
## Checklist
- [x] I have updated the documentation accordingly.
- [x] All new and existing tests passed.
1 parent 0312188 commit d99f37e
4 files changed
Lines changed: 111 additions & 28 deletions
File tree
- src/palace/manager/integration/license/overdrive
- tests
- manager/integration/license/overdrive
- mocks
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
241 | 241 | | |
242 | 242 | | |
243 | 243 | | |
| 244 | + | |
| 245 | + | |
| 246 | + | |
| 247 | + | |
| 248 | + | |
| 249 | + | |
| 250 | + | |
| 251 | + | |
| 252 | + | |
| 253 | + | |
| 254 | + | |
| 255 | + | |
| 256 | + | |
244 | 257 | | |
245 | 258 | | |
246 | 259 | | |
| |||
309 | 322 | | |
310 | 323 | | |
311 | 324 | | |
312 | | - | |
313 | | - | |
| 325 | + | |
| 326 | + | |
| 327 | + | |
| 328 | + | |
| 329 | + | |
314 | 330 | | |
315 | 331 | | |
316 | 332 | | |
| |||
381 | 397 | | |
382 | 398 | | |
383 | 399 | | |
384 | | - | |
| 400 | + | |
| 401 | + | |
| 402 | + | |
| 403 | + | |
| 404 | + | |
| 405 | + | |
| 406 | + | |
385 | 407 | | |
386 | 408 | | |
387 | | - | |
388 | | - | |
389 | | - | |
390 | | - | |
391 | | - | |
392 | | - | |
393 | | - | |
394 | | - | |
395 | | - | |
396 | | - | |
397 | | - | |
398 | | - | |
399 | | - | |
| 409 | + | |
| 410 | + | |
| 411 | + | |
| 412 | + | |
| 413 | + | |
| 414 | + | |
| 415 | + | |
| 416 | + | |
| 417 | + | |
| 418 | + | |
| 419 | + | |
| 420 | + | |
| 421 | + | |
| 422 | + | |
| 423 | + | |
| 424 | + | |
| 425 | + | |
| 426 | + | |
400 | 427 | | |
401 | 428 | | |
402 | 429 | | |
| |||
531 | 558 | | |
532 | 559 | | |
533 | 560 | | |
| 561 | + | |
| 562 | + | |
| 563 | + | |
| 564 | + | |
| 565 | + | |
534 | 566 | | |
535 | 567 | | |
536 | 568 | | |
| |||
539 | 571 | | |
540 | 572 | | |
541 | 573 | | |
| 574 | + | |
542 | 575 | | |
543 | 576 | | |
544 | 577 | | |
545 | 578 | | |
546 | 579 | | |
547 | 580 | | |
| 581 | + | |
| 582 | + | |
| 583 | + | |
| 584 | + | |
548 | 585 | | |
549 | 586 | | |
550 | 587 | | |
| |||
561 | 598 | | |
562 | 599 | | |
563 | 600 | | |
| 601 | + | |
564 | 602 | | |
565 | 603 | | |
566 | 604 | | |
| |||
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
27 | 27 | | |
28 | 28 | | |
29 | 29 | | |
30 | | - | |
| 30 | + | |
| 31 | + | |
| 32 | + | |
| 33 | + | |
31 | 34 | | |
32 | 35 | | |
33 | 36 | | |
| |||
1548 | 1551 | | |
1549 | 1552 | | |
1550 | 1553 | | |
1551 | | - | |
1552 | | - | |
1553 | | - | |
1554 | | - | |
1555 | | - | |
1556 | | - | |
1557 | | - | |
| 1554 | + | |
| 1555 | + | |
1558 | 1556 | | |
1559 | 1557 | | |
1560 | 1558 | | |
1561 | | - | |
| 1559 | + | |
| 1560 | + | |
1562 | 1561 | | |
1563 | 1562 | | |
1564 | 1563 | | |
| 1564 | + | |
| 1565 | + | |
| 1566 | + | |
| 1567 | + | |
| 1568 | + | |
| 1569 | + | |
| 1570 | + | |
| 1571 | + | |
| 1572 | + | |
| 1573 | + | |
| 1574 | + | |
| 1575 | + | |
| 1576 | + | |
| 1577 | + | |
| 1578 | + | |
| 1579 | + | |
| 1580 | + | |
| 1581 | + | |
| 1582 | + | |
| 1583 | + | |
| 1584 | + | |
| 1585 | + | |
| 1586 | + | |
| 1587 | + | |
| 1588 | + | |
| 1589 | + | |
| 1590 | + | |
| 1591 | + | |
| 1592 | + | |
| 1593 | + | |
| 1594 | + | |
| 1595 | + | |
| 1596 | + | |
| 1597 | + | |
| 1598 | + | |
| 1599 | + | |
| 1600 | + | |
1565 | 1601 | | |
1566 | 1602 | | |
1567 | 1603 | | |
| |||
Lines changed: 9 additions & 2 deletions
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
2 | 2 | | |
3 | 3 | | |
4 | 4 | | |
| 5 | + | |
5 | 6 | | |
6 | 7 | | |
7 | 8 | | |
8 | 9 | | |
9 | 10 | | |
10 | 11 | | |
11 | 12 | | |
12 | | - | |
| 13 | + | |
| 14 | + | |
| 15 | + | |
| 16 | + | |
13 | 17 | | |
14 | 18 | | |
15 | 19 | | |
16 | 20 | | |
17 | 21 | | |
18 | 22 | | |
| 23 | + | |
19 | 24 | | |
20 | 25 | | |
21 | 26 | | |
| |||
70 | 75 | | |
71 | 76 | | |
72 | 77 | | |
73 | | - | |
| 78 | + | |
| 79 | + | |
| 80 | + | |
74 | 81 | | |
75 | 82 | | |
76 | 83 | | |
| |||
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
19 | 19 | | |
20 | 20 | | |
21 | 21 | | |
22 | | - | |
| 22 | + | |
| 23 | + | |
| 24 | + | |
23 | 25 | | |
24 | 26 | | |
25 | 27 | | |
0 commit comments