116 lines
3.3 KiB
PHP
116 lines
3.3 KiB
PHP
<?php
|
|
|
|
declare(strict_types=1);
|
|
|
|
/**
|
|
* SPDX-FileCopyrightText: Sebastian Krupinski <krupinski01@gmail.com>
|
|
* SPDX-License-Identifier: AGPL-3.0-or-later
|
|
*/
|
|
|
|
namespace KTXM\MailManager\Queue;
|
|
|
|
use DateTimeImmutable;
|
|
use KTXF\Mail\Entity\IMessageMutable;
|
|
use KTXF\Mail\Queue\SendOptions;
|
|
|
|
/**
|
|
* Mail Job
|
|
*
|
|
* Represents a queued mail job with metadata and message content.
|
|
*
|
|
* @since 2025.05.01
|
|
*/
|
|
class MailJob {
|
|
|
|
public function __construct(
|
|
public readonly string $id,
|
|
public readonly string $tenantId,
|
|
public readonly string $providerId,
|
|
public readonly string|int $serviceId,
|
|
public readonly IMessageMutable $message,
|
|
public readonly SendOptions $options,
|
|
public JobStatus $status = JobStatus::Pending,
|
|
public int $attempts = 0,
|
|
public ?string $lastError = null,
|
|
public ?string $messageId = null,
|
|
public ?DateTimeImmutable $created = null,
|
|
public ?DateTimeImmutable $scheduled = null,
|
|
public ?DateTimeImmutable $lastAttempt = null,
|
|
public ?DateTimeImmutable $completed = null,
|
|
) {
|
|
$this->created = $this->created ?? new DateTimeImmutable();
|
|
$this->scheduled = $this->scheduled ?? $this->calculateScheduledTime();
|
|
}
|
|
|
|
/**
|
|
* Calculate when this job should be processed
|
|
*
|
|
* @return DateTimeImmutable
|
|
*/
|
|
private function calculateScheduledTime(): DateTimeImmutable {
|
|
$scheduled = $this->created ?? new DateTimeImmutable();
|
|
|
|
if ($this->options->delaySeconds !== null && $this->options->delaySeconds > 0) {
|
|
$scheduled = $scheduled->modify("+{$this->options->delaySeconds} seconds");
|
|
}
|
|
|
|
return $scheduled;
|
|
}
|
|
|
|
/**
|
|
* Check if the job is ready to be processed
|
|
*
|
|
* @return bool
|
|
*/
|
|
public function isReady(): bool {
|
|
if ($this->status !== JobStatus::Pending) {
|
|
return false;
|
|
}
|
|
|
|
return $this->scheduled === null || $this->scheduled <= new DateTimeImmutable();
|
|
}
|
|
|
|
/**
|
|
* Check if the job can be retried
|
|
*
|
|
* @return bool
|
|
*/
|
|
public function canRetry(): bool {
|
|
return $this->attempts < $this->options->retryCount;
|
|
}
|
|
|
|
/**
|
|
* Get retry delay in seconds based on attempt count (exponential backoff)
|
|
*
|
|
* @return int
|
|
*/
|
|
public function getRetryDelay(): int {
|
|
// Exponential backoff: 30s, 60s, 120s, 240s, ...
|
|
return min(30 * (2 ** $this->attempts), 3600);
|
|
}
|
|
|
|
/**
|
|
* Serialize job metadata for storage
|
|
*
|
|
* @return array
|
|
*/
|
|
public function toMetaArray(): array {
|
|
return [
|
|
'id' => $this->id,
|
|
'tenantId' => $this->tenantId,
|
|
'providerId' => $this->providerId,
|
|
'serviceId' => $this->serviceId,
|
|
'options' => $this->options->jsonSerialize(),
|
|
'status' => $this->status->value,
|
|
'attempts' => $this->attempts,
|
|
'lastError' => $this->lastError,
|
|
'messageId' => $this->messageId,
|
|
'created' => $this->created?->format('c'),
|
|
'scheduled' => $this->scheduled?->format('c'),
|
|
'lastAttempt' => $this->lastAttempt?->format('c'),
|
|
'completed' => $this->completed?->format('c'),
|
|
];
|
|
}
|
|
|
|
}
|