Issues (29)

src/TaskRunner.php (5 issues)

1
<?php
2
3
declare(strict_types=1);
4
5
/**
6
 * This file is part of BlitzPHP Tasks.
7
 *
8
 * (c) 2025 Dimitri Sitchet Tomkeu <[email protected]>
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 BlitzPHP\Tasks;
15
16
use Ahc\Cli\Output\Color;
17
use Ahc\Cli\Output\Writer;
18
use BlitzPHP\Utilities\Date;
19
use Throwable;
20
21
/**
22
 * @credit <a href="https://tasks.codeigniter.com">CodeIgniter4 - CodeIgniter\Tasks\TaskRunner</a>
23
 */
24
class TaskRunner
25
{
26
    protected Scheduler $scheduler;
27
    protected ?string $testTime = null;
28
29
    /**
30
     * Stocke les alias des tâches à exécuter
31
     * Si vide, toutes les tâches seront exécutées selon leur planification.
32
     *
33
     * @var list<mixed>
0 ignored issues
show
The type BlitzPHP\Tasks\list was not found. Maybe you did not declare it correctly or list all dependencies?

The issue could also be caused by a filter entry in the build configuration. If the path has been excluded in your configuration, e.g. excluded_paths: ["lib/*"], you can move it to the dependency path list as follows:

filter:
    dependency_paths: ["lib/*"]

For further information see https://scrutinizer-ci.com/docs/tools/php/php-scrutinizer/#list-dependency-paths

Loading history...
34
     */
35
    protected array $only = [];
36
37
    /**
38
     * Instance de la sortie de la console
39
     */
40
    protected static ?Writer $writter = null;
41
42
    public function __construct(?Scheduler $scheduler = null)
43
    {
44
        $this->scheduler = $scheduler ?? service('scheduler');
45
    }
46
47
    /**
48
     * Point d'entrée principal pour l'exécution des tâches au sein du système.
49
     * Il s'occupe également de la collecte des données de sortie et de l'envoi de notifications si nécessaire.
50
     */
51
    public function run(): void
52
    {
53
        $tasks = $this->scheduler->getTasks();
54
55
        if ($tasks === []) {
56
            return;
57
        }
58
59
        foreach ($tasks as $task) {
60
            // Si des tâches spécifiques ont été choisies, sauter l'exécution des tâches restantes.
61
            if (! empty($this->only) && ! in_array($task->name, $this->only, true)) {
62
                continue;
63
            }
64
65
            if (! $task->shouldRun($this->testTime) && empty($this->only)) {
66
                continue;
67
            }
68
69
            $error  = null;
70
            $start  = Date::now();
71
            $output = null;
0 ignored issues
show
The assignment to $output is dead and can be removed.
Loading history...
72
73
            $this->cliWrite('Traitement: ' . ($task->name ?: 'Task'), Color::GREEN);
74
75
            try {
76
                $output = $task->run();
77
78
                $this->cliWrite('Exécuté: ' . ($task->name ?: 'Task'), Color::CYAN);
79
            } catch (Throwable $e) {
80
                $this->cliWrite('Échoué: ' . ($task->name ?: 'Task'), Color::RED);
81
82
                logger()->error($e->getMessage(), $e->getTrace());
83
                $error = $e;
84
            } finally {
85
                // Sauvegarde des informations sur les performances
86
                $taskLog = new TaskLog([
87
                    'task'     => $task,
88
                    'output'   => $output,
89
                    'runStart' => $start,
90
                    'runEnd'   => Date::now(),
91
                    'error'    => $error,
92
                ]);
93
94
                $this->updateLogs($taskLog);
95
            }
96
        }
97
    }
98
99
    /**
100
     * Spécifier les tâches à exécuter
101
     *
102
     * @param list<mixed> $tasks
103
     */
104
    public function only(array $tasks = []): self
105
    {
106
        $this->only = $tasks;
0 ignored issues
show
Documentation Bug introduced by
It seems like $tasks of type array is incompatible with the declared type BlitzPHP\Tasks\list of property $only.

Our type inference engine has found an assignment to a property that is incompatible with the declared type of that property.

Either this assignment is in error or the assigned type should be added to the documentation/type hint for that property..

Loading history...
107
108
        return $this;
109
    }
110
111
    /**
112
     * Définit une heure qui sera utilisée.
113
     * Permet de définir une heure spécifique par rapport à laquelle le test sera effectué.
114
     * Doit être dans un format compatible avec DateTime.
115
     */
116
    public function withTestTime(string $time): self
117
    {
118
        $this->testTime = $time;
119
120
        return $this;
121
    }
122
123
    /**
124
     * Ecrire une ligne dans l'interface de ligne de commande
125
     */
126
    protected function cliWrite(string $text, ?int $foreground = null): void
127
    {
128
        // Sauter l'écriture pour cli dans les tests
129
        if (on_test()) {
130
            return;
131
        }
132
133
        if (! is_cli()) {
134
            return;
135
        }
136
137
        if (static::$writter === null) {
138
            static::$writter = new Writer();
139
        }
140
141
        static::$writter->write(
142
            text: static::$writter->colorizer()->line('[' . date('Y-m-d H:i:s') . '] ' . $text, ['fg' => $foreground]),
0 ignored issues
show
The method colorizer() does not exist on null. ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-call  annotation

142
            text: static::$writter->/** @scrutinizer ignore-call */ colorizer()->line('[' . date('Y-m-d H:i:s') . '] ' . $text, ['fg' => $foreground]),

This check looks for calls to methods that do not seem to exist on a given type. It looks for the method on the type itself as well as in inherited classes or implemented interfaces.

This is most likely a typographical error or the method has been renamed.

Loading history...
143
            eol: true,
144
        );
145
    }
146
147
    /**
148
     * Ajoute le journal des performances
149
     */
150
    protected function updateLogs(TaskLog $taskLog): void
151
    {
152
        if (parametre('tasks.log_performance') === false) {
153
            return;
154
        }
155
156
        // un nom « unique » sera renvoyé s'il n'a pas été défini
157
        $name = $taskLog->task->name;
158
159
        $data = [
160
            'task'     => $name,
161
            'type'     => $taskLog->task->getType(),
162
            'start'    => $taskLog->runStart->format('Y-m-d H:i:s'),
163
            'duration' => $taskLog->duration(),
164
            'output'   => $taskLog->output ?? null,
165
            'error'    => serialize($taskLog->error ?? null),
166
        ];
167
168
        // Obtenir les logs existants
169
        $logs = parametre("tasks.log-{$name}");
170
        if (empty($logs)) {
171
            $logs = [];
172
        }
173
174
        // Assurez-vous que nous avons de la place pour un de plus
175
        /** @var int $maxLogsPerTask */
176
        $maxLogsPerTask = parametre('tasks.max_logs_per_task');
177
        if ((is_countable($logs) ? count($logs) : 0) > $maxLogsPerTask) {
0 ignored issues
show
It seems like $logs can also be of type boolean and double and integer; however, parameter $value of count() does only seem to accept Countable|array, maybe add an additional type check? ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-type  annotation

177
        if ((is_countable($logs) ? count(/** @scrutinizer ignore-type */ $logs) : 0) > $maxLogsPerTask) {
Loading history...
178
            array_pop($logs);
179
        }
180
181
        // Add the log to the top of the array
182
        array_unshift($logs, $data);
183
184
        parametre("tasks.log-{$name}", $logs);
185
    }
186
}
187