fix: restart web/UI services before sessiond in restart commands

Running the suggested restart command from a PI WEB terminal kills the
command when sessiond restarts, so services listed after sessiond were
never restarted. Restart web/UI first in both the updates plugin's
suggested command and `pi-web restart` (systemd and launchd).
This commit is contained in:
Federico Jaramillo Martinez
2026-06-12 20:49:08 +02:00
parent 8de25d4a01
commit 38cf334c40
4 changed files with 29 additions and 6 deletions
@@ -0,0 +1,5 @@
---
"@jmfederico/pi-web": patch
---
Restart the web/UI services before the session daemon in the suggested "Restart all" command and `pi-web restart`, so running the command from a PI WEB terminal still restarts the UI even though restarting the session daemon kills the terminal.
+16 -2
View File
@@ -111,6 +111,10 @@ const serviceRefs: Record<ServiceId, ServiceRef> = {
const productionServiceIds: ServiceId[] = ["sessiond", "web"];
const startServiceOrder: ServiceId[] = ["sessiond", "web", "uiDev"];
const stopServiceOrder: ServiceId[] = ["web", "uiDev", "sessiond"];
// Restart web/UI before sessiond: when `pi-web restart` runs in a pi-web
// terminal (owned by sessiond), restarting sessiond kills the command, so any
// services handled after it would never be restarted.
const restartServiceOrder: ServiceId[] = ["web", "uiDev", "sessiond"];
function platformLabel(): string {
if (process.platform === "darwin") return "macOS";
@@ -377,6 +381,10 @@ function stopOrder(refs: ServiceRef[]): ServiceRef[] {
return orderServiceRefs(refs, stopServiceOrder);
}
function restartOrder(refs: ServiceRef[]): ServiceRef[] {
return orderServiceRefs(refs, restartServiceOrder);
}
function productionServiceDefinitions(options: InstallOptions, configPath: string, executables: ServiceExecutables): ServiceDefinition[] {
return [
{
@@ -827,7 +835,7 @@ async function uninstall(): Promise<void> {
}
function systemdServiceAction(action: "start" | "stop" | "restart", refs: ServiceRef[]): void {
const orderedRefs = action === "stop" ? stopOrder(refs) : startOrder(refs);
const orderedRefs = action === "stop" ? stopOrder(refs) : action === "restart" ? restartOrder(refs) : startOrder(refs);
run("systemctl", ["--user", action, ...orderedRefs.map((ref) => ref.systemdName)], { check: true });
}
@@ -838,7 +846,13 @@ function launchdServiceAction(action: "start" | "stop" | "restart", refs: Servic
}
if (action === "restart") {
for (const ref of stopOrder(refs)) launchdBootout(ref);
// Restart each service fully (bootout + start) before moving to the next,
// so the web/UI services are back up before sessiond is restarted.
for (const ref of restartOrder(refs)) {
launchdBootout(ref);
launchdStart(ref);
}
return;
}
for (const ref of startOrder(refs)) launchdStart(ref);
+1 -1
View File
@@ -71,7 +71,7 @@ describe("PI WEB status", () => {
const status = await getPiWebStatus(daemon);
expect(status.commands.restart).toBe("systemctl --user restart pi-web-sessiond.service pi-web-ui-dev.service");
expect(status.commands.restart).toBe("systemctl --user restart pi-web-ui-dev.service pi-web-sessiond.service");
expect(status.commands.restartWeb).toBe("systemctl --user restart pi-web-ui-dev.service");
expect(status.commands.restartSessiond).toBe("systemctl --user restart pi-web-sessiond.service");
expect(status.messages.find((message) => message.id === "sessiond-stale")?.command).toBe("systemctl --user restart pi-web-sessiond.service");
+7 -3
View File
@@ -58,6 +58,10 @@ const serviceRefs: Record<ServiceId, NativeServiceRef> = {
};
const startServiceOrder: ServiceId[] = ["sessiond", "web", "uiDev"];
// Restart web/UI before sessiond: when the restart command runs in a pi-web
// terminal (owned by sessiond), restarting sessiond kills the command, so any
// services listed after it would never be restarted.
const restartServiceOrder: ServiceId[] = ["web", "uiDev", "sessiond"];
interface PackageInfo {
name: string;
@@ -430,7 +434,7 @@ async function nativeServiceCommands(): Promise<NativeServiceCommands> {
if (installed.size === 0) return {};
const web = installedServiceRefs(installed, ["web", "uiDev"]);
const sessiond = installedServiceRefs(installed, ["sessiond"]);
const restartable = web.length === 0 ? [] : installedServiceRefs(installed);
const restartable = web.length === 0 ? [] : installedServiceRefs(installed, restartServiceOrder, restartServiceOrder);
const status = installedServiceRefs(installed);
return {
...(restartable.length === 0 ? {} : { restart: restartNativeServicesCommand(backend, restartable) }),
@@ -450,8 +454,8 @@ function installedServiceIds(backend: NativeServiceBackendKind): Set<ServiceId>
return new Set(startServiceOrder.filter((id) => existsSync(serviceFilePath(backend, serviceRefs[id]))));
}
function installedServiceRefs(installed: Set<ServiceId>, candidates: ServiceId[] = startServiceOrder): NativeServiceRef[] {
return startServiceOrder.filter((id) => candidates.includes(id) && installed.has(id)).map((id) => serviceRefs[id]);
function installedServiceRefs(installed: Set<ServiceId>, candidates: ServiceId[] = startServiceOrder, order: ServiceId[] = startServiceOrder): NativeServiceRef[] {
return order.filter((id) => candidates.includes(id) && installed.has(id)).map((id) => serviceRefs[id]);
}
function serviceFilePath(backend: NativeServiceBackendKind, ref: NativeServiceRef): string {