Skip to content

fix: circuit breaker persistent cache with safety fixes#281

Merged
koala73 merged 5 commits into
mainfrom
fix/circuit-breaker-persistent-cache
Feb 23, 2026
Merged

fix: circuit breaker persistent cache with safety fixes#281
koala73 merged 5 commits into
mainfrom
fix/circuit-breaker-persistent-cache

Conversation

@koala73

@koala73 koala73 commented Feb 23, 2026

Copy link
Copy Markdown
Owner

Summary

  • Persist circuit breaker cache to IndexedDB across page reloads (original PR fix: persist circuit breaker cache to IndexedDB across page reloads #279 by @elzalem)
  • Add dedicated delete_cache_entry Tauri command — fixes desktop cache deletion that silently failed due to serde_json::from_str("") rejecting empty strings
  • Fix clearCache() race condition — concurrent execute() could re-hydrate stale data before async delete completed
  • Default persistCache to false (opt-in) — 6 breakers store Date objects that become strings after JSON round-trip, breaking .getTime() callers
  • Fix falsy data guard in hydration — if (!entry?.data) dropped valid 0/false payloads

Changes

File Change
src/utils/circuit-breaker.ts Persistence infrastructure, default false, race fix, falsy guard
src/services/persistent-cache.ts deletePersistentCache() using dedicated Tauri command
src-tauri/src/main.rs New delete_cache_entry command + registered in invoke handler
e2e/circuit-breaker-persistence.spec.ts 7 Playwright E2E tests covering persist/hydrate/clear/TTL/stale

Test plan

  • npx tsc --noEmit passes
  • vite build succeeds
  • E2E: npx playwright test e2e/circuit-breaker-persistence.spec.ts
  • Desktop: verify delete_cache_entry removes key from persistent-cache.json
  • Breakers without persistCache: true do NOT write to IndexedDB
  • Weather alerts still render correctly (no .getTime() TypeError)

elzalem and others added 4 commits February 23, 2026 23:10
On page reload, all 28+ circuit breaker in-memory caches are lost,
triggering 20-30 simultaneous POST requests to Vercel edge functions.

Wire the existing persistent-cache.ts (IndexedDB + localStorage +
Tauri fallback) into CircuitBreaker so every breaker automatically:

- Hydrates from IndexedDB on first execute() call (~1-5ms read)
- Writes to IndexedDB fire-and-forget on every recordSuccess()
- Falls back to stale persistent data on network failure
- Auto-disables for breakers with cacheTtlMs=0 (live pricing)

Zero consumer code changes -- all 28+ breaker call sites untouched.
Reloads within the cache TTL (default 10min) serve instantly from
IndexedDB with zero network calls.

Also adds deletePersistentCache() to persistent-cache.ts for clean
cache invalidation via clearCache().

Co-Authored-By: Claude Opus 4.6 <[email protected]>
7 tests covering: IndexedDB persistence on success, hydration on new
instance, TTL expiry forcing fresh fetch, 24h stale ceiling rejection,
clearCache cleanup, cacheTtlMs=0 auto-disable, and network failure
fallback to stale persistent data.

Co-Authored-By: Claude Opus 4.6 <[email protected]>
P1: deletePersistentCache sent empty string to write_cache_entry,
which fails Rust's serde_json::from_str (not valid JSON). Add
dedicated delete_cache_entry Tauri command that removes the key
from the in-memory HashMap and flushes to disk.

P2: clearCache() set persistentLoaded=false, allowing a concurrent
execute() to re-hydrate stale data from IndexedDB before the async
delete completed. Remove the reset — after explicit clear there is
no reason to re-hydrate from persistent storage.
P1b: 6 breakers store Date objects (weather, aviation, ACLED,
military-flights, military-vessels, GDACS) which become strings
after JSON round-trip. Callers like MapPopup.getTimeUntil() call
date.getTime() on hydrated strings → TypeError. Change default
to false (opt-in) so persistence requires explicit confirmation
that the payload is JSON-safe.

P2: `if (!entry?.data) return` drops valid falsy payloads (0,
false, empty string). Use explicit null/undefined check instead.
@chatgpt-codex-connector

Copy link
Copy Markdown

You have reached your Codex usage limits for code reviews. You can see your limits in the Codex usage dashboard.

@vercel

vercel Bot commented Feb 23, 2026

Copy link
Copy Markdown

The latest updates on your projects. Learn more about Vercel for GitHub.

Project Deployment Actions Updated (UTC)
worldmonitor Ready Ready Preview, Comment Feb 23, 2026 10:24pm
worldmonitor-finance Ready Ready Preview, Comment Feb 23, 2026 10:24pm
worldmonitor-happy Ready Ready Preview, Comment Feb 23, 2026 10:24pm
worldmonitor-startup Ready Ready Preview, Comment Feb 23, 2026 10:24pm

Request Review

- clearCache() nulls persistentLoadPromise to orphan in-flight hydration
- delete_cache_entry defers disk flush to exit handler (avoids 14MB sync write)
- hydratePersistentCache checks TTL before setting lastDataState to 'cached'
- deletePersistentCache resets cacheDbPromise on IDB error + logs warning
- hydration catch logs warning instead of silently swallowing
- deletePersistentCache respects isStorageQuotaExceeded() for localStorage
@koala73
koala73 merged commit 53309c6 into main Feb 23, 2026
5 checks passed
koala73 added a commit that referenced this pull request Feb 24, 2026
## What's Changed

### Performance
- perf: defer YouTube/map init and stagger data loads to reduce blocking time (#287)

### Features
- feat: universal country detection — CII scoring for all countries (#344)
- feat: add Mexico as CII hotspot for cartel/security monitoring (#327)
- feat: add Mexico and LatAm security feeds for instability coverage (#325)
- feat: add category pills and search filter to Panels tab (#322)
- feat: consolidate settings into unified tabbed modal (#319)
- feat: add Island Times (Palau) RSS feed (#317)
- feat: add AI Flow settings popup for web-only AI provider control (#314)
- feat: optional channels with tab-based region browse UI (#295)
- feat: custom channel management (#282)
- feat: add Bild RSS feed scoped to German locale (#312)

### Bug Fixes
- fix: suppress notification sound when popup alerts are disabled
- fix: prevent entity conflation in pane summarization (#341)
- fix: add Mexico to COUNTRY_BOUNDS and COUNTRY_ALIASES (#338)
- fix: make OpenSky cache TTLs env-configurable (#333)
- fix: serialize OpenSky requests with global 429 cooldown (#332)
- fix: replace RSSHub feeds with native/Google News alternatives (#331)
- fix: OpenSky auth resilience — retry, IPv4, no negative cache on auth fail (#329)
- fix: add CARTO and OpenStreetMap attribution to map (#323)
- fix: add drag cleanup handlers and suppress click after drag-drop (#315)
- fix: replace HTML5 drag API with mouse events for WKWebView (#313)
- fix: open channel settings as inline modal instead of separate window (#311)
- fix: sync YouTube live panel mute state with native player controls (#285)
- fix: strip Ollama reasoning tokens from summaries (#299)
- fix: open external links in system browser on Tauri desktop (#297)
- fix: add User-Agent and Cloudflare 403 detection to secret validation (#296)
- fix: infra cost optimizations round 2 (#275)
- fix: enforce military bbox filtering (#284)
- fix: infrastructure cost optimizations across caching, polling, batching (#283)
- fix: circuit breaker persistent cache with safety fixes (#281)
- fix: immediately refresh stale services when tab regains focus (#277)

### Security
- Security hardening: SSRF protection, auth gating, and token generation (#343)
- Harden Railway relay auth, caching, and proxy routing (#320)
- Build/runtime hardening and dependency security updates (#286)
- fix: harden embed postMessage origin check (#302)
koala73 added a commit that referenced this pull request Feb 25, 2026
## What's Changed

### Performance
- perf: defer YouTube/map init and stagger data loads (#287)

### Features
- feat: universal country detection — CII scoring for all countries (#344)
- feat: add Mexico as CII hotspot (#327)
- feat: add Mexico and LatAm security feeds (#325)
- feat: add category pills and search filter to Panels tab (#322)
- feat: consolidate settings into unified tabbed modal (#319)
- feat: optional channels with tab-based region browse UI (#295)
- feat: custom channel management (#282)

### Bug Fixes
- fix: suppress notification sound when popup alerts are disabled
- fix: prevent entity conflation in pane summarization (#341)
- fix: add Mexico to COUNTRY_BOUNDS and COUNTRY_ALIASES (#338)
- fix: OpenSky cache TTLs, serialization, and auth resilience (#329-#333)
- fix: replace RSSHub feeds with native/Google News alternatives (#331)
- fix: replace HTML5 drag API with mouse events for WKWebView (#313)
- fix: sync YouTube mute state with native player controls (#285)
- fix: strip Ollama reasoning tokens from summaries (#299)
- fix: infra cost optimizations (#275, #283)
- fix: circuit breaker persistent cache (#281)
- fix: immediately refresh stale services on tab focus (#277)

### Security
- Security hardening: SSRF protection, auth gating, token generation (#343)
- Harden Railway relay auth, caching, and proxy routing (#320)
- Build/runtime hardening and dependency security updates (#286)
koala73 added a commit that referenced this pull request Feb 25, 2026
…346)

* fix: suppress notification sound when popup alerts are disabled

Badge playSound() was firing on new findings regardless of the
"Pop up new alerts" toggle. Gate sound on popupEnabled so both
the modal and audio respect the user preference.

* chore: bump version to 2.5.7 with changelog

## What's Changed

### Performance
- perf: defer YouTube/map init and stagger data loads (#287)

### Features
- feat: universal country detection — CII scoring for all countries (#344)
- feat: add Mexico as CII hotspot (#327)
- feat: add Mexico and LatAm security feeds (#325)
- feat: add category pills and search filter to Panels tab (#322)
- feat: consolidate settings into unified tabbed modal (#319)
- feat: optional channels with tab-based region browse UI (#295)
- feat: custom channel management (#282)

### Bug Fixes
- fix: suppress notification sound when popup alerts are disabled
- fix: prevent entity conflation in pane summarization (#341)
- fix: add Mexico to COUNTRY_BOUNDS and COUNTRY_ALIASES (#338)
- fix: OpenSky cache TTLs, serialization, and auth resilience (#329-#333)
- fix: replace RSSHub feeds with native/Google News alternatives (#331)
- fix: replace HTML5 drag API with mouse events for WKWebView (#313)
- fix: sync YouTube mute state with native player controls (#285)
- fix: strip Ollama reasoning tokens from summaries (#299)
- fix: infra cost optimizations (#275, #283)
- fix: circuit breaker persistent cache (#281)
- fix: immediately refresh stale services on tab focus (#277)

### Security
- Security hardening: SSRF protection, auth gating, token generation (#343)
- Harden Railway relay auth, caching, and proxy routing (#320)
- Build/runtime hardening and dependency security updates (#286)
@koala73
koala73 deleted the fix/circuit-breaker-persistent-cache branch February 25, 2026 08:02
andreteow pushed a commit to andreteow/worldmonitor-a47 that referenced this pull request Feb 25, 2026
…oala73#346)

* fix: suppress notification sound when popup alerts are disabled

Badge playSound() was firing on new findings regardless of the
"Pop up new alerts" toggle. Gate sound on popupEnabled so both
the modal and audio respect the user preference.

* chore: bump version to 2.5.7 with changelog

## What's Changed

### Performance
- perf: defer YouTube/map init and stagger data loads (koala73#287)

### Features
- feat: universal country detection — CII scoring for all countries (koala73#344)
- feat: add Mexico as CII hotspot (koala73#327)
- feat: add Mexico and LatAm security feeds (koala73#325)
- feat: add category pills and search filter to Panels tab (koala73#322)
- feat: consolidate settings into unified tabbed modal (koala73#319)
- feat: optional channels with tab-based region browse UI (koala73#295)
- feat: custom channel management (koala73#282)

### Bug Fixes
- fix: suppress notification sound when popup alerts are disabled
- fix: prevent entity conflation in pane summarization (koala73#341)
- fix: add Mexico to COUNTRY_BOUNDS and COUNTRY_ALIASES (koala73#338)
- fix: OpenSky cache TTLs, serialization, and auth resilience (koala73#329-koala73#333)
- fix: replace RSSHub feeds with native/Google News alternatives (koala73#331)
- fix: replace HTML5 drag API with mouse events for WKWebView (koala73#313)
- fix: sync YouTube mute state with native player controls (koala73#285)
- fix: strip Ollama reasoning tokens from summaries (koala73#299)
- fix: infra cost optimizations (koala73#275, koala73#283)
- fix: circuit breaker persistent cache (koala73#281)
- fix: immediately refresh stale services on tab focus (koala73#277)

### Security
- Security hardening: SSRF protection, auth gating, token generation (koala73#343)
- Harden Railway relay auth, caching, and proxy routing (koala73#320)
- Build/runtime hardening and dependency security updates (koala73#286)
facusturla pushed a commit to facusturla/worldmonitor that referenced this pull request Feb 27, 2026
* fix: persist circuit breaker cache to IndexedDB across page reloads

On page reload, all 28+ circuit breaker in-memory caches are lost,
triggering 20-30 simultaneous POST requests to Vercel edge functions.

Wire the existing persistent-cache.ts (IndexedDB + localStorage +
Tauri fallback) into CircuitBreaker so every breaker automatically:

- Hydrates from IndexedDB on first execute() call (~1-5ms read)
- Writes to IndexedDB fire-and-forget on every recordSuccess()
- Falls back to stale persistent data on network failure
- Auto-disables for breakers with cacheTtlMs=0 (live pricing)

Zero consumer code changes -- all 28+ breaker call sites untouched.
Reloads within the cache TTL (default 10min) serve instantly from
IndexedDB with zero network calls.

Also adds deletePersistentCache() to persistent-cache.ts for clean
cache invalidation via clearCache().

Co-Authored-By: Claude Opus 4.6 <[email protected]>

* test: add Playwright e2e tests for circuit breaker persistent cache

7 tests covering: IndexedDB persistence on success, hydration on new
instance, TTL expiry forcing fresh fetch, 24h stale ceiling rejection,
clearCache cleanup, cacheTtlMs=0 auto-disable, and network failure
fallback to stale persistent data.

Co-Authored-By: Claude Opus 4.6 <[email protected]>

* fix: desktop cache deletion + clearCache race condition

P1: deletePersistentCache sent empty string to write_cache_entry,
which fails Rust's serde_json::from_str (not valid JSON). Add
dedicated delete_cache_entry Tauri command that removes the key
from the in-memory HashMap and flushes to disk.

P2: clearCache() set persistentLoaded=false, allowing a concurrent
execute() to re-hydrate stale data from IndexedDB before the async
delete completed. Remove the reset — after explicit clear there is
no reason to re-hydrate from persistent storage.

* fix: default persistCache to false, fix falsy data guard

P1b: 6 breakers store Date objects (weather, aviation, ACLED,
military-flights, military-vessels, GDACS) which become strings
after JSON round-trip. Callers like MapPopup.getTimeUntil() call
date.getTime() on hydrated strings → TypeError. Change default
to false (opt-in) so persistence requires explicit confirmation
that the payload is JSON-safe.

P2: `if (!entry?.data) return` drops valid falsy payloads (0,
false, empty string). Use explicit null/undefined check instead.

* fix: address blocking review issues on circuit breaker persistence

- clearCache() nulls persistentLoadPromise to orphan in-flight hydration
- delete_cache_entry defers disk flush to exit handler (avoids 14MB sync write)
- hydratePersistentCache checks TTL before setting lastDataState to 'cached'
- deletePersistentCache resets cacheDbPromise on IDB error + logs warning
- hydration catch logs warning instead of silently swallowing
- deletePersistentCache respects isStorageQuotaExceeded() for localStorage

---------

Co-authored-by: Elias El Khoury <[email protected]>
Co-authored-by: Claude Opus 4.6 <[email protected]>
facusturla pushed a commit to facusturla/worldmonitor that referenced this pull request Feb 27, 2026
…oala73#346)

* fix: suppress notification sound when popup alerts are disabled

Badge playSound() was firing on new findings regardless of the
"Pop up new alerts" toggle. Gate sound on popupEnabled so both
the modal and audio respect the user preference.

* chore: bump version to 2.5.7 with changelog

## What's Changed

### Performance
- perf: defer YouTube/map init and stagger data loads (koala73#287)

### Features
- feat: universal country detection — CII scoring for all countries (koala73#344)
- feat: add Mexico as CII hotspot (koala73#327)
- feat: add Mexico and LatAm security feeds (koala73#325)
- feat: add category pills and search filter to Panels tab (koala73#322)
- feat: consolidate settings into unified tabbed modal (koala73#319)
- feat: optional channels with tab-based region browse UI (koala73#295)
- feat: custom channel management (koala73#282)

### Bug Fixes
- fix: suppress notification sound when popup alerts are disabled
- fix: prevent entity conflation in pane summarization (koala73#341)
- fix: add Mexico to COUNTRY_BOUNDS and COUNTRY_ALIASES (koala73#338)
- fix: OpenSky cache TTLs, serialization, and auth resilience (koala73#329-koala73#333)
- fix: replace RSSHub feeds with native/Google News alternatives (koala73#331)
- fix: replace HTML5 drag API with mouse events for WKWebView (koala73#313)
- fix: sync YouTube mute state with native player controls (koala73#285)
- fix: strip Ollama reasoning tokens from summaries (koala73#299)
- fix: infra cost optimizations (koala73#275, koala73#283)
- fix: circuit breaker persistent cache (koala73#281)
- fix: immediately refresh stale services on tab focus (koala73#277)

### Security
- Security hardening: SSRF protection, auth gating, token generation (koala73#343)
- Harden Railway relay auth, caching, and proxy routing (koala73#320)
- Build/runtime hardening and dependency security updates (koala73#286)
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants