• Home
  • Features
  • Pricing
  • Docs
  • Announcements
  • Sign In

daycry / jobs / 21145580946

19 Jan 2026 04:55PM UTC coverage: 58.025% (-4.5%) from 62.567%
21145580946

push

github

daycry
Add security, performance, and health features; simplify architecture

Introduces shell command whitelisting, smart token detection, per-queue rate limiting, dead letter queue, job timeout protection, config caching, and a health monitoring command. Refactors architecture by consolidating traits, removing the CompletionStrategy pattern, and unifying retry policies under RetryPolicyFixed. Updates documentation and tests to reflect new features and architectural changes, ensuring backward compatibility and improved reliability.

143 of 340 new or added lines in 20 files covered. (42.06%)

1 existing line in 1 file now uncovered.

1193 of 2056 relevant lines covered (58.03%)

4.44 hits per line

Source File
Press 'n' to go to next uncovered line, 'b' for previous

84.09
/src/Job.php
1
<?php
2

3
declare(strict_types=1);
4

5
/**
6
 * This file is part of Daycry Queues.
7
 *
8
 * (c) Daycry <daycry9@proton.me>
9
 *
10
 * For the full copyright and license information, please view
11
 * the LICENSE file that was distributed with this source code.
12
 */
13

14
namespace Daycry\Jobs;
15

16
use DateTime;
17
use DateTimeZone;
18
use Daycry\Jobs\Traits\ActivityTrait;
19
use Daycry\Jobs\Traits\CallbackTrait;
20
use Daycry\Jobs\Traits\EnqueuableTrait;
21
use Daycry\Jobs\Traits\EnvironmentTrait;
22
use Daycry\Jobs\Traits\FrequenciesTrait;
23
use Daycry\Jobs\Traits\IdentityTrait;
24
use Daycry\Jobs\Traits\StateTrait;
25
use Throwable;
26

27
/**
28
 * Core Job definition aggregating scheduling traits, queue metadata, naming,
29
 * environment constraints, retry limits, notification flags and more.
30
 *
31
 * This class is a mutable builder used prior to execution. Execution runtime
32
 * state/results are captured separately by immutable DTOs (ExecutionResult, LifecycleOutcome).
33
 *
34
 * Properties (selected):
35
 *  - job: handler key referencing an entry in config('Jobs')->jobs
36
 *  - payload: mixed user data passed to the handler
37
 *  - singleInstance: whether only one concurrent execution is allowed
38
 *  - schedule: optional DateTime for queue delayed execution
39
 *  - attempts: internal retry attempt counter for queue contexts
40
 */
