Standardize in-process caching behind DW::Cache (request + process scopes) (#3652)
Standardize in-process caching behind DW::Cache (request + process scopes) (#3652)
- Standardize request-scoped caching behind DW::RequestCache
Request caches lived in a sprawl of package globals (%LJ::REQ_CACHE*, %LJ::REQUEST_CACHE, %LJ::S2::REQ_CACHE_*, etc.) wiped by a hand-maintained clear-list in LJ::start_request. That list drifted -- %LJ::REQ_CACHE (UniqCookie) and %LJ::REQ_CACHE_POLL already escaped it and leaked across requests on persistent workers -- and DW::CacheStats kept a second, separately drifting copy for size sampling. The SQS task workers never called start_request at all, so every request cache lived for the whole worker process.
Introduce DW::RequestCache: one module whose single clear() empties everything routed through it, so a cache added here cannot leak. It offers a namespaced KV memoization API (get/set/memoize/remove/clear_ns) plus a registration API (register_var/register_reset) for state that keeps direct package-var access. LJ::start_request's clear-block collapses to one DW::RequestCache->clear call, and DW::CacheStats now samples the same registry it clears (via ->registered), so the two sets can no longer drift.
Migrate all existing request caches onto the interface (users, rel, usertags, trustmask, S2 style/layer/layer-info, poll, uniqcookie, langdatfile, OAuth consumer/access) and register the remaining scratch/accumulator state and singleton resets. Wire DW::TaskQueue::start_work to wrap each job in start_request/end_request, matching the legacy TheSchwartz/Gearman workers; a scope guard guarantees end_request runs on the die and timeout exit paths.
Tests reaching into the old package vars are updated to the new API. Adds t/request-cache.t covering the KV API, registration, the clear() guarantee, and per-request/per-job isolation via LJ::start_request.
Co-Authored-By: Claude Opus 4.8 (1M context) noreply@anthropic.com
Address review: guard ScopeGuard DESTROY and clear OAuth consumer by id
DW::TaskQueue::ScopeGuard::DESTROY now runs its cleanup under local $@ + eval, so a die in LJ::end_request can't mask a job's own exception during unwinding.
- DW::OAuth::Consumer::deletecache clears the request-cache entry keyed by id as well as by token (the consumer is cached under both), matching the memcache invalidation right above it.
Co-Authored-By: Claude Opus 4.8 (1M context) noreply@anthropic.com
- Rework into DW::Cache with request/process scopes; retire DW::CacheStats
Replace DW::RequestCache with DW::Cache, one facade over two scope singletons sharing a single store implementation: DW::Cache->request (wiped per web request / background job by LJ::start_request) and DW::Cache->process (global reference data -- props, moods, codes, styles, translations -- wiped on config reload by LJ::handle_caches, whose hand-maintained clear-list collapses to one process->clear the same way start_request's did). Each scope has the same KV memoization + register_var/register_reset API, and each scope's clear() and sizing draw from the same registry, so cleared and measured sets cannot drift.
DW::CacheStats is deleted. Cache byte sizes are now emitted by
DW::Cache->report_sizes (dw.cache.bytes tagged cache:
t/request-cache.t becomes t/cache.t and also covers scope independence and the handle_caches/process-scope integration.
Co-Authored-By: Claude Opus 4.8 (1M context) noreply@anthropic.com
- Fix stale cache-terminology comments flagged in review
"process cache" comments on request-scope lookups in LJ/User/Account.pm now say "request cache" (an actual process scope exists, so the old wording misleads), and the trusted-anon rationale in LJ/Session.pm + t/session-trust.t no longer cites the retired never-cleared %LJ::REQ_CACHE; t/vgift-trans.t explains the manual rel-cache invalidation instead of referencing REQ_CACHE_REL.
Co-Authored-By: Claude Opus 4.8 (1M context) noreply@anthropic.com
