Skip to content

Commit 30835d7

Browse files
authored
handle EAGAIN (macOS) in ErrorHandlingProcessManager (flutter#154306)
~~Fixes~~ Discovered in flutter#153776. To my knowledge, `Resource temporarily unavailable` when trying to run a process means that some required resource is at capacity. There may be too many processes active, not enough available ports, or some sort of blocking cache is full, etc. Feel free to independently research and see if you come to the same conclusion. Then, it seems safe to catch and handle this within the tool's `ErrorHandlingProcessManager` abstraction, as Flutter cannot realistically do anything to prevent this issue.
1 parent 93d06eb commit 30835d7

File tree

2 files changed

+31
-0
lines changed

2 files changed

+31
-0
lines changed

packages/flutter_tools/lib/src/base/error_handling_io.dart

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -777,6 +777,7 @@ void _handlePosixException(Exception e, String? message, int errorCode, String?
777777
void _handleMacOSException(Exception e, String? message, int errorCode, String? posixPermissionSuggestion) {
778778
// https://github.com/apple/darwin-xnu/blob/main/bsd/dev/dtrace/scripts/errno.d
779779
const int ebadarch = 86;
780+
const int eagain = 35;
780781
if (errorCode == ebadarch) {
781782
final StringBuffer errorBuffer = StringBuffer();
782783
if (message != null) {
@@ -787,6 +788,17 @@ void _handleMacOSException(Exception e, String? message, int errorCode, String?
787788
errorBuffer.writeln(' sudo softwareupdate --install-rosetta --agree-to-license');
788789
_throwFileSystemException(errorBuffer.toString());
789790
}
791+
if (errorCode == eagain) {
792+
final StringBuffer errorBuffer = StringBuffer();
793+
if (message != null) {
794+
errorBuffer.writeln('$message.');
795+
}
796+
errorBuffer.writeln(
797+
'Your system may be running into its process limits. '
798+
'Consider quitting unused apps and trying again.',
799+
);
800+
throwToolExit(errorBuffer.toString());
801+
}
790802
_handlePosixException(e, message, errorCode, posixPermissionSuggestion);
791803
}
792804

packages/flutter_tools/test/general.shard/base/error_handling_io_test.dart

Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1108,6 +1108,7 @@ Please ensure that the SDK and/or project is installed in a location that has re
11081108
const int enospc = 28;
11091109
const int eacces = 13;
11101110
const int ebadarch = 86;
1111+
const int eagain = 35;
11111112

11121113
testWithoutContext('when writing to a full device', () {
11131114
final FakeProcessManager fakeProcessManager = FakeProcessManager.list(<FakeCommand>[
@@ -1190,6 +1191,24 @@ Please ensure that the SDK and/or project is installed in a location that has re
11901191
expect(() => processManager.runSync(<String>['foo', '--bar']),
11911192
throwsToolExit(message: expectedMessage));
11921193
});
1194+
1195+
testWithoutContext('when up against resource limits (EAGAIN)', () async {
1196+
final FakeProcessManager fakeProcessManager = FakeProcessManager.list(<FakeCommand>[
1197+
const FakeCommand(command: <String>['foo', '--bar'], exception: ProcessException('', <String>[], '', eagain)),
1198+
]);
1199+
1200+
final ProcessManager processManager = ErrorHandlingProcessManager(
1201+
delegate: fakeProcessManager,
1202+
platform: macOSPlatform,
1203+
);
1204+
1205+
const String expectedMessage = 'Flutter failed to run "foo --bar".\n'
1206+
'Your system may be running into its process limits. '
1207+
'Consider quitting unused apps and trying again.';
1208+
1209+
expect(() async => processManager.start(<String>['foo', '--bar']),
1210+
throwsToolExit(message: expectedMessage));
1211+
});
11931212
});
11941213

11951214
testWithoutContext('ErrorHandlingProcessManager delegates killPid correctly', () async {

0 commit comments

Comments
 (0)