feat(engine): guard one engine per project per machine
Adds a per-machine singleton lock that engages in
ProjectEngineManager.createAndStart() before any engine subsystems
spin up. Two fn dashboard processes can no longer run engines for the
same project on the same host — previously they would share .fusion/
state and corrupt worktrees / task rows for in-process projects.
The guard combines two independent checks:
- A proper-lockfile file at <project>/.fusion/engine.lock with
stale-lock recovery (auto-released on process death).
- A loopback listener on a hashed per-project address — UDS on
POSIX, named pipe on Windows. Stale UDS files are probed and
unlinked before a retry bind.
Failures raise EngineAlreadyRunningError. Both guards are released
from stopAll() and pauseProject(); a release on engine.start()
failure lets retries re-acquire cleanly.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
This commit is contained in:
@@ -1,5 +1,16 @@
|
||||
import { describe, it, expect, vi, beforeEach, afterEach } from "vitest";
|
||||
|
||||
// Stub out the per-machine singleton lock so tests with fake working dirs
|
||||
// (e.g. /mapped/...) don't try to mkdir or bind real sockets.
|
||||
vi.mock("../engine-singleton-lock.js", () => ({
|
||||
acquireEngineSingleton: vi.fn().mockResolvedValue({
|
||||
release: vi.fn().mockResolvedValue(undefined),
|
||||
socketPath: "/tmp/test.sock",
|
||||
lockFilePath: "/tmp/test.lock",
|
||||
}),
|
||||
EngineAlreadyRunningError: class EngineAlreadyRunningError extends Error {},
|
||||
}));
|
||||
|
||||
// Mock ProjectEngine before importing the manager
|
||||
vi.mock("../project-engine.js", () => {
|
||||
return {
|
||||
|
||||
Reference in New Issue
Block a user