'array', 'result' => 'array', 'started_at' => 'datetime', 'completed_at' => 'datetime', 'next_retry_at' => 'datetime', ]; public const STATUS_PENDING = 'pending'; public const STATUS_RUNNING = 'running'; public const STATUS_COMPLETED = 'completed'; public const STATUS_FAILED = 'failed'; public const STATUS_CANCELLED = 'cancelled'; protected static function boot() { parent::boot(); static::creating(function ($model) { $model->uuid = $model->uuid ?? Str::uuid()->toString(); }); } public function provisionable(): MorphTo { return $this->morphTo(); } public function markRunning(): void { $this->update([ 'status' => self::STATUS_RUNNING, 'started_at' => now(), 'attempts' => $this->attempts + 1, ]); } public function markCompleted(array $result = []): void { $this->update([ 'status' => self::STATUS_COMPLETED, 'completed_at' => now(), 'result' => $result, ]); } public function markFailed(string $error, bool $canRetry = true): void { $status = ($canRetry && $this->attempts < $this->max_attempts) ? self::STATUS_PENDING : self::STATUS_FAILED; $this->update([ 'status' => $status, 'error_message' => $error, 'next_retry_at' => $status === self::STATUS_PENDING ? now()->addMinutes(5) : null, ]); } public function scopePending($query) { return $query->where('status', self::STATUS_PENDING) ->where(function ($q) { $q->whereNull('next_retry_at') ->orWhere('next_retry_at', '<=', now()); }); } }