Code Coverage
 
Lines
Functions and Methods
Classes and Traits
Total
78.05% covered (success)
78.05%
64 / 82
25.00% covered (danger)
25.00%
2 / 8
CRAP
0.00% covered (danger)
0.00%
0 / 1
QueueController
78.05% covered (success)
78.05%
64 / 82
25.00% covered (danger)
25.00%
2 / 8
53.27
0.00% covered (danger)
0.00%
0 / 1
 resolveApp
100.00% covered (success)
100.00%
10 / 10
100.00% covered (success)
100.00%
1 / 1
3
 worker
100.00% covered (success)
100.00%
7 / 7
100.00% covered (success)
100.00%
1 / 1
3
 config
0.00% covered (danger)
0.00%
0 / 3
0.00% covered (danger)
0.00%
0 / 1
6
 work
84.62% covered (success)
84.62%
11 / 13
0.00% covered (danger)
0.00%
0 / 1
6.13
 scheduler
76.92% covered (success)
76.92%
10 / 13
0.00% covered (danger)
0.00%
0 / 1
6.44
 clear
71.43% covered (success)
71.43%
5 / 7
0.00% covered (danger)
0.00%
0 / 1
3.21
 jobs
78.57% covered (success)
78.57%
11 / 14
0.00% covered (danger)
0.00%
0 / 1
7.48
 tasks
