When caching derived state, you must define (and encode) a validity contract: what exact changes make the cached data incorrect, and how that change is detected (keying and/or TTL/refresh).
Practical rules: 1) Key caches on the right change marker
metadata.modifiedIndex / conf_version as part of cache keys (so rebuild happens on metadata/config change, not only on LRU eviction or TTL).
2) Include secret/external-data drift in validityconf_version, bound staleness with a TTL/refresh or include a secret version in the validity check.
3) Treat delete/empty updates as real changesCode sketch (keying on a change marker):
-- Example pattern: include modifiedIndex in the cache key
local tracer, err = core.lrucache.plugin_ctx(
lrucache,
api_ctx,
metadata.modifiedIndex, -- invalidates/rebuilds on metadata change
create_tracer_obj,
conf,
plugin_info
)
Code sketch (don’t skip deletes/empty updates in incremental reconciliation):
local function filter(val)
if not val.value then
pending_delete = true
has_pending = true
-- record delete so reconciliation removes old entries
return
end
-- ... even if val.value.plugins is empty, still record the update for reconciliation
end
Adhering to these rules prevents security/auth drift, stale behavior that only clears on TTL, and “rebuild-time” bugs caused by inconsistent IDs or non-idempotent refresh logic.
Enter the URL of a public GitHub repository