Update watcher overflow detection (#2182)
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.
diff --git a/pkgs/watcher/CHANGELOG.md b/pkgs/watcher/CHANGELOG.md
index 01755b4..b4c823e 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 9b17f8d..87eca0f 100644
--- a/pkgs/watcher/lib/src/directory_watcher/windows.dart
+++ b/pkgs/watcher/lib/src/directory_watcher/windows.dart
@@ -405,35 +405,42 @@
/// 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<void>.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<void>.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<void> _listDir() {