connection->insert('aeon_dump_manager_job', [ 'id' => $id, 'status' => 'pending', 'created_at' => (new \DateTimeImmutable())->format('Y-m-d H:i:s.v'), ]); return Uuid::fromBytesToHex($id); } public function markRunning(string $jobId): void { $this->update($jobId, ['status' => 'running']); } public function updateProgress(string $jobId, int $percent): void { $this->update($jobId, ['percent' => min(99, max(0, $percent))]); } public function markDone(string $jobId, string $filename): void { $this->update($jobId, ['status' => 'done', 'percent' => 100, 'filename' => $filename]); } public function markFailed(string $jobId, string $errorMessage): void { $this->update($jobId, ['status' => 'failed', 'error_message' => $errorMessage]); } /** * @return array{id: string, status: string, percent: ?int, filename: ?string, errorMessage: ?string}|null */ public function find(string $jobId): ?array { $row = $this->connection->fetchAssociative( 'SELECT LOWER(HEX(id)) AS id, status, percent, filename, error_message FROM aeon_dump_manager_job WHERE id = :id', ['id' => Uuid::fromHexToBytes($jobId)] ); if ($row === false) { return null; } return [ 'id' => $row['id'], 'status' => $row['status'], 'percent' => $row['percent'] !== null ? (int) $row['percent'] : null, 'filename' => $row['filename'], 'errorMessage' => $row['error_message'], ]; } public function purgeOlderThan(\DateTimeImmutable $threshold): void { $this->connection->executeStatement( 'DELETE FROM aeon_dump_manager_job WHERE created_at < :threshold', ['threshold' => $threshold->format('Y-m-d H:i:s.v')] ); } private function update(string $jobId, array $data): void { $data['updated_at'] = (new \DateTimeImmutable())->format('Y-m-d H:i:s.v'); $this->connection->update('aeon_dump_manager_job', $data, ['id' => Uuid::fromHexToBytes($jobId)]); } }