Allow restarting failed server instances
This commit is contained in:
@@ -173,6 +173,7 @@ func (svc *CoreService) StartServerInstance(command domain.ServerLifecycleComman
|
|||||||
return svc.dispatchExistingServerLifecycle(command, domain.ServerLifecycleActionStart, []domain.ServerInstanceState{
|
return svc.dispatchExistingServerLifecycle(command, domain.ServerLifecycleActionStart, []domain.ServerInstanceState{
|
||||||
domain.ServerInstanceStateReady,
|
domain.ServerInstanceStateReady,
|
||||||
domain.ServerInstanceStateStopped,
|
domain.ServerInstanceStateStopped,
|
||||||
|
domain.ServerInstanceStateFailed,
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -283,6 +283,23 @@ func TestCoreServiceLifecycleFailureProjectsFailedState(t *testing.T) {
|
|||||||
if instance.State != domain.ServerInstanceStateFailed {
|
if instance.State != domain.ServerInstanceStateFailed {
|
||||||
t.Fatalf("expected failed install result to mark failed, got %+v", instance)
|
t.Fatalf("expected failed install result to mark failed, got %+v", instance)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
started, err := svc.StartServerInstance(domain.ServerLifecycleCommand{
|
||||||
|
ServerInstanceID: instance.ID,
|
||||||
|
ExpectedConfigVersion: instance.ConfigVersion,
|
||||||
|
IdempotencyKey: "idem-start-after-failure",
|
||||||
|
})
|
||||||
|
if err != nil || started.Job.Capability != domain.LifecycleCapabilityStart || started.Job.TargetKey != "actions/start.json" {
|
||||||
|
t.Fatalf("failed server should allow explicit restart dispatch, result=%+v err=%v", started, err)
|
||||||
|
}
|
||||||
|
claimAndCompleteLifecycleJob(t, svc, sessionToken, domain.LifecycleCapabilityStart, domain.JobStateSucceeded)
|
||||||
|
recovered, err := svc.GetServerInstance("server-1")
|
||||||
|
if err != nil {
|
||||||
|
t.Fatalf("get recovered instance: %v", err)
|
||||||
|
}
|
||||||
|
if recovered.State != domain.ServerInstanceStateRunning {
|
||||||
|
t.Fatalf("expected explicit restart to recover failed instance, got %+v", recovered)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func TestCoreServicePluginLifecycleManagesMultipleInstancesIndependently(t *testing.T) {
|
func TestCoreServicePluginLifecycleManagesMultipleInstancesIndependently(t *testing.T) {
|
||||||
|
|||||||
@@ -0,0 +1,19 @@
|
|||||||
|
import { describe, expect, it } from "vitest";
|
||||||
|
|
||||||
|
import { canStartServer, canStopServer } from "./serverManagement";
|
||||||
|
import type { ServerInstanceState } from "../api/types";
|
||||||
|
|
||||||
|
describe("server management lifecycle contracts", () => {
|
||||||
|
it("allows explicit starts from recoverable non-running states", () => {
|
||||||
|
const startable: ServerInstanceState[] = ["ready", "stopped", "failed"];
|
||||||
|
const blocked: ServerInstanceState[] = ["draft", "installing", "running", "deleted"];
|
||||||
|
|
||||||
|
expect(startable.every(canStartServer)).toBe(true);
|
||||||
|
expect(blocked.some(canStartServer)).toBe(false);
|
||||||
|
});
|
||||||
|
|
||||||
|
it("keeps stop limited to running servers", () => {
|
||||||
|
expect(canStopServer("running")).toBe(true);
|
||||||
|
expect(canStopServer("failed")).toBe(false);
|
||||||
|
});
|
||||||
|
});
|
||||||
@@ -108,7 +108,7 @@ export function endpointLabel(endpoint: RunEndpointResponse | undefined, runEndp
|
|||||||
}
|
}
|
||||||
|
|
||||||
export function canStartServer(state: ServerInstanceState): boolean {
|
export function canStartServer(state: ServerInstanceState): boolean {
|
||||||
return state === "ready" || state === "stopped";
|
return state === "ready" || state === "stopped" || state === "failed";
|
||||||
}
|
}
|
||||||
|
|
||||||
export function canStopServer(state: ServerInstanceState): boolean {
|
export function canStopServer(state: ServerInstanceState): boolean {
|
||||||
|
|||||||
Reference in New Issue
Block a user