Issues (17)

src/console/SchedulerController.php (3 issues)

1
<?php
2
/**
3
 * @copyright Copyright(c) 2016 Webtools Ltd
4
 * @copyright Copyright(c) 2018 Thamtech, LLC
5
 * @link https://github.com/thamtech/yii2-scheduler
6
 * @license https://opensource.org/licenses/MIT
7
**/
8
9
namespace thamtech\scheduler\console;
10
11
use thamtech\scheduler\events\SchedulerEvent;
12
use thamtech\scheduler\models\base\SchedulerLog;
13
use thamtech\scheduler\models\SchedulerTask;
14
use thamtech\scheduler\Task;
15
use thamtech\scheduler\TaskRunner;
16
use Yii;
17
use yii\base\InvalidParamException;
18
use yii\console\Controller;
19
use yii\console\ExitCode;
20
use yii\helpers\Console;
21
22
23
/**
24
 * Scheduled task runner for Yii2
25
 *
26
 * You can use this command to manage scheduler tasks
27
 *
28
 * ```
29
 * $ ./yii scheduler/run-all
30
 * ```
31
 *
32
 */
33
class SchedulerController extends Controller
34
{
35
    /**
36
     * @var bool Force pending tasks to run.
37
     */
38
    public $force = false;
39
40
    /**
41
     * @var null|string Name of the task to run
42
     */
43
    public $taskName;
44
45
    /**
46
     * @var \thamtech\scheduler\Module the scheduler module
47
     */
48
    public $scheduler;
49
50
    /**
51
     * @var array Colour map for SchedulerTask status ids
52
     */
53
    private $_statusColors = [
54
        SchedulerTask::STATUS_PENDING => Console::FG_BLUE,
55
        SchedulerTask::STATUS_DUE => Console::FG_YELLOW,
56
        SchedulerTask::STATUS_OVERDUE => Console::FG_RED,
57
        SchedulerTask::STATUS_RUNNING => Console::FG_GREEN,
58
        SchedulerTask::STATUS_ERROR => Console::FG_RED,
59
    ];
60
61
    /**
62
     * @param string $actionId
63
     *
64
     * @return array
65
     */
66
    public function options($actionId)
67
    {
68
        $options = parent::options($actionId);
69
70
        switch ($actionId) {
71
            case 'run-all':
72
                $options[] = 'force';
73
                break;
74
            case 'run':
75
                $options[] = 'force';
76
                $options[] = 'taskName';
77
                break;
78
        }
79
80
        return $options;
81
    }
82
83
    /**
84
     * List all tasks
85
     */
86
    public function actionIndex()
87
    {
88
        // Update task index
89
        $this->scheduler->getTasks();
90
91
        $models = SchedulerTask::find()->all();
92
93
        $this->stdout($this->ansiFormat('Scheduled Tasks', Console::UNDERLINE).PHP_EOL);
94
95
        foreach ($models as $model) { /* @var SchedulerTask $model */
96
            $row = sprintf(
97
                "%s\t%s\t%s\t%s\t%s",
98
                $model->name,
99
                $model->schedule,
100
                is_null($model->last_run) ? 'NULL' : $model->last_run,
101
                $model->next_run,
102
                $model->getStatus()
103
            );
104
105
            $color = isset($this->_statusColors[$model->status_id]) ? $this->_statusColors[$model->status_id] : null;
106
            $this->stdout($this->ansiFormat($row, $color).PHP_EOL);
107
        }
108
    }
109
110
    /**
111
     * Run all due tasks
112
     */
113
    public function actionRunAll()
114
    {
115
        if (!$this->scheduler->acquireLock()) {
116
            $this->stdout("Unable to acquire lock. Another scheduler instance may still be running.\n");
117
            return ExitCode::UNAVAILABLE;
118
        }
119
120
        $tasks = $this->scheduler->getTasks();
121
122
        $this->stdout('Running Tasks:'.PHP_EOL);
123
124
        $event = new SchedulerEvent([
125
            'tasks' => $tasks,
126
            'success' => true,
127
        ]);
128
129
        $this->trigger(SchedulerEvent::EVENT_BEFORE_RUN, $event);
130
        foreach ($tasks as $task) {
131
            $this->runTask($task);
132
            if ($task->exception) {
133
                $event->success = false;
134
                $event->exceptions[] = $task->exception;
135
            }
136
        }
137
        $this->scheduler->releaseLock();
138
        $this->trigger(SchedulerEvent::EVENT_AFTER_RUN, $event);
139
140
        $this->stdout(PHP_EOL);
141
    }
142
143
    /**
144
     * Run the specified task (if due)
145
     */
146
    public function actionRun()
147
    {
148
        if (null === $this->taskName) {
149
            throw new InvalidParamException('taskName must be specified');
0 ignored issues
show
Deprecated Code introduced by
The class yii\base\InvalidParamException has been deprecated: since 2.0.14. Use [[InvalidArgumentException]] instead. ( Ignorable by Annotation )

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

149
            throw /** @scrutinizer ignore-deprecated */ new InvalidParamException('taskName must be specified');
Loading history...
150
        }
151
152
        if (!$this->scheduler->acquireLock()) {
153
            $this->stdout("Unable to acquire lock. Another scheduler instance may still be running.\n");
154
            return ExitCode::UNAVAILABLE;
155
        }
156
157
        /* @var Task $task */
158
        $task = $this->scheduler->loadTask($this->taskName);
159
160
        if (!$task) {
0 ignored issues
show
$task is of type thamtech\scheduler\Task, thus it always evaluated to true.
Loading history...
161
            $this->scheduler->releaseLock();
162
            throw new InvalidParamException('Invalid taskName');
0 ignored issues
show
Deprecated Code introduced by
The class yii\base\InvalidParamException has been deprecated: since 2.0.14. Use [[InvalidArgumentException]] instead. ( Ignorable by Annotation )

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

162
            throw /** @scrutinizer ignore-deprecated */ new InvalidParamException('Invalid taskName');
Loading history...
163
        }
164
165
        $event = new SchedulerEvent([
166
            'tasks' => [$task],
167
            'success' => true,
168
        ]);
169
170
        $this->trigger(SchedulerEvent::EVENT_BEFORE_RUN, $event);
171
        $this->runTask($task);
172
        if ($task->exception) {
173
            $event->success = false;
174
            $event->exceptions = [$task->exception];
175
        }
176
        $this->scheduler->releaseLock();
177
        $this->trigger(SchedulerEvent::EVENT_AFTER_RUN, $event);
178
179
    }
180
181
    /**
182
     * @param Task $task
183
     */
184
    private function runTask(Task $task)
185
    {
186
        if (!$task->active) {
187
            $this->stdout(sprintf("\tSkipping inactive %s", $task->getDisplayName()).PHP_EOL);
188
            return;
189
        }
190
191
        $this->stdout(sprintf("\tRunning %s...", $task->getDisplayName()));
192
        if ($task->shouldRun($this->force)) {
193
            $runner = new TaskRunner();
194
            $runner->setTask($task);
195
            $runner->setLog(new SchedulerLog());
196
            $runner->runTask($this->force);
197
            $this->stdout($runner->error ? 'error' : 'done'.PHP_EOL);
198
        } else {
199
            $this->stdout("Task is not due, use --force to run anyway".PHP_EOL);
200
        }
201
    }
202
}
203