08-Jun-2026 — memory & heap diagnostics, per-VM heap sizing, plus websocket send reliability ref #257
build 671 — commit adc08f7
Tooling to investigate per-site memory and get area sites onto 512MB, plus a websocket reliability fix found during testing.
Memory diagnostics (ref #257):
- GET /api/health/memory (public, numbers only): process.memoryUsage() and v8.getHeapStatistics() in MB - rss, heapUsed, external, arrayBuffers, heap size limit. Tells us at a glance whether a site is heap-bound (objects/caches) or external-bound (buffers) without a full snapshot.
- GET /api/health/memory/heap-snapshot (authenticated): streams a V8 heap
snapshot straight to S3 (diagnostics/heap-snapshots/
- ) without buffering it in process memory, returns the key for offline analysis. - Diagnostics tab under Admin > System Settings: Refresh reads the memory endpoint and shows RSS, heap used/total, heap size limit, external buffers, ArrayBuffers, uptime and Node version; Capture heap snapshot calls the authenticated endpoint and reports the S3 object key.
WebSocket send reliability:
- sendMessage called WebSocket.send() while the socket was still CONNECTING (connect() resolves immediately when reusing an in-progress connection), throwing "InvalidStateError: Still in CONNECTING state" - seen on the backup history page. Messages sent before the connection opens are now queued and flushed in onopen, protecting every consumer (backup, environment setup/create, migration, walks-manager sync, image resize, legacy-redirect scrape).
Heap sizing:
- Remove the fixed --max_old_space_size cap from the server start command. It dated from the Heroku era, where Node read the host machine's RAM rather than the dyno quota and had to be capped by hand. On Fly each machine is a VM whose real RAM Node reads directly, so Node now sizes the old-space heap from the machine it runs on: a 1GB site gets more headroom than a 512MB site without every environment sharing one hardcoded ceiling. worker-server keeps its explicit cap so its browser and Serenity subprocesses retain room outside the Node heap.