diff --git a/app/Provisioning/RunRunner.php b/app/Provisioning/RunRunner.php index 60f34b8..1886bad 100644 --- a/app/Provisioning/RunRunner.php +++ b/app/Provisioning/RunRunner.php @@ -18,8 +18,12 @@ class RunRunner { public function __construct(private PipelineRegistry $registry) {} + private ?string $pendingContinuation = null; + public function advance(ProvisioningRun $run): void { + $this->pendingContinuation = null; + // Lock must outlive the longest step so a duplicate job (dispatched by // the minutely tick while this one still runs) can't execute concurrently. $lock = Cache::lock('run:'.$run->uuid, 2100); @@ -33,6 +37,13 @@ class RunRunner } finally { $lock->release(); } + + // Dispatch the continuation only AFTER releasing the lock, so a second + // worker can't consume it and then bail on the still-held lock. + if ($this->pendingContinuation !== null) { + AdvanceRunJob::dispatch($this->pendingContinuation); + $this->pendingContinuation = null; + } } private function runLocked(ProvisioningRun $run): void @@ -116,7 +127,7 @@ class RunRunner $run->save(); $this->record($run, $step->key(), 'advanced', null); - AdvanceRunJob::dispatch($run->uuid); + $this->pendingContinuation = $run->uuid; // dispatched after the lock releases } private function onRetry(ProvisioningRun $run, ProvisioningStep $step, StepResult $result): void