feat(menu): wire cache-ttl property to a CachingMenuProvider decorator#23
Merged
Conversation
Follow-up #5/5 to the contract-gap series. #18 exposed `devslab.kit.menu.cache-ttl-seconds` on the Settings endpoint but the property wasn't actually wired to anything. This PR makes it real. Property -------- - DevslabKitProperties.Menu gains cacheTtl Duration (default PT5M). A zero or negative duration disables the cache decorator entirely — the right behaviour for tests that mutate menus or permissions and need the next read to see the change immediately. CachingMenuProvider ------------------- - New menu-core CachingMenuProvider decorator wrapping any MenuProvider: * Per-user keying (user.id) — the delegate's MenuTree is already permission-filtered, so the result varies per user even inside the same tenant. Per-user keys keep the cache correct without invalidation on tenant-wide menu edits; the TTL handles that. * ConcurrentHashMap with per-entry expiry timestamps. Lazy eviction on read, no background thread, no LRU bound. Plenty for "a few dozen admins per tenant, menus loaded once per session" — swap in Caffeine if the access pattern outgrows it. * Manual invalidate(userId) and invalidateAll() exposed for admin tooling that mutates menus and wants the next read to skip the cache. * Inject Clock so tests can advance time without sleeping. Wiring (autoconfigure) ---------------------- - MenuAutoConfiguration.menuProvider: * Builds the database-backed DefaultMenuProvider as before. * Wraps it in CachingMenuProvider when devslab.kit.menu.cache-ttl is positive (default 5m). * Skips the decorator when ttl <= 0 — returns the bare DefaultMenuProvider. - @EnableConfigurationProperties added so the new Duration field binds correctly from configuration sources.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Follow-up #5/5 (and last of the backend wiring). #18 exposed
devslab.kit.menu.cache-ttl-secondson the Settings endpoint but the property wasn't actually wired to anything. This PR makes it real.Property
DevslabKitProperties.Menu.cacheTtl(Duration, defaultPT5M). A zero or negative duration disables the cache decorator entirely — the right behaviour for tests that mutate menus or permissions and need the next read to see the change immediately.CachingMenuProviderNew
menu-coredecorator wrapping anyMenuProvider:user.id()) — the delegate'sMenuTreeis already permission-filtered, so the result varies per user even inside the same tenant. Per-user keys keep the cache correct without invalidation on tenant-wide menu edits; the TTL handles that.ConcurrentHashMapwith per-entry expiry timestamps. Lazy eviction on read, no background thread, no LRU bound. Plenty for "a few dozen admins per tenant, menus loaded once per session" — swap in Caffeine if the access pattern outgrows it.invalidate(userId)andinvalidateAll()exposed for admin tooling that mutates menus and wants the next read to skip the cache.Clockso tests can advance time without sleeping.Wiring (
autoconfigure)MenuAutoConfiguration.menuProvider:DefaultMenuProvideras before.CachingMenuProviderwhendevslab.kit.menu.cache-ttlis positive (default 5m).ttl <= 0— returns the bareDefaultMenuProvider.@EnableConfigurationPropertiesadded so the newDurationfield binds correctly from configuration sources.Test plan
./gradlew buildgreen (55 tasks; sample-app context loads, all tests pass)devslab.kit.menu.cache-ttl=PT0S, hit/menusadmin endpoint, change a menu, hit/menus/treefrom the UI → see the change immediately. Then setPT5M, repeat, confirm the change is delayed up to 5m or untilinvalidate*()is called.Series wrap
This was the last of the five backend follow-ups. The full back-half of the contract-gap series:
outcome/ip/userAgentfirst-class onAuditEventPolicyEvaluationricher decision (reason + matchedRules)PermissionGrantpath on DiagnosticsmatchedViaasync-queue-capacitywired to a bounded executorcache-ttlwired to a per-user caching decoratorThe admin-ui's 9 CRUD pages still ship with hardcoded English labels — i18n migration of those pages is the last open item; landing it on the UI repo separately.