mirror of
https://github.com/koala73/worldmonitor.git
synced 2026-04-25 17:14:57 +02:00
fix: circuit breaker persistent cache with safety fixes (#281)
* 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 <noreply@anthropic.com> * 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 <noreply@anthropic.com> * 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 <efk@anghami.com> Co-authored-by: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
@@ -314,6 +314,20 @@ fn read_cache_entry(cache: tauri::State<'_, PersistentCache>, key: String) -> Re
|
||||
Ok(cache.get(&key))
|
||||
}
|
||||
|
||||
#[tauri::command]
|
||||
fn delete_cache_entry(cache: tauri::State<'_, PersistentCache>, key: String) -> Result<(), String> {
|
||||
{
|
||||
let mut data = cache.data.lock().unwrap_or_else(|e| e.into_inner());
|
||||
data.remove(&key);
|
||||
}
|
||||
{
|
||||
let mut dirty = cache.dirty.lock().unwrap_or_else(|e| e.into_inner());
|
||||
*dirty = true;
|
||||
}
|
||||
// Disk flush deferred to exit handler (cache.flush) — avoids blocking main thread
|
||||
Ok(())
|
||||
}
|
||||
|
||||
#[tauri::command]
|
||||
fn write_cache_entry(app: AppHandle, cache: tauri::State<'_, PersistentCache>, key: String, value: String) -> Result<(), String> {
|
||||
let parsed_value: Value = serde_json::from_str(&value)
|
||||
@@ -967,6 +981,7 @@ fn main() {
|
||||
get_desktop_runtime_info,
|
||||
read_cache_entry,
|
||||
write_cache_entry,
|
||||
delete_cache_entry,
|
||||
open_logs_folder,
|
||||
open_sidecar_log_file,
|
||||
open_settings_window_command,
|
||||
|
||||
Reference in New Issue
Block a user