fix(worker): claim workspace lock in main before enqueue (D-02)
The lock was previously claimed when the worker reported `running`, which is after `agent.prompt` had already started streaming. Two concurrent runs targeting the same workspace could both pass the main-side checks, both get enqueued, and both read half-written state before one of them lost the lock race and was cancelled mid-flight. Move the `claimWorkspaceLock` call into `dispatchRunToWorker` so main coordinates exclusivity authoritatively. If the lock is unavailable, the run is finished as failed and never enqueued. The worker-side lease-renewal path is preserved since it is a lease, not a lock.
This commit is contained in:
1 parent
f86b3ddbac
commit
ff0c01fe87
2 files changed
+27
-4
No files matched your search
@@ -86,6 +86,30 @@ export function createRunDispatch(deps: OrchestrationDependencies) {
|
||||
throw new Error(connectorIssue);
|
||||
}
|
||||
|
||||
// D-02: Claim the workspace lock synchronously before enqueuing the run.
|
||||
// Previously the worker claimed the lock only after it emitted `running`,
|
||||
// so two runs could race between enqueue and startup and both read the
|
||||
// same workspace mid-write. Main is the authoritative coordinator.
|
||||
if (
|
||||
params.workspaceMode === "exclusive" &&
|
||||
params.workspace &&
|
||||
!db.claimWorkspaceLock(params.workspace.id, params.runId)
|
||||
) {
|
||||
db.finishRun({
|
||||
runId: params.runId,
|
||||
status: "failed",
|
||||
summary: null,
|
||||
errorMessage: `Workspace ${params.workspace.id} is locked by another run.`,
|
||||
exitCode: null,
|
||||
signal: null,
|
||||
model: null,
|
||||
sessionDisplayId: null,
|
||||
costUsd: null,
|
||||
unattributedCost: true,
|
||||
});
|
||||
return;
|
||||
}
|
||||
|
||||
const payload = buildRunPayload(params, {
|
||||
db,
|
||||
logger,
|
||||
|
||||
Reference in new issue
Block a user