From c690c1e6fdcb786295d9077890291df1242369e9 Mon Sep 17 00:00:00 2001 From: Vyacheslav Egorov Date: Tue, 30 Sep 2025 09:39:19 +0200 Subject: [PATCH] Prepare for changes to FileSystemEntity.watch Current versions of Dart SDK contain a bug: when watcher overflows on Windows it throws a synchronous exception instead of emitting an error into the stream. Newer versions of Dart SDK will fix this bug - but this means watcher restart code needs to be updated to be prepared for this. --- pkgs/watcher/CHANGELOG.md | 3 ++ .../lib/src/directory_watcher/windows.dart | 43 +++++++++++-------- 2 files changed, 28 insertions(+), 18 deletions(-) diff --git a/pkgs/watcher/CHANGELOG.md b/pkgs/watcher/CHANGELOG.md index 01755b407..b4c823ea1 100644 --- a/pkgs/watcher/CHANGELOG.md +++ b/pkgs/watcher/CHANGELOG.md @@ -3,6 +3,9 @@ - Improve handling of subdirectories: ignore `PathNotFoundException` due to subdirectory deletion racing with watcher internals, instead of raising it on the event stream. +- Improve handling of watcher overflow on Windows: prepare for future versions + of SDK, which will properly forward `FileSystemException` into the stream + returned by the watcher. ## 1.1.3 diff --git a/pkgs/watcher/lib/src/directory_watcher/windows.dart b/pkgs/watcher/lib/src/directory_watcher/windows.dart index 9b17f8db1..87eca0f2f 100644 --- a/pkgs/watcher/lib/src/directory_watcher/windows.dart +++ b/pkgs/watcher/lib/src/directory_watcher/windows.dart @@ -405,35 +405,42 @@ class _WindowsDirectoryWatcher /// Start or restart the underlying [Directory.watch] stream. void _startWatch() { - // Note: "watcher closed" exceptions do not get sent over the stream - // returned by watch, and must be caught via a zone handler. + // Note: in older SDKs "watcher closed" exceptions might not get sent over + // the stream returned by watch, and must be caught via a zone handler. runZonedGuarded( () { var innerStream = Directory(path).watch(recursive: true); _watchSubscription = innerStream.listen( _onEvent, - onError: _eventsController.addError, + onError: _restartWatchOnOverflowOr(_eventsController.addError), onDone: _onDone, ); }, - (error, stackTrace) async { - if (error is FileSystemException && - error.message.startsWith('Directory watcher closed unexpectedly')) { - // Wait to work around https://github.com/dart-lang/sdk/issues/61378. - // Give the VM time to reset state after the error. See the issue for - // more discussion of the workaround. - await _watchSubscription?.cancel(); - await Future.delayed(const Duration(milliseconds: 1)); - _eventsController.addError(error, stackTrace); - _startWatch(); - } else { - // ignore: only_throw_errors - throw error; - } - }, + _restartWatchOnOverflowOr((error, stackTrace) { + // ignore: only_throw_errors + throw error; + }), ); } + void Function(Object, StackTrace) _restartWatchOnOverflowOr( + void Function(Object, StackTrace) otherwise) { + return (Object error, StackTrace stackTrace) async { + if (error is FileSystemException && + error.message.startsWith('Directory watcher closed unexpectedly')) { + // Wait to work around https://github.com/dart-lang/sdk/issues/61378. + // Give the VM time to reset state after the error. See the issue for + // more discussion of the workaround. + await _watchSubscription?.cancel(); + await Future.delayed(const Duration(milliseconds: 1)); + _eventsController.addError(error, stackTrace); + _startWatch(); + } else { + otherwise(error, stackTrace); + } + }; + } + /// Starts or restarts listing the watched directory to get an initial picture /// of its state. Future _listDir() {