Skip to content
Merged
Show file tree
Hide file tree
Changes from 1 commit
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 2 additions & 2 deletions apps/server/src/cloud/selfUpdate.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -545,7 +545,7 @@ it.layer(NodeServices.layer)("ServerSelfUpdate.update", (it) => {
yield* TestClock.adjust(Duration.seconds(10));
assert.deepEqual(context.commands[3], {
command: "systemctl",
args: ["--user", "restart", "t3code.service"],
args: ["--user", "restart", "--no-block", "t3code.service"],
});
assert.lengthOf(context.spawns, 0);
// systemd replaces the process; the server must not exit itself.
Expand Down Expand Up @@ -583,7 +583,7 @@ it.layer(NodeServices.layer)("ServerSelfUpdate.update", (it) => {
assert.deepEqual(
context.commands.slice(-2).map((entry) => entry.args),
[
["--user", "restart", BOOT_SERVICE_UNIT_FILE],
["--user", "restart", "--no-block", BOOT_SERVICE_UNIT_FILE],
["--user", "daemon-reload"],
],
);
Expand Down
11 changes: 8 additions & 3 deletions apps/server/src/cloud/selfUpdate.ts
Original file line number Diff line number Diff line change
Expand Up @@ -354,14 +354,19 @@ export const make = Effect.fn("cloud.server_self_update.make")(function* (option
targetVersion,
});
// Restart after the acknowledgement has had time to cross any relay
// hop. If systemd rejects the handoff, restore the previous unit while
// this process is still alive and log the failure for diagnostics.
// hop. --no-block queues the restart job and exits before systemd
// stops this unit: a blocking restart's SIGTERM reaches the systemctl
// child (it shares this service's cgroup), which read as a restart
// failure and rolled the new unit back while the old server finished
// shutting down. With the handoff race gone, a non-zero exit or spawn
// error means systemd genuinely rejected the job while this process is
// still alive, so restoring the previous unit below stays correct.
yield* scheduleRestart(
Effect.gen(function* () {
const restart = yield* runner
.run({
command: "systemctl",
args: ["--user", "restart", BOOT_SERVICE_UNIT_FILE],
args: ["--user", "restart", "--no-block", BOOT_SERVICE_UNIT_FILE],
Comment thread
cursor[bot] marked this conversation as resolved.
})
.pipe(
Effect.mapError((cause) =>
Expand Down
Loading