41
class Job
42
{
43
    use EnvironmentTrait;
44
    use FrequenciesTrait;
45
    use IdentityTrait;
46
    use ActivityTrait;
47
    use StateTrait;
48
    use EnqueuableTrait;
49
    use CallbackTrait;
50

51
    protected string $job;
52
    protected mixed $payload;
53
    protected bool $singleInstance = false;
54

55
    /**
56
     * Origin of the job: 'cron' when created via Scheduler, 'queue' when pushed directly,
57
     * or custom (e.g. 'api') if set by integrator. Propagated into logs for observability.
58
     */
59
    protected ?string $source = null;
60

61
    /**
62
     * True when this job was generated as a callback child of another job.
63
     */
64
    protected bool $isCallbackChild = false;
65

66
    /**
67
     * Whether this callback child is permitted to trigger its own callback chain.
68
     */
69
    protected bool $callbackChainAllowed = false;
70

71
    public function __construct(...$params)
72
    {
73
        $this->job     = $params['job'] ?? '';
71✔
74
        $this->payload = $params['payload'] ?? '';
71✔
75
    }
76

77
    public function getJob(): string
78
    {
79
        return $this->job;
46✔
80
    }
81

82
    public function getPayload(): mixed
83
    {
84
        return $this->payload;
35✔
85
    }
86

87
    /**
88
     * Internal helper allowing lifecycle components to adjust payload (e.g., injecting meta for callback jobs).
89
     */
90
    public function setPayload(mixed $payload): self
91
    {
92
        $this->payload = $payload;
8✔
93

94
        return $this;
8✔
95
    }
96

97
    public function singleInstance(bool $singleInstance = true): self
98
    {
99
        $this->singleInstance = $singleInstance;
59✔
100

101
        return $this;
59✔
102
    }
103

104
    public function isSingleInstance(): bool
105
    {
106
        return $this->singleInstance;
18✔
107
    }
108

109
    public function toObject(): object
110
    {
111
        $data = get_object_vars($this);
22✔
112

113
        unset($data['types'], $data['worker']);
22✔
114

115
        $data = json_decode(json_encode($data));
22✔
116

117
        if (isset($data->schedule->date)) {
22✔
118
            $data->schedule = new DateTime($data->schedule->date, new DateTimeZone($data->schedule->timezone));
6✔
119
        } else {
120
            $data->schedule = null;
17✔
121
        }
122

123
        return $data;
22✔
124
    }
125

126
    /**
127
     * Define origin source for logging/analytics.
128
     */
129
    public function source(string $source): self
130
    {
131
        $this->source = $source;
26✔
132

133
        return $this;
26✔
134
    }
135

136
    public function getSource(): ?string
137
    {
138
        return $this->source;
23✔
139
    }
140

141
    public function markAsCallbackChild(bool $allowChain = false): self
142
    {
143
        $this->isCallbackChild      = true;
8✔
144
        $this->callbackChainAllowed = $allowChain;
8✔
145

146
        return $this;
8✔
147
    }
148

149
    public function isCallbackChild(): bool
150
    {
151
        return $this->isCallbackChild;
×
152
    }
153

154
    public function isCallbackChainAllowed(): bool
155
    {
156
        return $this->callbackChainAllowed;
×
157
    }
158

159
    /**
160
     * Rebuild a Job instance from a queue record object.
161
     * The $record must at minimum provide 'job' and 'payload'. Optional fields restored:
162
     *  name, queue, priority, schedule (DateTime or serialized), attempts.
163
     */
164
    public static function fromQueueRecord(object $record): self
165
    {
166
        $instance = new self(job: $record->job ?? '', payload: $record->payload ?? null);
3✔
167

168
        // Restaurar propiedades conocidas si existen
169
        if (isset($record->name)) {
3✔
170
            $instance->named($record->name);
1✔
171
        }
172
        if (isset($record->queue)) {
3✔
173
            $instance->setQueue($record->queue);
2✔
174
        }
175
        if (isset($record->priority)) {
3✔
176
            try {
177
                $instance->priority((int) $record->priority);
2✔
178
            } catch (Throwable) { // ignore invalid
×
179
            }
180
        }
181
        if (isset($record->schedule) && $record->schedule) {
3✔
182
            try {
183
                $dt = new DateTime($record->schedule->date ?? $record->schedule, new DateTimeZone($record->schedule->timezone ?? date_default_timezone_get()));
2✔
184
                $instance->scheduled($dt);
2✔
185
            } catch (Throwable) {
×
186
                // ignorar si no se puede parsear
187
            }
188
        }
189
        // Attempts (si estuviera presente en versiones futuras)
190
        if (isset($record->attempts) && is_numeric($record->attempts)) {
3✔
191
            // Forzar el contador interno sumando tantas veces como sea necesario
192
            for ($i = 0; $i < (int) $record->attempts; $i++) {
2✔
193
                $instance->addAttempt();
×
194
            }
195
        }
196

197
        // Restore maxRetries configuration
198
        if (isset($record->maxRetries) && is_numeric($record->maxRetries)) {
3✔
NEW
199
            $instance->maxRetries((int) $record->maxRetries);
×
200
        }
201

202
        // Restore callback flags if present (for enqueued callback children)
203
        if (isset($record->isCallbackChild) && $record->isCallbackChild) {
3✔
204
            $instance->markAsCallbackChild((bool) ($record->callbackChainAllowed ?? false));
×
205
        }
206

207
        return $instance;
3✔
208
    }
209
}
STATUS · Troubleshooting · Open an Issue · Sales · Support · CAREERS · ENTERPRISE · START FREE · SCHEDULE DEMO
ANNOUNCEMENTS · TWITTER · TOS & SLA · Supported CI Services · What's a CI service? · Automated Testing

© 2026 Coveralls, Inc