Oh, qwen 3.8, it's too perfect!
I asked, "why don't you change to SCAN instead of KEYS for cache invalidation performance". Then, qwen 3.8 27b performed test code, regression tests, e2e tests, and even benchmarks for 2 HOURS. Here's final report from qwen. God damn! I just asked "small code refactor". It make me monk. --- ### Changes /services/cacheService.js: Added three private helper functions at the top (scanKeys with SCAN collection, Set dedup, and COUNT 500; deleteKeys in chunks of 500 with empty array guard; scanDelete). Replaced redisClient.keys + del blocks across 10 functions with scanDelete (0 remaining instances of redisClient.keys). Maintained Invariants: Pattern strings, static key direct del (e.g., object:{id}, object_stats:{id}, MD5/ISBN keys), try/catch, return values, and invalidateFeedCache's 4-pattern Promise.all + Set dedup structure. redis.js: Unmodified (Phase 2). docs/cache-invalidation.md: Added 5 core principles (key discovery/propagation separation) and updated warning #4 to "Migration Completed". --- ### Verification Results (Local 127.0.0.1) node --check: Passed. Equivalence + Pub/Sub Tests: 17/17 PASS — 10k key bulk deletion in 352ms, 10k/10k key-by-key publish, 0-match empty guard, KEYS vs. SCAN deletion set equivalence (10/10 decoys preserved), feed dedup (same pattern 1 & 3) publishing exactly once, 5 static keys direct del. E2E (PM2 Live Service with Watch Auto-Reload): object_comments comment registration 200 $\rightarrow$ normal invalidation logs $\rightarrow$ new comment ranked 1st in object-comments API (total_count 95 $\rightarrow$ 96, await contract verified) / invalidate-object 13-pattern loop 200 OK / 0 error logs. Cleanup: Deleted comment 5821, saved decision (cache-invalidation-scan). --- ### Performance Measurement & Candid Analysis (Local 556,309 Keys) Legacy KEYS: 11 sequential calls $\approx$ 286ms — Single-threaded Redis blocking across all phases (all node cache reads/writes halted during this window). SCAN (COUNT 500): $\approx$ 141ms per pattern, sub-ms single iteration blocking — Non-blocking. Wall-time lower bound per pattern converges to $\approx$ 100ms (changing COUNT 500 $\rightarrow$ 20000 yields 99ms due to identical server-side scan workload). Takeaway: Comment registration response wall-time is neutral to slightly increased; the real win is eliminating global node blocking (preventing latency spikes for other users' pages/APIs). The plan's expected value ("several seconds $\rightarrow$ tens of ms") depends on the production keyspace scale — since local is 556k keys, a larger production scale would mean a much steeper KEYS penalty, amplifying the blocking-removal benefit. COUNT 500 was retained per the plan to minimize single-iteration blocking. COUNT tuning is recommended if production keyspace scale is known. Next Steps: Local verification complete — Production deployment ready upon approval. Phase 2 candidates are outlined in plan §6 (redis.js del return value restoration, 15+ sidebar/stat locations, removing 11 $\rightarrow$ 8 duplicate patterns, COUNT tuning).