Code Coverage
 
Lines
Functions and Methods
Classes and Traits
Total
0.00% covered (danger)
0.00%
0 / 43
0.00% covered (danger)
0.00%
0 / 13
CRAP
0.00% covered (danger)
0.00%
0 / 1
SequentialBackgroundProcess
0.00% covered (danger)
0.00%
0 / 43
0.00% covered (danger)
0.00%
0 / 13
342
0.00% covered (danger)
0.00%
0 / 1
 __construct
0.00% covered (danger)
0.00%
0 / 9
0.00% covered (danger)
0.00%
0 / 1
2
 getPayload
0.00% covered (danger)
0.00%
0 / 1
0.00% covered (danger)
0.00%
0 / 1
2
 getErrors
0.00% covered (danger)
0.00%
0 / 1
0.00% covered (danger)
0.00%
0 / 1
2
 getId
0.00% covered (danger)
0.00%
0 / 1
0.00% covered (danger)
0.00%
0 / 1
2
 getVersion
0.00% covered (danger)
0.00%
0 / 1
0.00% covered (danger)
0.00%
0 / 1
2
 getStep
0.00% covered (danger)
0.00%
0 / 1
0.00% covered (danger)
0.00%
0 / 1
2
 getRetries
0.00% covered (danger)
0.00%
0 / 1
0.00% covered (danger)
0.00%
0 / 1
2
 getStartTime
0.00% covered (danger)
0.00%
0 / 1
0.00% covered (danger)
0.00%
0 / 1
2
 getCompletionTime
0.00% covered (danger)
0.00%
0 / 1
0.00% covered (danger)
0.00%
0 / 1
2
 getStatus
0.00% covered (danger)
0.00%
0 / 1
0.00% covered (danger)
0.00%
0 / 1
2
 getResult
0.00% covered (danger)
0.00%
0 / 1
0.00% covered (danger)
0.00%
0 / 1
2
 cancel
0.00% covered (danger)
0.00%
0 / 3
0.00% covered (danger)
0.00%
0 / 1
6
 runStep
0.00% covered (danger)
0.00%
0 / 21
0.00% covered (danger)
0.00%
0 / 1
30
1<?php
2namespace Apie\Core\BackgroundProcess;
3
4use Apie\Core\ApieLib;
5use Apie\Core\Attributes\AlwaysDisabled;
6use Apie\Core\Attributes\Context;
7use Apie\Core\Attributes\FakeCount;
8use Apie\Core\Attributes\StaticCheck;
9use Apie\Core\Context\ApieContext;
10use Apie\Core\ContextConstants;
11use Apie\Core\Dto\MessageAndTimestamp;
12use Apie\Core\Entities\EntityInterface;
13use Apie\Core\Identifiers\PascalCaseSlug;
14use Apie\Core\Identifiers\Ulid;
15use Apie\Core\Lists\ItemHashmap;
16use Apie\Core\Lists\ItemList;
17use Apie\Core\Lists\MessageAndTimestampList;
18use Apie\Core\ValueObjects\DatabaseText;
19use DateTimeInterface;
20use ReflectionClass;
21use Throwable;
22
23#[FakeCount(0)]
24class SequentialBackgroundProcess implements EntityInterface
25{
26    private int $version;
27    private int $step;
28    private int $retries = 0;
29    private DateTimeInterface $startTime;
30    private ?DateTimeInterface $completionTime = null;
31    private DatabaseText $className;
32    private BackgroundProcessStatus $status = BackgroundProcessStatus::Active;
33    private SequentialBackgroundProcessIdentifier $id;
34    private mixed $result = null;
35    private MessageAndTimestampList $errors;
36
37    #[StaticCheck(new AlwaysDisabled())]
38    public function __construct(
39        BackgroundProcessDeclaration $backgroundProcessDeclaration,
40        private ItemHashmap|ItemList $payload
41    ) {
42        $this->className = new DatabaseText(get_debug_type($backgroundProcessDeclaration));
43        $this->version = $backgroundProcessDeclaration->getCurrentVersion();
44        $this->step = 0;
45        $this->startTime = ApieLib::getPsrClock()->now();
46        $this->id = new SequentialBackgroundProcessIdentifier(
47            new PascalCaseSlug((new ReflectionClass($backgroundProcessDeclaration))->getShortName()),
48            Ulid::createRandom()
49        );
50        $this->errors = new MessageAndTimestampList();
51    }
52
53    public function getPayload(): ItemHashmap|ItemList
54    {
55        return $this->payload;
56    }
57
58    public function getErrors(): MessageAndTimestampList
59    {
60        return $this->errors;
61    }
62
63    public function getId(): SequentialBackgroundProcessIdentifier
64    {
65        return $this->id;
66    }
67
68    public function getVersion(): int
69    {
70        return $this->version;
71    }
72
73    public function getStep(): int
74    {
75        return $this->step;
76    }
77
78    public function getRetries(): int
79    {
80        return $this->retries;
81    }
82
83    public function getStartTime(): DateTimeInterface
84    {
85        return $this->startTime;
86    }
87
88    public function getCompletionTime(): ?DateTimeInterface
89    {
90        return $this->completionTime;
91    }
92
93    public function getStatus(): BackgroundProcessStatus
94    {
95        return $this->status;
96    }
97
98    public function getResult(): mixed
99    {
100        return $this->result;
101    }
102
103    public function cancel(): void
104    {
105        if ($this->status !== BackgroundProcessStatus::Active) {
106            throw new \LogicException('Process ' . $this->id . ' can not be executed!');
107        }
108        $this->status = BackgroundProcessStatus::Canceled;
109    }
110
111    public function runStep(#[Context()] ApieContext $apieContext): void
112    {
113        if ($this->status !== BackgroundProcessStatus::Active) {
114            throw new \LogicException('Process ' . $this->id . ' can not be executed!');
115        }
116        $apieContext = $apieContext->withContext(ContextConstants::BACKGROUND_PROCESS, $this->result);
117        $maxRetries = 1;
118        try {
119            $className = $this->className->toNative();
120            $maxRetries = $className::getMaxRetries($this->version);
121            $steps = array_values($className::retrieveDeclaration($this->version));
122            if (isset($steps[$this->step])) {
123                $this->result = call_user_func($steps[$this->step], $apieContext, $this->payload);
124                $this->step++;
125                $this->retries = 0;
126            } else {
127                $this->completionTime = ApieLib::getPsrClock()->now();
128                $this->status = BackgroundProcessStatus::Finished;
129            }
130        } catch (Throwable $error) {
131            $this->errors[] = new MessageAndTimestamp(
132                $error->getMessage(),
133                ApieLib::getPsrClock()->now()
134            );
135            $this->retries++;
136            if ($this->retries >= $maxRetries) {
137                $this->status = BackgroundProcessStatus::TooManyErrors;
138            }
139        }
140    }
141}