- Add comprehensive health check system with multiple endpoints - Add Prometheus metrics endpoint - Add production logging configurations (5 strategies) - Add complete deployment documentation suite: * QUICKSTART.md - 30-minute deployment guide * DEPLOYMENT_CHECKLIST.md - Printable verification checklist * DEPLOYMENT_WORKFLOW.md - Complete deployment lifecycle * PRODUCTION_DEPLOYMENT.md - Comprehensive technical reference * production-logging.md - Logging configuration guide * ANSIBLE_DEPLOYMENT.md - Infrastructure as Code automation * README.md - Navigation hub * DEPLOYMENT_SUMMARY.md - Executive summary - Add deployment scripts and automation - Add DEPLOYMENT_PLAN.md - Concrete plan for immediate deployment - Update README with production-ready features All production infrastructure is now complete and ready for deployment.
167 lines
4.4 KiB
PHP
167 lines
4.4 KiB
PHP
<?php
|
|
|
|
declare(strict_types=1);
|
|
|
|
namespace App\Framework\Queue\ValueObjects;
|
|
|
|
/**
|
|
* Value Object representing a chain of jobs with their execution order
|
|
*/
|
|
final readonly class JobChain
|
|
{
|
|
/** @var string[] */
|
|
public array $jobIds;
|
|
|
|
public function __construct(
|
|
public string $chainId,
|
|
public string $name,
|
|
array $jobIds,
|
|
public ChainExecutionMode $executionMode = ChainExecutionMode::SEQUENTIAL,
|
|
public bool $stopOnFailure = true,
|
|
public ?array $metadata = null
|
|
) {
|
|
$this->jobIds = array_values(array_unique($jobIds));
|
|
$this->validate();
|
|
}
|
|
|
|
public static function sequential(string $chainId, string $name, array $jobIds): self
|
|
{
|
|
return new self($chainId, $name, $jobIds, ChainExecutionMode::SEQUENTIAL);
|
|
}
|
|
|
|
public static function parallel(string $chainId, string $name, array $jobIds): self
|
|
{
|
|
return new self($chainId, $name, $jobIds, ChainExecutionMode::PARALLEL);
|
|
}
|
|
|
|
public static function conditional(string $chainId, string $name, array $jobIds): self
|
|
{
|
|
return new self($chainId, $name, $jobIds, ChainExecutionMode::CONDITIONAL);
|
|
}
|
|
|
|
public function isSequential(): bool
|
|
{
|
|
return $this->executionMode === ChainExecutionMode::SEQUENTIAL;
|
|
}
|
|
|
|
public function isParallel(): bool
|
|
{
|
|
return $this->executionMode === ChainExecutionMode::PARALLEL;
|
|
}
|
|
|
|
public function isConditional(): bool
|
|
{
|
|
return $this->executionMode === ChainExecutionMode::CONDITIONAL;
|
|
}
|
|
|
|
public function shouldStopOnFailure(): bool
|
|
{
|
|
return $this->stopOnFailure;
|
|
}
|
|
|
|
public function getJobCount(): int
|
|
{
|
|
return count($this->jobIds);
|
|
}
|
|
|
|
public function getFirstJob(): ?string
|
|
{
|
|
return $this->jobIds[0] ?? null;
|
|
}
|
|
|
|
public function getLastJob(): ?string
|
|
{
|
|
return end($this->jobIds) ?: null;
|
|
}
|
|
|
|
public function containsJob(string $jobId): bool
|
|
{
|
|
return in_array($jobId, $this->jobIds, true);
|
|
}
|
|
|
|
public function getJobPosition(string $jobId): ?int
|
|
{
|
|
$position = array_search($jobId, $this->jobIds, true);
|
|
|
|
return $position !== false ? $position : null;
|
|
}
|
|
|
|
public function getNextJob(string $currentJobId): ?string
|
|
{
|
|
$position = $this->getJobPosition($currentJobId);
|
|
if ($position === null) {
|
|
return null;
|
|
}
|
|
|
|
return $this->jobIds[$position + 1] ?? null;
|
|
}
|
|
|
|
public function getPreviousJob(string $currentJobId): ?string
|
|
{
|
|
$position = $this->getJobPosition($currentJobId);
|
|
if ($position === null || $position === 0) {
|
|
return null;
|
|
}
|
|
|
|
return $this->jobIds[$position - 1];
|
|
}
|
|
|
|
public function withMetadata(array $metadata): self
|
|
{
|
|
return new self(
|
|
chainId: $this->chainId,
|
|
name: $this->name,
|
|
jobIds: $this->jobIds,
|
|
executionMode: $this->executionMode,
|
|
stopOnFailure: $this->stopOnFailure,
|
|
metadata: array_merge($this->metadata ?? [], $metadata)
|
|
);
|
|
}
|
|
|
|
public function withStopOnFailure(bool $stopOnFailure): self
|
|
{
|
|
return new self(
|
|
chainId: $this->chainId,
|
|
name: $this->name,
|
|
jobIds: $this->jobIds,
|
|
executionMode: $this->executionMode,
|
|
stopOnFailure: $stopOnFailure,
|
|
metadata: $this->metadata
|
|
);
|
|
}
|
|
|
|
public function toArray(): array
|
|
{
|
|
return [
|
|
'chain_id' => $this->chainId,
|
|
'name' => $this->name,
|
|
'job_ids' => $this->jobIds,
|
|
'execution_mode' => $this->executionMode->value,
|
|
'stop_on_failure' => $this->stopOnFailure,
|
|
'job_count' => $this->getJobCount(),
|
|
'metadata' => $this->metadata,
|
|
];
|
|
}
|
|
|
|
private function validate(): void
|
|
{
|
|
if (empty(trim($this->chainId))) {
|
|
throw new \InvalidArgumentException('Chain ID cannot be empty');
|
|
}
|
|
|
|
if (empty(trim($this->name))) {
|
|
throw new \InvalidArgumentException('Chain name cannot be empty');
|
|
}
|
|
|
|
if (empty($this->jobIds)) {
|
|
throw new \InvalidArgumentException('Job chain must contain at least one job');
|
|
}
|
|
|
|
foreach ($this->jobIds as $jobId) {
|
|
if (empty(trim($jobId))) {
|
|
throw new \InvalidArgumentException('Job ID cannot be empty');
|
|
}
|
|
}
|
|
}
|
|
}
|