66.67% covered (warning)
66.67%
10 / 15
0.00% covered (danger)
0.00%
0 / 1
10.37
1<?php
2declare(strict_types=1);
3/**
4 * Pop PHP Framework (http://www.popphp.org/)
5 *
6 * @link       https://github.com/popphp/pop-bootstrap
7 * @author     Nick Sagona, III <nick@noladev.com>
8 * @copyright  Copyright (c) 2012-2025 NOLA Interactive, LLC.
9 * @license    http://www.popphp.org/license     New BSD License
10 */
11
12/**
13 * @namespace
14 */
15namespace Pop\Kettle\Controller;
16
17use Pop\Console\Color;
18use Pop\Kettle\Model;
19
20/**
21 * Console queue controller class
22 *
23 * @category   Pop\Kettle
24 * @package    Pop\Kettle
25 * @author     Nick Sagona, III <nick@noladev.com>
26 * @copyright  Copyright (c) 2012-2025 NOLA Interactive, LLC.
27 * @license    http://www.popphp.org/license     New BSD License
28 * @version    3.0.0
29 */
30class QueueController extends AbstractController
31{
32
33    /**
34     * Resolve the consuming application's own Application instance, printing a friendly
35     * error and returning null if nothing is scaffolded
36     *
37     * @return ?\Pop\Application
38     */
39    protected function resolveApp(): ?\Pop\Application
40    {
41        try {
42            $app = (new Model\Application())->resolveAppInstance(
43                getcwd(), $this->application->autoloader(), $this->application->config()['routes']
44            );
45        } catch (\Exception $e) {
46            $app = null;
47        }
48
49        // Null means either nothing is scaffolded, or the app class isn't autoloadable
50        // (e.g. a missing or incomplete kettle.inc.php) - either way, say so
51        if ($app === null) {
52            $this->console->write($this->console->colorize(
53                "No application was detected. Run 'app:init' first.", Color::BOLD_RED
54            ));
55        }
56
57        return $app;
58    }
59
60    /**
61     * Resolve the app and build a worker for $queue, printing a friendly error and
62     * returning null on failure
63     *
64     * @param  string $queue
65     * @return ?\Pop\Queue\Worker
66     */
67    protected function worker(string $queue): ?\Pop\Queue\Worker
68    {
69        $app = $this->resolveApp();
70        if ($app === null) {
71            return null;
72        }
73
74        try {
75            return (new Model\Queue())->buildWorker(getcwd(), $app, $queue);
76        } catch (\Exception $e) {
77            $this->console->write($this->console->colorize($e->getMessage(), Color::BOLD_RED));
78            return null;
79        }
80    }
81
82    /**
83     * Config command
84     *
85     * @param  ?string $queue
86     * @return void
87     */
88    public function config(?string $queue = 'default'): void
89    {
90        if ($queue === null) {
91            $queue = 'default';
92        }
93
94        (new Model\Queue())->configure($this->console, getcwd(), $queue);
95    }
96
97    /**
98     * Work command
99     *
100     * @param  ?string $queue
101     * @param  array   $options
102     * @return void
103     */
104    public function work(?string $queue = 'default', array $options = []): void
105    {
106        if ($queue === null) {
107            $queue = 'default';
108        }
109
110        $worker = $this->worker($queue);
111        if ($worker === null) {
112            return;
113        }
114
115        if (isset($options['once'])) {
116            if ($queue == 'all') {
117                $worker->workAll();
118            } else {
119                $worker->work($queue);
120            }
121            $this->console->write('Worker pass complete.');
122        } else {
123            $sleep = isset($options['sleep']) ? (int)$options['sleep'] : 1;
124            $this->console->write('Worker started. Press Ctrl+C to stop.');
125            $worker->workLoop($sleep);
126        }
127    }
128
129    /**
130     * Scheduler command
131     *
132     * @param  ?string $queue
133     * @param  array   $options
134     * @return void
135     */
136    public function scheduler(?string $queue = 'default', array $options = []): void
137    {
138        if ($queue === null) {
139            $queue = 'default';
140        }
141
142        $worker = $this->worker($queue);
143        if ($worker === null) {
144            return;
145        }
146
147        if (isset($options['once'])) {
148            if ($queue == 'all') {
149                $worker->runAll();
150            } else {
151                $worker->run($queue);
152            }
153            $this->console->write('Scheduler pass complete.');
154        } else {
155            $sleep = isset($options['sleep']) ? (int)$options['sleep'] : 1;
156            $this->console->write('Scheduler started. Press Ctrl+C to stop.');
157            $worker->runLoop($sleep);
158        }
159    }
160
161    /**
162     * Clear command
163     *
164     * @param  ?string $queue
165     * @param  array   $options
166     * @return void
167     */
168    public function clear(?string $queue = 'default', array $options = []): void
169    {
170        if ($queue === null) {
171            $queue = 'default';
172        }
173
174        $worker = $this->worker($queue);
175        if ($worker === null) {
176            return;
177        }
178
179        (new Model\Queue())->clear($worker, $queue, isset($options['failed']), isset($options['tasks']));
180        $this->console->write("Queue '" . $queue . "' cleared.");
181    }
182
183    /**
184     * Jobs command
185     *
186     * @param  ?string $queue
187     * @return void
188     */
189    public function jobs(?string $queue = 'default'): void
190    {
191        if ($queue === null) {
192            $queue = 'default';
193        }
194
195        $worker = $this->worker($queue);
196        if ($worker === null) {
197            return;
198        }
199
200        $model = new Model\Queue();
201        $names = ($queue == 'all') ? array_keys($worker->getQueues()) : [$queue];
202
203        foreach ($names as $name) {
204            $summary = $model->jobsSummary($worker->getQueue($name));
205
206            $this->console->write($this->console->colorize("Queue '" . $name . "':", Color::BOLD_CYAN));
207            $this->console->write('    Pending: ' . $summary['pending']);
208            $this->console->write('    Dead:    ' . $summary['dead']);
209
210            foreach ($summary['deadJobs'] as $jobId => $reason) {
211                $this->console->write('        - ' . $jobId . (($reason !== null) ? ' (' . $reason . ')' : ''));
212            }
213        }
214    }
215
216    /**
217     * Tasks command
218     *
219     * @param  ?string $queue
220     * @return void
221     */
222    public function tasks(?string $queue = 'default'): void
223    {
224        if ($queue === null) {
225            $queue = 'default';
226        }
227
228        $worker = $this->worker($queue);
229        if ($worker === null) {
230            return;
231        }
232
233        $model = new Model\Queue();
234        $names = ($queue == 'all') ? array_keys($worker->getQueues()) : [$queue];
235
236        foreach ($names as $name) {
237            $summary = $model->tasksSummary($worker->getQueue($name));
238
239            $this->console->write($this->console->colorize("Queue '" . $name . "':", Color::BOLD_CYAN));
240
241            if (empty($summary)) {
242                $this->console->write('    No scheduled tasks.');
243            } else {
244                foreach ($summary as $taskId => $task) {
245                    $grace = ($task['gracePeriod'] !== null) ? ' (grace: ' . $task['gracePeriod'] . 's)' : '';
246                    $this->console->write('    - ' . $taskId . ': ' . $task['schedule'] . $grace);
247                }
248            }
249        }
250    }
251
252}