Detect a busy run by identity, and clean up a failed kit write
CI / unit (8.2) (push) Has been cancelled
CI / unit (8.3) (push) Has been cancelled
CI / unit (8.4) (push) Has been cancelled
CI / psalm (push) Has been cancelled
CI / integration (mariadb, 32) (push) Has been cancelled
CI / integration (mariadb, 33) (push) Has been cancelled
CI / integration (mariadb, 34) (push) Has been cancelled
CI / integration (mariadb, 35) (push) Has been cancelled
CI / integration (pgsql, 32) (push) Has been cancelled
CI / integration (pgsql, 33) (push) Has been cancelled
CI / integration (pgsql, 34) (push) Has been cancelled
CI / integration (pgsql, 35) (push) Has been cancelled
CI / integration (sqlite, 32) (push) Has been cancelled
CI / integration (sqlite, 33) (push) Has been cancelled
CI / integration (sqlite, 34) (push) Has been cancelled
CI / integration (sqlite, 35) (push) Has been cancelled
CI / integration-targets (push) Has been cancelled
CI / integration-user (32) (push) Has been cancelled
CI / integration-user (33) (push) Has been cancelled
CI / integration-user (34) (push) Has been cancelled
CI / integration-user (35) (push) Has been cancelled
CI / integration-full-restore (push) Has been cancelled

step() hands back the same Run object when another process holds the lease;
comparing update times per second could stop the scheduled job early after a
quick step. A failed write of the recovery kit file now closes the handle and
removes the partial file.
This commit is contained in:
2026-10-07 00:48:11 +02:00
parent b89b5b5fa6
commit b37a953cfd
2 changed files with 12 additions and 6 deletions
+4 -4
View File
@@ -46,11 +46,11 @@ final class BackupJob extends TimedJob {
$this->startScheduled();
foreach ($this->runs->findRunning(null, BackupService::KIND_FULL) as $run) {
while (microtime(true) < $deadline && $run->getStatus() === 'running') {
$before = $run->getUpdatedAt();
$run = $this->backups->step($run, min($deadline, microtime(true) + $budget));
if ($run->getUpdatedAt() === $before && $run->getStatus() === 'running') {
break; // another process holds this run's lease: leave it to that process
$next = $this->backups->step($run, min($deadline, microtime(true) + $budget));
if ($next === $run) {
break; // step() hands back the same object when another process holds the run's lease
}
$run = $next;
}
}
$this->failStaleRestores();
+8 -2
View File
@@ -47,8 +47,14 @@ final class KeyKit extends Command {
} finally {
umask($old);
}
if ($fh === false || fwrite($fh, $json) !== strlen($json) || !fclose($fh)) {
$output->writeln("<error>Cannot write $file (it must not exist yet)</error>");
if ($fh === false) {
$output->writeln("<error>Cannot create $file (it must not exist yet)</error>");
return 1;
}
$ok = fwrite($fh, $json) === strlen($json);
if (!fclose($fh) || !$ok) {
@unlink($file);
$output->writeln("<error>Cannot write $file</error>");
return 1;
}
$output->writeln("Recovery kit written to <info>$file</info>. Copy it off this server, then run <info>occ backup:key:confirm</info>.");