Without system cron: warning and a backup that moves on while the page is open (#13); progress of the database phase; Bin tab

- The admin page and backup:status warn when background jobs do not run on a
  system cron, or the cron stopped, with a link to how to set one up.
- Without a working system cron, the open admin page moves a running backup
  forward through /api/tick, a short step per poll.
- The database phase shows the tables dumped ("db: 47/183 tables"); a backup
  that has not moved for 15 minutes says it is waiting for background jobs.
- The trash of restore points is on a tab of its own, Bin.
- New screenshots; changelog and plan for 1.0.2.
This commit is contained in:
2026-11-04 04:08:20 +01:00
parent d7c7ca093b
commit 36a30732ad
20 changed files with 529 additions and 75 deletions
+30 -1
View File
@@ -48,6 +48,7 @@ final class AdminApiController extends Controller {
private \OCA\NgBackup\Service\KeySlotService $slots,
private \OCA\NgBackup\Service\PruneService $prune,
private \OCA\NgBackup\Service\Schedule $schedule,
private \OCA\NgBackup\Service\CronHealth $cron,
) {
parent::__construct(Application::APP_ID, $request);
}
@@ -75,9 +76,36 @@ final class AdminApiController extends Controller {
'recentDays' => \OCA\NgBackup\Command\Status::RECENT_DAYS,
'schedule' => $this->schedule->get()['time'],
'scheduleTimezone' => $this->schedule->get()['timezone'],
'cron' => $this->cron->check(),
]);
}
/** Seconds of backup work one tick() does: well within a normal web request. */
public const TICK_SECONDS = 10.0;
/**
* Move running backups forward from the open admin page, when background jobs do not run on a
* working system cron (#13). The page calls this while a backup runs, so "Back up now" works
* without cron as long as the page stays open; scheduled backups still need cron. With a
* working system cron this does nothing: the background job does the work.
*/
public function tick(): JSONResponse {
if ($this->cron->check()['ok']) {
return new JSONResponse(['stepped' => 0]);
}
$deadline = microtime(true) + self::TICK_SECONDS;
$stepped = 0;
foreach ($this->runs->findRunning(null, BackupService::KIND_FULL) as $run) {
if (microtime(true) >= $deadline) {
break;
}
// step() returns at once when the background job (or another tab) holds the run.
$this->backups->step($run, $deadline);
$stepped++;
}
return new JSONResponse(['stepped' => $stepped]);
}
#[PasswordConfirmationRequired]
public function initKey(string $passphrase, int $deleteDelayDays = \OCA\NgBackup\Service\KeyService::DEFAULT_DELETE_DELAY, string $label = 'Slot 1'): JSONResponse {
try {
@@ -313,6 +341,7 @@ final class AdminApiController extends Controller {
return ['id' => $r->getId(), 'targetId' => $r->getTargetId(), 'kind' => $r->getKind(), 'status' => $r->getStatus(),
'phase' => $r->getPhase(), 'snapshotId' => $r->getSnapshotId(), 'snapshot' => $snapshot, 'startedAt' => $r->getStartedAt(),
'updatedAt' => $r->getUpdatedAt(), 'finishedAt' => $r->getFinishedAt(), 'error' => $r->getError(),
'stats' => json_decode($r->getStats() ?? 'null', true), 'progress' => \OCA\NgBackup\Job\BackupRun::progressOf($r)];
'stats' => json_decode($r->getStats() ?? 'null', true), 'progress' => \OCA\NgBackup\Job\BackupRun::progressOf($r),
'waitingFor' => $r->getKind() === BackupService::KIND_FULL ? \OCA\NgBackup\Service\CronHealth::waitingFor($r) : null];
}
}