ScaleBun
Skip to article

Watchdog & profiler

webDeveloper

Two opt-in diagnostics — continuous resource health with local incident detection, and JS Self-Profiling flame graphs around a slow operation.

Updated Reviewed

Both are off by default, for different reasons: the watchdog samples continuously, and the profiler needs a response header you have to set.

Watchdog#

Continuous resource sampling that turns into local incidents — the SDK decides something went wrong on the device, rather than shipping raw samples for a backend to sift.

TypeScript
await ScaleBun.init({  clientKey,  apiBaseUrl,  features: { watchdog: true },  watchdog: { thresholds: { lagP95Ms: 400 } },});
ScaleBun.watchdog.stats();

Incident types#

TypeWhat it means
cpu_spikeSustained critical compute pressure, or a high event-loop-lag p95.
main_thread_stallA single heartbeat gap at or above the threshold.
jank_burstN long frames inside a window.
frozen_frameOne frame at or above the frozen threshold.
memory_surgeHeap growth rate sustained across two trend intervals.
memory_leak_suspicionMonotonic growth across N samples and a minimum total.
low_memory_pressureUsed heap over the limit ratio.

Each incident carries a tierpressure, lag-proxy, loaf, longtask or memory — recording which signal produced it. Browsers differ wildly here, and the tier is what lets the dashboard grade a cross-browser claim honestly instead of pretending Chromium's Compute Pressure and a lag proxy are the same evidence.

Thresholds#

ThresholdDefault
pressureSustainMs6000
lagP95Ms500
mainThreadStallMs500
jankBurstCount / jankWindowMs5 in 10000
frozenFrameMs700
memSurgeBytesPerSec6 MiB/s
leakSamples / leakMinBytes10 samples, 50 MiB
heapUsedRatio0.9
cooldownMs60000 per incident type

Sampling and caps#

cooldownMs is per incident type, so a noisy CPU signal cannot mask a memory one. Above that sits a session-wide cap of 10 incidents per 10 minutes; anything dropped by the cap is counted and surfaced on the health rollup rather than silently discarded.

OptionDefault
sampleRate1 — deterministic per session
heartbeatMs1000, floored at 250
rollupMs30000 — one health rollup per window
memorySampleMs20000

Profiler#

Sampled call-stack traces via the W3C JS Self-Profiling API, shipped as a performance item and rendered as a flame graph.

TypeScript
await ScaleBun.init({ clientKey, apiBaseUrl, features: { profiler: true } });
if (ScaleBun.profiler.available()) {  ScaleBun.profiler.start(10);   // sample interval in ms, default 10  await slowOperation();  await ScaleBun.profiler.stop(); // ships the trace}

Use it around a known-slow operation rather than leaving it running. Profiling has a real CPU cost, which is why it is opt-in and why the API is a window rather than a mode.

Next#