feat(watchdog): dedicated-isolate heartbeat + resource sampler (T-435)
A main-isolate Timer would freeze WITH the main isolate and tell us nothing, so the watchdog runs in its own isolate: it fsyncs a heartbeat every ~500ms (so the last on-disk heartbeat bounds a freeze to ~500ms) and every ~2s samples this process's thread / handle-or-fd / child-host / RSS counts. A monotonically climbing child or thread count is the leak signature the soak couldn't reproduce on CI but a real freeze would show. Output is JSON-lines in clide-watchdog.log, bounded by the same truncate-on-cap scheme as the crumb files. - watchdog.dart (Flutter-free, tested): ResourceSample, ResourceSampler (forPlatform), PosixResourceSampler (/proc/self: Threads, fd count, task children, ProcessInfo.currentRss), WatchdogFile (bounded fsynced JSON-lines), runWatchdog (the loop, bounded by maxTicks for tests), watchdogEntry (the sendable Isolate.spawn entry). - watchdog_windows.dart (coverage:ignore — Win32 FFI, validated only at runtime on Windows): one CreateToolhelp32Snapshot for thread + conhost/OpenConsole child count, GetProcessHandleCount, ProcessInfo.currentRss. Exhaustively defensive: any failure yields a -1 field, snapshot handle always closed, never throws. - main.dart: spawn the watchdog at boot (desktop only), non-fatal. Per-line fsync means the OS reaping the isolate at exit loses nothing. Tests: ResourceSample.toJson, Posix sampler against real /proc, WatchdogFile (JSON shape, cap, disabled), runWatchdog (immediate baseline tick). Coverage gate 95.08%. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
This commit is contained in:
@@ -18,6 +18,7 @@ export 'src/events/types.dart';
|
||||
export 'src/ipc/client.dart';
|
||||
export 'src/log.dart';
|
||||
export 'src/file_log_sink.dart';
|
||||
export 'src/watchdog.dart';
|
||||
export 'src/settings.dart';
|
||||
export 'src/facade.dart';
|
||||
export 'src/clipboard.dart';
|
||||
|
||||
Reference in New Issue
Block a user