get(function () use ($total): bool { if ($this->isActive()) { return false; } $this->put([ 'status' => 'running', 'total' => $total, 'imported' => 0, 'error' => null, 'started_at' => now()->getTimestamp(), ]); return true; }); } public function advance(): void { $run = $this->raw(); if ($run !== null) { $run['imported']++; $this->put($run); } } public function finish(): void { $this->end('finished'); } public function fail(string $error): void { $this->end('failed', $error); } public function isActive(): bool { return ($this->current()['status'] ?? null) === 'running'; } /** * The run as the page shows it. A running run that has gone quiet is * reported as stalled. * * @return array{status: string, total: int, imported: int, error: ?string, started_at: int}|null */ public function current(): ?array { $run = $this->raw(); if ($run === null) { return null; } if ($run['status'] === 'running' && now()->getTimestamp() - $run['updated_at'] > self::STALL_SECONDS) { $run['status'] = 'stalled'; } unset($run['updated_at']); return $run; } private function end(string $status, ?string $error = null): void { $run = $this->raw(); if ($run !== null) { $this->put([...$run, 'status' => $status, 'error' => $error]); } } /** * @return Run|null */ private function raw(): ?array { return Cache::get(self::KEY); } /** * @param array $run */ private function put(array $run): void { Cache::put(self::KEY, [...$run, 'updated_at' => now()->getTimestamp()], self::TTL_SECONDS); } }