PUL-22: replace whole-snapshot Redis cache with cheap, targeted reads - #15
Merged
Merged
Conversation
The Redis snapshot cache shipped earlier for PUL-22 doesn't survive real scale: a real 22,210-order store serializes to 188.31MB, which blows past Upstash's entire free-tier storage quota and times out on every write -- confirmed by testing against a live production store. Every write was silently failing (by design, so a cache failure never breaks a request), which meant the cache was never actually caching anything for this store. Replaces it with three narrower fixes instead of a bigger Redis blob: - getAnalyticsForVersion() (analytics/cache.ts) checks the existing Postgres-bytea shared analytics cache using just the store's URL and last-sync timestamp -- both already on hand, no query required -- before paying for a full snapshot reassembly. /api/analytics and /api/reports/export now use this fast path; on a cache hit neither ever touches the raw order/customer/product mirror. - readProducts(), readMostRecentCurrency() and readPhoneByCustomerKey() (mirror.ts) answer the product picker and inbox chat-enrichment routes directly from narrow, targeted queries instead of pulling in the entire order history to answer a question about 53 products or a phone number. - A partial expression index on woo_orders' billing phone (new migration) cuts readPhoneByCustomerKey from ~8s to ~1.7s on the real store. The sync routes now warm the shared analytics cache after a sync instead of the raw snapshot, since that's what the hot paths actually read. Testing against naturesjoystore.com (22,211 real orders) also surfaced a separate, deeper issue: a full readSnapshot() can now exceed Postgres's own 2-minute statement timeout outright (TOAST decompression on ~121MB of compressed order JSON), independent of any caching layer. This change makes that path far less frequently hit -- once per sync cycle instead of once per request -- but doesn't fix the underlying read itself; tracked as a follow-up, not blocking this fix. Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
|
The latest updates on your projects. Learn more about Vercel for GitHub.
|
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.
Summary
The Redis whole-snapshot cache shipped earlier for PUL-22 doesn't survive real scale — a real 22,210-order store (
naturesjoystore.com) serializes to 188.31MB, which blows past Upstash's entire free-tier storage quota and times out on every write, confirmed by testing against the live store. The write was failing silently (by design), so nothing was actually being cached.getAnalyticsForVersion()checks the existing Postgres-bytea shared analytics cache using just{storeUrl, lastSyncAt}— no query, both already on hand — before paying for a full snapshot reassembly./api/analyticsand/api/reports/exportnow use this fast path.readProducts(),readMostRecentCurrency(),readPhoneByCustomerKey()answer the product picker and inbox chat-enrichment directly, without pulling in the whole order history.woo_orders' billing phone — cuts the phone lookup from ~8s to ~1.7s on the real store (already applied to production).Follow-up (not blocking this PR)
Testing also surfaced that a full
readSnapshot()can now exceed Postgres's own 2-minute statement timeout outright (TOAST decompression on ~121MB of compressed order JSON) — independent of caching. This PR makes that path far less frequently hit (once per sync cycle instead of once per request), but doesn't fix the underlying read itself. Tracked separately.Test plan
npm run typecheck— cleannpm run lint— clean (only pre-existing warnings)readProducts/readMostRecentCurrency/readPhoneByCustomerKeyagainst real production data (naturesjoystore.com, 22,211 orders): 392ms, 213ms, 1.7s respectivelygetAnalyticsForVersionwrites to and reads from the shared Postgres-bytea cache correctlysupabase_migrations.schema_migrationsCo-Authored-By: Claude Sonnet 5 noreply@anthropic.com