Commit 3c37671
committed
fix(cache): implement proper caching strategies per industry best practices
Audit and fix caching implementation against cache-aside, write-through,
thundering herd prevention, and stale-while-revalidate patterns.
Thundering herd prevention:
- findById() and findByKey() now use Caffeine's get(key, loader) which
coalesces concurrent cache misses into a single DB query. Previously
used getIfPresent() + manual put, meaning N concurrent misses for the
same key caused N parallel database queries.
TTL jitter (mass expiry prevention):
- Cache expiration times now include configurable random jitter (default
10% of TTL). A 30-minute TTL becomes 27-33 minutes. Prevents stampede
when preload() writes thousands of entries at the same instant and they
all expire together.
Stale-while-revalidate:
- New refreshAfterWrite option in CacheConfig. When set, expired entries
serve stale data immediately while Caffeine triggers an async background
reload. Users never block on cache revalidation. Leverages Caffeine's
native refresh mechanism.
Bounded preload:
- Added preload(int limit) and preloadAsync(int limit) for large tables.
Previous preload() loaded the entire table into memory with no safety
bound.
Cache observability:
- Added logCacheStats() method that logs hit rate, hit/miss counts,
eviction count, and cache size per layer at INFO level. Stats were
recorded via recordStats() but never surfaced.
Cache contract documentation:
- Documented staleness window, invalidation strategy, cold start
behavior, and consistency model in class javadoc.
Cross-population:
- findById() now cross-populates the key cache on hit, and findByKey()
cross-populates the ID cache. Previously each layer was only populated
through its own lookup path.
CacheConfig additions:
- refreshAfterWrite (Duration) — stale-while-revalidate trigger
- jitterPercent (int, 0-50) — TTL jitter percentage1 parent aec212c commit 3c37671
2 files changed
Lines changed: 205 additions & 97 deletions
File tree
- src/main/java/de/jexcellence/jehibernate/repository/base
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
505 | 505 | | |
506 | 506 | | |
507 | 507 | | |
508 | | - | |
| 508 | + | |
| 509 | + | |
| 510 | + | |
| 511 | + | |
| 512 | + | |
| 513 | + | |
| 514 | + | |
| 515 | + | |
| 516 | + | |
| 517 | + | |
| 518 | + | |
| 519 | + | |
509 | 520 | | |
510 | 521 | | |
511 | 522 | | |
| |||
521 | 532 | | |
522 | 533 | | |
523 | 534 | | |
| 535 | + | |
| 536 | + | |
| 537 | + | |
| 538 | + | |
| 539 | + | |
| 540 | + | |
| 541 | + | |
| 542 | + | |
| 543 | + | |
| 544 | + | |
| 545 | + | |
| 546 | + | |
| 547 | + | |
| 548 | + | |
| 549 | + | |
524 | 550 | | |
525 | | - | |
526 | | - | |
527 | | - | |
528 | | - | |
| 551 | + | |
| 552 | + | |
| 553 | + | |
| 554 | + | |
529 | 555 | | |
530 | 556 | | |
531 | 557 | | |
| |||
534 | 560 | | |
535 | 561 | | |
536 | 562 | | |
537 | | - | |
| 563 | + | |
| 564 | + | |
538 | 565 | | |
539 | | - | |
| 566 | + | |
| 567 | + | |
540 | 568 | | |
541 | 569 | | |
542 | 570 | | |
543 | 571 | | |
| 572 | + | |
| 573 | + | |
| 574 | + | |
| 575 | + | |
| 576 | + | |
| 577 | + | |
| 578 | + | |
| 579 | + | |
| 580 | + | |
| 581 | + | |
| 582 | + | |
544 | 583 | | |
545 | 584 | | |
546 | 585 | | |
| |||
859 | 898 | | |
860 | 899 | | |
861 | 900 | | |
862 | | - | |
| 901 | + | |
0 commit comments