Initial commit

This commit is contained in:
root
2025-12-21 09:55:58 -05:00
committed by Sebastian Krupinski
commit 169b7b4c91
57 changed files with 10105 additions and 0 deletions

115
lib/Queue/MailJob.php Normal file
View File

@@ -0,0 +1,115 @@
<?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'),
];
}
}