Cache the database integrity check instead of running it on every dashboard fetch
This commit is contained in:
@@ -216,3 +216,5 @@ Roughly in priority order:
|
||||
`v0.16.43` scopes page refreshes to the page actually being viewed, instead of every refresh across the entire app unconditionally re-fetching everything -- Hosted Sites, Proxy Hosts, Redirects, Streams, Access Lists, Groups, the full Dashboard snapshot, and Certificates -- regardless of which single page triggered it. This was confirmed directly from the user's own account of the behavior ("if I'm on Hosted Sites and click refresh, it appears the whole entire site refreshes") and traced to a single shared `refresh()` function that every action in the app called: creating or editing a hosted site or proxy, toggling one on or off, deleting an entry, saving gateway settings, and re-syncing the gateway all ran the identical 8-endpoint fetch no matter which page initiated it. `refresh()` and its endpoints are now built from one shared map (`REFRESH_ENDPOINTS`), and a new `refreshCurrentView()` fetches only the state keys a `VIEW_REFRESH_KEYS` table says the active view actually renders -- Hosted Sites now refetches just `sites`, Proxy Hosts just `proxies`, Streaming just `streams`, Redirects just `redirects`, Access Lists just `accessLists` and `groups`. Every action listed above that's only ever reachable from one specific view (creating/editing/toggling/deleting a hosted site or proxy) now calls `refreshCurrentView()` instead of the full `refresh()`. Overview keeps the full, unscoped fetch deliberately: its attention list and the sidebar's per-section counts summarize the whole gateway, not one section of it, so scoping it would defeat the page's purpose; the initial page load (`boot()`) and the gateway re-sync button (only reachable from Overview) are unchanged for the same reason. A new generic refresh button (the same "↻" icon `refresh-health` already used) now appears on every page except Logs (which keeps its own dedicated "Refresh logs" button) so every view has an explicit, page-scoped way to pull fresh data without a full browser reload -- previously several views (Hosted, Proxy Hosts, Streaming, Redirects, Access Lists) had no refresh control of their own at all and only ever picked up new data from the page's initial load or the next full-page reload. One deliberate trade-off: sidebar badge counts for sections other than the one currently being viewed are not part of a scoped refresh and can go briefly stale until the next full refresh (a fresh page load, or a visit to Overview) -- intentional, since fetching data a page doesn't display was the entire problem being fixed here.
|
||||
|
||||
`v0.16.44` is a temporary, diagnostic-only release -- no behavior changes, just logging -- added after v0.16.43 (which fixed the app from over-fetching per page) didn't resolve the user's reported 6-14 second page loads. A Network-tab Timing capture the user sent for a single `GET /api/sites` request showed DNS and TCP connection at 0-7ms but "Waiting" (time to first byte) at 7485ms -- almost the entire delay happened server-side, before the app sent back a single byte of what should be a near-instant, in-memory list. Since this codebase's database and JS execution is single-threaded, that pattern (a trivially cheap request taking seconds) points to something else blocking the whole process at that moment, not a cost specific to any one endpoint. The leading suspect: `importAccessLogsToSqlite()`, a job that runs every 30 seconds, reads Caddy's access-log files, JSON-parses and hashes up to 5000 lines, and batch-inserts them -- all synchronous work with nothing to yield the event loop partway through. Rather than ship a fourth guess-based fix, this release adds two pieces of logging visible in the container's own logs: a warning whenever that import job takes over 500ms (broken down into read/hash/insert time), and a warning whenever any request takes over 1 second to answer. The next slow page load should show, in the logs, either the import job's duration lining up with the slow request's timestamp (confirming the suspect) or a different pattern entirely (pointing somewhere else). Both log lines are marked as temporary instrumentation, intended to be removed once the real cause is confirmed and fixed.
|
||||
|
||||
`v0.16.45` fixes the confirmed root cause behind the multi-second page loads reported after v0.16.41-v0.16.43: the user's own container logs, captured with v0.16.44's temporary diagnostics, showed completely unrelated endpoints -- `/api/dashboard`, `/api/system/security`, `/api/logs/prune/preview` -- all finishing within moments of each other at nearly identical ~8.5-9 second durations, right after the container started. That pattern only happens when several requests are queued behind one shared blocking operation, not when each is independently slow. The culprit: `dashboardSnapshot()` (which every `/api/dashboard` fetch runs) called `storage.integrity()` -- a full `PRAGMA integrity_check`, a complete scan of the entire SQLite database file for corruption, one of the most expensive operations SQLite can run -- on every single call, purely to compute one cosmetic "Healthy"/"Needs attention" label. Because this app's SQLite queries run synchronously, that scan didn't just make its own request slow, it froze the entire single-threaded server for its whole duration, on every dashboard fetch, for every user. The fix moves that check off the request path entirely: a new `refreshDatabaseIntegrityCache()` runs the real scan once shortly after startup and then every 30 minutes in the background, caching just the resulting status string, and `dashboardSnapshot()` now reads that cached value instantly instead of re-scanning the whole database on every poll. The (rarely-used, explicitly manual) downloadable support report still runs a live, real-time integrity check, since that's an appropriate place for a slow, thorough scan. v0.16.44's temporary `[perf]` logging stays in place for this release so the fix's effect is directly visible in the container's own logs -- expect no more `[perf] GET ... took` warnings tied to `/api/dashboard` going forward.
|
||||
|
||||
Reference in New Issue
Block a user