diff options
author | 2022-01-04 18:29:21 -0800 | |
---|---|---|
committer | 2022-01-04 18:29:21 -0800 | |
commit | 0edf6fd1e4fed378328ef58c0d872631efc9e9d1 (patch) | |
tree | c909140a08e2a4c12a634ef5d06f184aa1f8f3b0 /src | |
parent | c9d6c25f710e274383d10532aad6671e5cde4249 (diff) | |
download | bun-0edf6fd1e4fed378328ef58c0d872631efc9e9d1.tar.gz bun-0edf6fd1e4fed378328ef58c0d872631efc9e9d1.tar.zst bun-0edf6fd1e4fed378328ef58c0d872631efc9e9d1.zip |
Improve error handling when out of file handles
Diffstat (limited to '')
-rw-r--r-- | src/analytics/analytics_thread.zig | 5 | ||||
-rw-r--r-- | src/bundler.zig | 6 | ||||
-rw-r--r-- | src/main.zig | 53 | ||||
-rw-r--r-- | src/report.zig | 240 |
4 files changed, 247 insertions, 57 deletions
diff --git a/src/analytics/analytics_thread.zig b/src/analytics/analytics_thread.zig index 026947445..e883a798f 100644 --- a/src/analytics/analytics_thread.zig +++ b/src/analytics/analytics_thread.zig @@ -375,7 +375,10 @@ fn start() bool { fn spawn() !void { @setCold(true); has_loaded = true; - thread = try std.Thread.spawn(.{}, readloop, .{}); + thread = std.Thread.spawn(.{}, readloop, .{}) catch { + disabled = true; + return; + }; } const headers_buf: string = "Content-Type binary/peechy"; diff --git a/src/bundler.zig b/src/bundler.zig index 5afd25d6a..5dcff1292 100644 --- a/src/bundler.zig +++ b/src/bundler.zig @@ -49,7 +49,7 @@ const NodeFallbackModules = @import("./node_fallbacks.zig"); const CacheEntry = @import("./cache.zig").FsCacheEntry; const Analytics = @import("./analytics/analytics_thread.zig"); const URL = @import("./query_string_map.zig").URL; - +const Report = @import("./report.zig"); const Linker = linker.Linker; const Resolver = _resolver.Resolver; @@ -603,9 +603,7 @@ pub const Bundler = struct { Output.flush(); } - this.loop() catch |err| { - Output.prettyErrorln("<r><red>Error: {s}<r>", .{@errorName(err)}); - }; + this.loop() catch |err| Report.globalError(err); } pub fn loop(this: *Worker) anyerror!void { diff --git a/src/main.zig b/src/main.zig index 4da55d864..b3455d884 100644 --- a/src/main.zig +++ b/src/main.zig @@ -54,58 +54,7 @@ pub fn main() anyerror!void { Output.Source.set(&output_source); defer Output.flush(); - cli.Cli.start(default_allocator, stdout, stderr, MainPanicHandler) catch |err| { - switch (err) { - error.CurrentWorkingDirectoryUnlinked => { - Output.prettyError( - "\n<r><red>error: <r>The current working directory was deleted, so that command didn't work. Please cd into a different directory and try again.", - .{}, - ); - Output.flush(); - std.os.exit(1); - }, - error.FileNotFound => { - Output.prettyError( - "\n<r><red>error<r><d>:<r> <b>FileNotFound<r>\nbun could not find a file, and the code that produces this error is missing a better error.\n", - .{}, - ); - Output.flush(); - - Report.printMetadata(); - - Output.flush(); - - print_stacktrace: { - var debug_info = std.debug.getSelfDebugInfo() catch break :print_stacktrace; - var trace = @errorReturnTrace() orelse break :print_stacktrace; - Output.disableBuffering(); - std.debug.writeStackTrace(trace.*, Output.errorWriter(), default_allocator, debug_info, std.debug.detectTTYConfig()) catch break :print_stacktrace; - } - - std.os.exit(1); - }, - error.MissingPackageJSON => { - Output.prettyError( - "\n<r><red>error<r><d>:<r> <b>MissingPackageJSON<r>\nbun could not find a package.json file.\n", - .{}, - ); - Output.flush(); - std.os.exit(1); - }, - else => { - Report.fatal(err, null); - - print_stacktrace: { - var debug_info = std.debug.getSelfDebugInfo() catch break :print_stacktrace; - var trace = @errorReturnTrace() orelse break :print_stacktrace; - Output.disableBuffering(); - std.debug.writeStackTrace(trace.*, Output.errorWriter(), default_allocator, debug_info, std.debug.detectTTYConfig()) catch break :print_stacktrace; - } - - std.os.exit(1); - }, - } - }; + cli.Cli.start(default_allocator, stdout, stderr, MainPanicHandler) catch |err| Report.globalError(err); std.mem.doNotOptimizeAway(JavaScriptVirtualMachine.fetch); std.mem.doNotOptimizeAway(JavaScriptVirtualMachine.init); diff --git a/src/report.zig b/src/report.zig index 7032fc9aa..400a4dc41 100644 --- a/src/report.zig +++ b/src/report.zig @@ -16,6 +16,8 @@ const Features = @import("./analytics/analytics_thread.zig").Features; const HTTP = @import("http").AsyncHTTP; const CrashReporter = @import("crash_reporter"); +const Report = @This(); + var crash_reporter_path: [1024]u8 = undefined; pub fn printMetadata() void { @setCold(true); @@ -166,3 +168,241 @@ pub fn fatal(err_: ?anyerror, msg_: ?string) void { Output.flush(); } } + +var globalError_ranOnce = false; + +pub noinline fn globalError(err: anyerror) noreturn { + @setCold(true); + + if (@atomicRmw(bool, &globalError_ranOnce, .Xchg, true, .Monotonic)) { + std.os.exit(1); + } + + switch (err) { + error.CurrentWorkingDirectoryUnlinked => { + Output.prettyError( + "\n<r><red>error: <r>The current working directory was deleted, so that command didn't work. Please cd into a different directory and try again.", + .{}, + ); + Output.flush(); + std.os.exit(1); + }, + error.SystemFdQuotaExceeded => { + const limit = std.os.getrlimit(.NOFILE) catch std.mem.zeroes(std.os.rlimit); + if (comptime Environment.isMac) { + Output.prettyError( + \\ + \\<r><red>error<r>: Your computer ran out of file descriptors <d>(<red>SystemFdQuotaExceeded<r><d>)<r> + \\ + \\<d>Current limit: {d}<r> + \\ + \\To fix this, try running: + \\ + \\ <cyan>sudo launchctl limit maxfiles 2147483646<r> + \\ <cyan>ulimit -n 2147483646<r> + \\ + \\That will only work until you reboot. + \\ + , + .{ + limit.cur, + }, + ); + } else { + Output.prettyError( + \\ + \\<r><red>error<r>: Your computer ran out of file descriptors <d>(<red>SystemFdQuotaExceeded<r><d>)<r> + \\ + \\<d>Current limit: {d}<r> + \\ + \\To fix this, try running: + \\ + \\ <cyan>sudo echo -e "\nfs.file-max=2147483646\n" >> /etc/sysctl.conf<r> + \\ <cyan>sudo sysctl -p<r> + \\ <cyan>ulimit -n 2147483646<r> + \\ + , + .{ + limit.cur, + }, + ); + + if (std.os.getenv("USER")) |user| { + if (user.len > 0) { + Output.prettyError( + \\ + \\If that still doesn't work, you may need to add these lines to /etc/security/limits.conf: + \\ + \\ <cyan>{s} soft nofile 2147483646<r> + \\ <cyan>{s} hard nofile 2147483646<r> + \\ + , + .{ user, user }, + ); + } + } + } + + Output.flush(); + std.os.exit(1); + }, + error.ProcessFdQuotaExceeded => { + const limit = std.os.getrlimit(.NOFILE) catch std.mem.zeroes(std.os.rlimit); + if (comptime Environment.isMac) { + Output.prettyError( + \\ + \\<r><red>error<r>: bun ran out of file descriptors <d>(<red>ProcessFdQuotaExceeded<r><d>)<r> + \\ + \\<d>Current limit: {d}<r> + \\ + \\To fix this, try running: + \\ + \\ <cyan>ulimit -n 2147483646<r> + \\ + \\You may also need to run: + \\ + \\ <cyan>sudo launchctl limit maxfiles 2147483646<r> + \\ + , + .{ + limit.cur, + }, + ); + } else { + Output.prettyError( + \\ + \\<r><red>error<r>: bun ran out of file descriptors <d>(<red>ProcessFdQuotaExceeded<r><d>)<r> + \\ + \\<d>Current limit: {d}<r> + \\ + \\To fix this, try running: + \\ + \\ <cyan>ulimit -n 2147483646<r> + \\ + \\That will only work for the current shell. To fix this for the entire system, run: + \\ + \\ <cyan>sudo echo -e "\nfs.file-max=2147483646\n" >> /etc/sysctl.conf<r> + \\ <cyan>sudo sysctl -p<r> + \\ + , + .{ + limit.cur, + }, + ); + + if (std.os.getenv("USER")) |user| { + if (user.len > 0) { + Output.prettyError( + \\ + \\If that still doesn't work, you may need to add these lines to /etc/security/limits.conf: + \\ + \\ <cyan>{s} soft nofile 2147483646<r> + \\ <cyan>{s} hard nofile 2147483646<r> + \\ + , + .{ user, user }, + ); + } + } + } + + Output.flush(); + std.os.exit(1); + }, + // The usage of `unreachable` in Zig's std.os may cause the file descriptor problem to show up as other errors + error.NotOpenForReading, error.Unexpected => { + const limit = std.os.getrlimit(.NOFILE) catch std.mem.zeroes(std.os.rlimit); + + if (limit.cur > 0 and limit.cur < (8096 * 2)) { + Output.prettyError( + \\ + \\<r><red>error<r>: An unknown error ocurred, possibly due to low max file descriptors <d>(<red>Unexpected<r><d>)<r> + \\ + \\<d>Current limit: {d}<r> + \\ + \\To fix this, try running: + \\ + \\ <cyan>ulimit -n 2147483646<r> + \\ + , + .{ + limit.cur, + }, + ); + + if (Environment.isLinux) { + if (std.os.getenv("USER")) |user| { + if (user.len > 0) { + Output.prettyError( + \\ + \\If that still doesn't work, you may need to add these lines to /etc/security/limits.conf: + \\ + \\ <cyan>{s} soft nofile 2147483646<r> + \\ <cyan>{s} hard nofile 2147483646<r> + \\ + , + .{ + user, + user, + }, + ); + } + } + } else if (Environment.isMac) { + Output.prettyError( + \\ + \\If that still doesn't work, you may need to run: + \\ + \\ <cyan>sudo launchctl limit maxfiles 2147483646<r> + \\ + , + .{}, + ); + } + + Output.flush(); + std.os.exit(1); + } + }, + error.FileNotFound => { + Output.prettyError( + "\n<r><red>error<r><d>:<r> <b>FileNotFound<r>\nbun could not find a file, and the code that produces this error is missing a better error.\n", + .{}, + ); + Output.flush(); + + Report.printMetadata(); + + Output.flush(); + + print_stacktrace: { + var debug_info = std.debug.getSelfDebugInfo() catch break :print_stacktrace; + var trace = @errorReturnTrace() orelse break :print_stacktrace; + Output.disableBuffering(); + std.debug.writeStackTrace(trace.*, Output.errorWriter(), default_allocator, debug_info, std.debug.detectTTYConfig()) catch break :print_stacktrace; + } + + std.os.exit(1); + }, + error.MissingPackageJSON => { + Output.prettyError( + "\n<r><red>error<r><d>:<r> <b>MissingPackageJSON<r>\nbun could not find a package.json file.\n", + .{}, + ); + Output.flush(); + std.os.exit(1); + }, + else => {}, + } + + Report.fatal(err, null); + + print_stacktrace: { + var debug_info = std.debug.getSelfDebugInfo() catch break :print_stacktrace; + var trace = @errorReturnTrace() orelse break :print_stacktrace; + Output.disableBuffering(); + std.debug.writeStackTrace(trace.*, Output.errorWriter(), default_allocator, debug_info, std.debug.detectTTYConfig()) catch break :print_stacktrace; + } + + std.os.exit(1); +} |