Skip to content

Instantly share code, notes, and snippets.

@zigster64
Last active December 7, 2025 01:37
Show Gist options
  • Select an option

  • Save zigster64/8d9bbf9477e0149fc92038a56a209a28 to your computer and use it in GitHub Desktop.

Select an option

Save zigster64/8d9bbf9477e0149fc92038a56a209a28 to your computer and use it in GitHub Desktop.
Zig binary file watcher - reboot on recompile
// For dev use - add a call to this watchLoop thread in the main() of your program
// Whenever the app is re-compiled, it will detect the change and re-execute itself automatically
//
// For prod or UAT - can use this too (if its safe to simply re-exec in the middle of doing work)
//
// Makes deployments pretty simple - just drop the new binary in production and it respawns within 2 secs max
// Obviously - extend this for your real prod case to do a graceful shutdown, depending on what that
// means for your app
fn watchLoop(self: *Watcher) !void {
const cwd = std.fs.cwd();
std.Thread.sleep(2 * std.time.ns_per_s);
var buffer: [255]u8 = undefined; // select appropriate size here
const path = try std.fs.selfExePath(&buffer);
var stat = try cwd.statFile(path);
const initial_inode = stat.inode;
const initial_mtime = stat.mtime;
while (true) {
std.Thread.sleep(2 * std.time.ns_per_s);
stat = try cwd.statFile(path);
const inode_changed = (stat.inode != initial_inode);
const mtime_changed = (stat.mtime > initial_mtime);
if (inode_changed or mtime_changed) {
// log reboot here ♻️
const args = try std.process.argsAlloc(allocator);
const self_path = try std.fs.selfExePathAlloc(allocator);
var exec_args: std.ArrayList([]const u8) = .empty;
try exec_args.append(allocator, self_path);
for (args[1..]) |arg| {
try exec_args.append(allocator, arg);
}
// INSERT HERE - anything you need to do for a graceful shutdown first
// Reboot !
return std.process.execv(allocator, exec_args.items);
// The rebooted process will have the exact same PID as the existing process
// If you want a new PID, use fork() instead
}
}
}
// example of use from main ... using ENV var as feature flag
fn main() !void {
var allocator = ... get me an allocator
if (std.posix.getenv("WATCH")) |_| {
const thread = try std.Thread.spawn(.{}, watchLoop, .{allocator});
thread.detach();
}
.. do the app stuff now
.. app will reboot on successful re-compile
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment