mirror of
https://github.com/openclaw/openclaw.git
synced 2026-05-13 12:20:45 +00:00
fix: expose safe restart deferral bypass (#78658)
Expose the existing safe-restart skipDeferral escape hatch through gateway RPC and the daemon CLI, document the flag, and add restart/CLI regression coverage. Also keep CLI failure output off the cold bootstrap graph and align CLI guidance expectations needed by current CI. Co-authored-by: Solomon Neas <solomonneas@users.noreply.github.com>
This commit is contained in:
@@ -122,6 +122,7 @@ describe("runDaemonRestart health checks", () => {
|
||||
json?: boolean;
|
||||
safe?: boolean;
|
||||
force?: boolean;
|
||||
skipDeferral?: boolean;
|
||||
}) => Promise<boolean>;
|
||||
let runDaemonStop: (opts?: { json?: boolean; disable?: boolean }) => Promise<void>;
|
||||
let envSnapshot: ReturnType<typeof captureEnv>;
|
||||
@@ -283,6 +284,25 @@ describe("runDaemonRestart health checks", () => {
|
||||
expect(runServiceRestart).toHaveBeenCalled();
|
||||
});
|
||||
|
||||
it("forwards --safe --skip-deferral as skipDeferral: true on the RPC", async () => {
|
||||
await runDaemonRestart({ json: true, safe: true, skipDeferral: true });
|
||||
|
||||
expect(callGatewayCli).toHaveBeenCalledWith({
|
||||
method: "gateway.restart.request",
|
||||
params: { reason: "gateway.restart.safe", skipDeferral: true },
|
||||
timeoutMs: 10_000,
|
||||
});
|
||||
expect(runServiceRestart).not.toHaveBeenCalled();
|
||||
});
|
||||
|
||||
it("rejects --skip-deferral without --safe", async () => {
|
||||
await expect(runDaemonRestart({ json: true, skipDeferral: true })).rejects.toThrow(
|
||||
"--skip-deferral requires --safe",
|
||||
);
|
||||
expect(callGatewayCli).not.toHaveBeenCalled();
|
||||
expect(runServiceRestart).not.toHaveBeenCalled();
|
||||
});
|
||||
|
||||
it("repairs stale loaded service definitions from gateway start", async () => {
|
||||
repairLoadedGatewayServiceForStart.mockResolvedValue({
|
||||
result: "started",
|
||||
|
||||
@@ -155,9 +155,14 @@ async function requestSafeGatewayRestart(opts: DaemonLifecycleOptions): Promise<
|
||||
if (opts.wait !== undefined) {
|
||||
throw new Error("--safe cannot be combined with --wait; safe restart uses gateway deferral");
|
||||
}
|
||||
const skipDeferral = opts.skipDeferral === true;
|
||||
const params: { reason: string; skipDeferral?: true } = { reason: "gateway.restart.safe" };
|
||||
if (skipDeferral) {
|
||||
params.skipDeferral = true;
|
||||
}
|
||||
const result = await callGatewayCli<SafeGatewayRestartRequestResult>({
|
||||
method: "gateway.restart.request",
|
||||
params: { reason: "gateway.restart.safe" },
|
||||
params,
|
||||
timeoutMs: 10_000,
|
||||
});
|
||||
const message =
|
||||
@@ -165,7 +170,9 @@ async function requestSafeGatewayRestart(opts: DaemonLifecycleOptions): Promise<
|
||||
? "safe restart request joined an existing pending gateway restart"
|
||||
: result.status === "deferred"
|
||||
? "safe restart requested; gateway will restart after active work drains"
|
||||
: "safe restart requested; gateway will restart momentarily";
|
||||
: skipDeferral
|
||||
? "safe restart requested; gateway bypassing active-work deferral"
|
||||
: "safe restart requested; gateway will restart momentarily";
|
||||
const payload = {
|
||||
ok: true,
|
||||
result: result.status,
|
||||
@@ -265,6 +272,9 @@ export async function runDaemonStop(opts: DaemonLifecycleOptions = {}) {
|
||||
* Throws/exits on check or restart failures.
|
||||
*/
|
||||
export async function runDaemonRestart(opts: DaemonLifecycleOptions = {}): Promise<boolean> {
|
||||
if (opts.skipDeferral && !opts.safe) {
|
||||
throw new Error("--skip-deferral requires --safe");
|
||||
}
|
||||
if (opts.safe) {
|
||||
return await requestSafeGatewayRestart(opts);
|
||||
}
|
||||
|
||||
@@ -129,6 +129,7 @@ export function addGatewayServiceCommands(parent: Command, opts?: { statusDescri
|
||||
.description("Restart the Gateway service (launchd/systemd/schtasks)")
|
||||
.option("--force", "Restart immediately without waiting for active gateway work", false)
|
||||
.option("--safe", "Request an OpenClaw-aware restart after active work drains", false)
|
||||
.option("--skip-deferral", "Bypass the safe-restart deferral gate; requires --safe", false)
|
||||
.option(
|
||||
"--wait <duration>",
|
||||
"Wait duration before forcing restart (ms, 10s, 5m; 0 waits indefinitely)",
|
||||
|
||||
@@ -28,6 +28,7 @@ export type DaemonLifecycleOptions = {
|
||||
json?: boolean;
|
||||
force?: boolean;
|
||||
safe?: boolean;
|
||||
skipDeferral?: boolean;
|
||||
wait?: string;
|
||||
disable?: boolean;
|
||||
};
|
||||
|
||||
Reference in New Issue
Block a user