-
Notifications
You must be signed in to change notification settings - Fork 1
/
restarter.zig
77 lines (68 loc) · 2.22 KB
/
restarter.zig
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
const std = @import("std");
const mem = std.mem;
const os = std.os;
const logging = @import("./logging.zig");
const timing = @import("./timing.zig");
const ChildProcess = std.ChildProcess;
const log = logging.log;
fn makeThrottler(logPrefix: []const u8) timing.Throttler {
return (timing.makeThrottler {
.logPrefix = logPrefix,
.desiredSleepMillis = 10000,
.slowRateMillis = 500,
}).create();
}
const global = struct {
var arena = std.heap.ArenaAllocator.init(std.heap.page_allocator);
};
fn usage() void {
std.debug.warn("Usage: restarter PROGRAM ARGS\n", .{});
}
pub fn main() anyerror!u8 {
var args = try std.process.argsAlloc(&global.arena.allocator);
if (args.len <= 1) {
usage();
return 1;
}
args = args[1..];
var throttler = makeThrottler("[restarter] throttle: ");
while (true) {
throttler.throttle();
logging.logTimestamp();
std.debug.warn("[restarter] starting: ", .{});
printArgs(args);
std.debug.warn("\n", .{});
// TODO: is there a way to use an allocator that can free?
var proc = try std.ChildProcess.init(args, &global.arena.allocator);
defer proc.deinit();
try proc.spawn();
try waitForChild(proc);
}
}
fn printArgs(argv: []const []const u8) void {
var prefix : []const u8 = "";
for (argv) |arg| {
std.debug.warn("{s}'{s}'", .{prefix, arg});
prefix = " ";
}
}
fn waitForChild(proc: *ChildProcess) !void {
// prottect from printing signals too fast
var signalThrottler = (timing.makeThrottler {
.logPrefix = "[restarter] signal throttler: ",
.desiredSleepMillis = 10000,
.slowRateMillis = 100,
}).create();
while (true) {
signalThrottler.throttle();
switch (try proc.spawnAndWait()) {
.Exited => |code| {
log("[restarter] child process exited with {}", .{code});
return;
},
.Stopped => |sig| log("[restarter] child process has stopped ({})", .{sig}),
.Signal => |sig| log("[restarter] child process signal ({})", .{sig}),
.Unknown => |sig| log("[restarter] child process unknown ({})", .{sig}),
}
}
}