1
|
|
|
<?php |
2
|
|
|
|
3
|
|
|
namespace Dtc\QueueBundle\Command; |
4
|
|
|
|
5
|
|
|
use Dtc\QueueBundle\Exception\ClassNotSubclassException; |
6
|
|
|
use Dtc\QueueBundle\Run\Loop; |
7
|
|
|
use Dtc\QueueBundle\Util\Util; |
8
|
|
|
use Psr\Log\LoggerInterface; |
|
|
|
|
9
|
|
|
use Symfony\Component\Console\Command\Command; |
|
|
|
|
10
|
|
|
use Symfony\Component\Console\Input\InputArgument; |
|
|
|
|
11
|
|
|
use Symfony\Component\Console\Input\InputInterface; |
|
|
|
|
12
|
|
|
use Symfony\Component\Console\Input\InputOption; |
|
|
|
|
13
|
|
|
use Symfony\Component\Console\Output\OutputInterface; |
|
|
|
|
14
|
|
|
use Symfony\Component\DependencyInjection\Container; |
|
|
|
|
15
|
|
|
use Symfony\Component\HttpKernel\Kernel; |
|
|
|
|
16
|
|
|
|
17
|
|
|
class RunCommand extends Command |
18
|
|
|
{ |
19
|
|
|
protected $loggerPrivate = false; |
20
|
|
|
protected $nanoSleepOption = null; |
21
|
|
|
|
22
|
|
|
/** @var Loop */ |
23
|
|
|
private $runLoop; |
24
|
|
|
/** @var LoggerInterface */ |
25
|
|
|
private $logger; |
26
|
|
|
/** @var Container */ |
27
|
|
|
private $container; |
28
|
|
|
|
29
|
1 |
|
protected function symfonyDetect() |
30
|
|
|
{ |
31
|
1 |
|
$this->nanoSleepOption = null; |
32
|
1 |
|
if (class_exists('Symfony\Component\HttpKernel\Kernel')) { |
33
|
1 |
|
if (Kernel::VERSION_ID >= 30000) { |
34
|
1 |
|
$this->nanoSleepOption = 's'; |
35
|
|
|
} |
36
|
1 |
|
if (Kernel::VERSION_ID >= 30400) { |
37
|
1 |
|
$this->loggerPrivate = true; |
38
|
|
|
} |
39
|
|
|
} |
40
|
1 |
|
} |
41
|
|
|
|
42
|
1 |
|
protected function configure(): void |
43
|
|
|
{ |
44
|
1 |
|
$this->symfonyDetect(); |
45
|
|
|
$options = [ |
46
|
1 |
|
new InputArgument('worker-name', InputArgument::OPTIONAL, 'Name of worker', null), |
47
|
1 |
|
new InputArgument('method', InputArgument::OPTIONAL, 'DI method of worker', null), |
48
|
1 |
|
new InputOption( |
49
|
1 |
|
'id', |
50
|
1 |
|
'i', |
51
|
1 |
|
InputOption::VALUE_REQUIRED, |
52
|
1 |
|
'Id of Job to run', |
53
|
1 |
|
null |
54
|
|
|
), |
55
|
1 |
|
new InputOption( |
56
|
1 |
|
'max-count', |
57
|
1 |
|
'm', |
58
|
1 |
|
InputOption::VALUE_REQUIRED, |
59
|
1 |
|
'Maximum number of jobs to work on before exiting', |
60
|
1 |
|
null |
61
|
|
|
), |
62
|
1 |
|
new InputOption( |
63
|
1 |
|
'duration', |
64
|
1 |
|
'd', |
65
|
1 |
|
InputOption::VALUE_REQUIRED, |
66
|
1 |
|
'Duration to run for in seconds', |
67
|
1 |
|
null |
68
|
|
|
), |
69
|
1 |
|
new InputOption( |
70
|
1 |
|
'timeout', |
71
|
1 |
|
't', |
72
|
1 |
|
InputOption::VALUE_REQUIRED, |
73
|
1 |
|
'Process timeout in seconds (hard exit of process regardless)', |
74
|
1 |
|
3600 |
75
|
|
|
), |
76
|
1 |
|
new InputOption( |
77
|
1 |
|
'nano-sleep', |
78
|
1 |
|
$this->nanoSleepOption, |
79
|
1 |
|
InputOption::VALUE_REQUIRED, |
80
|
1 |
|
'If using duration, this is the time to sleep when there\'s no jobs in nanoseconds', |
81
|
1 |
|
500000000 |
82
|
|
|
), |
83
|
1 |
|
new InputOption( |
84
|
1 |
|
'disable-gc', |
85
|
1 |
|
null, |
86
|
1 |
|
InputOption::VALUE_NONE, |
87
|
1 |
|
'Disable garbage collection' |
88
|
|
|
), |
89
|
|
|
]; |
90
|
|
|
|
91
|
1 |
|
$options[] = |
92
|
1 |
|
new InputOption( |
93
|
1 |
|
'logger', |
94
|
1 |
|
'l', |
95
|
1 |
|
InputOption::VALUE_REQUIRED, |
96
|
1 |
|
'Log using the logger service specified. Otherwise if not used will output to console. Logger service must be public, otherwise inject one by overriding the definition for this RunCommand service and calling the setLogger() method instead of using this option.' |
97
|
|
|
); |
98
|
|
|
|
99
|
|
|
$this |
100
|
1 |
|
->setName('dtc:queue:run') |
101
|
1 |
|
->setDefinition($options) |
102
|
1 |
|
->setDescription('Start up a job in queue'); |
103
|
1 |
|
} |
104
|
|
|
|
105
|
1 |
|
public function setRunLoop($runLoop) |
106
|
|
|
{ |
107
|
1 |
|
$this->runLoop = $runLoop; |
108
|
1 |
|
} |
109
|
|
|
|
110
|
|
|
public function setLogger(LoggerInterface $logger) |
111
|
|
|
{ |
112
|
|
|
$this->logger = $logger; |
113
|
|
|
} |
114
|
|
|
|
115
|
|
|
public function setContainer($container) |
116
|
|
|
{ |
117
|
|
|
$this->container = $container; |
118
|
|
|
} |
119
|
|
|
|
120
|
1 |
|
protected function execute(InputInterface $input, OutputInterface $output): int |
121
|
|
|
{ |
122
|
1 |
|
$start = microtime(true); |
123
|
|
|
// @TODO: move this to dependency injection. |
124
|
1 |
|
$this->runLoop->setOutput($output); |
125
|
1 |
|
$workerName = $input->getArgument('worker-name'); |
126
|
1 |
|
$methodName = $input->getArgument('method'); |
127
|
1 |
|
$maxCount = $input->getOption('max-count'); |
128
|
1 |
|
$duration = $input->getOption('duration'); |
129
|
1 |
|
$processTimeout = $input->getOption('timeout'); |
130
|
1 |
|
$nanoSleep = $input->getOption('nano-sleep'); |
131
|
1 |
|
$loggerService = !$this->loggerPrivate ? $input->getOption('logger', null) : null; |
132
|
1 |
|
$disableGc = $input->getOption('disable-gc', false); |
133
|
1 |
|
$this->setGc($disableGc); |
134
|
|
|
|
135
|
1 |
|
$this->setLoggerService($this->runLoop, $loggerService); |
136
|
|
|
|
137
|
1 |
|
$maxCount = Util::validateIntNull('max_count', $maxCount, 32); |
138
|
1 |
|
$duration = Util::validateIntNull('duration', $duration, 32); |
139
|
1 |
|
$nanoSleep = Util::validateIntNull('nano_sleep', $nanoSleep, 63); |
140
|
1 |
|
$processTimeout = Util::validateIntNull('timeout', $processTimeout, 32); |
141
|
1 |
|
$this->runLoop->checkMaxCountDuration($maxCount, $duration, $processTimeout); |
142
|
|
|
|
143
|
|
|
// Check to see if there are other instances |
144
|
1 |
|
set_time_limit($processTimeout); // Set timeout on the process |
145
|
|
|
|
146
|
1 |
|
if ($jobId = $input->getOption('id')) { |
147
|
|
|
$this->runLoop->runJobById($start, $jobId); // Run a single job |
|
|
|
|
148
|
|
|
return $this::SUCCESS; |
149
|
|
|
} |
150
|
1 |
|
|
151
|
|
|
$this->runLoop->runLoop($start, $workerName, $methodName, $maxCount, $duration, $nanoSleep); |
|
|
|
|
152
|
|
|
return $this::SUCCESS; |
153
|
|
|
} |
154
|
|
|
|
155
|
|
|
/** |
156
|
1 |
|
* @param bool $disableGc |
157
|
|
|
*/ |
158
|
1 |
|
protected function setGc($disableGc) |
159
|
|
|
{ |
160
|
|
|
if ($disableGc) { |
161
|
|
|
if (gc_enabled()) { |
162
|
|
|
gc_disable(); |
163
|
|
|
} |
164
|
|
|
|
165
|
|
|
return; |
166
|
1 |
|
} |
167
|
|
|
|
168
|
|
|
if (!gc_enabled()) { |
169
|
1 |
|
gc_enable(); |
170
|
|
|
} |
171
|
1 |
|
} |
172
|
|
|
|
173
|
1 |
|
protected function setLoggerService(Loop $loop, $loggerService) |
174
|
1 |
|
{ |
175
|
|
|
if (!$loggerService) { |
176
|
|
|
return; |
177
|
|
|
} |
178
|
|
|
|
179
|
|
|
$logger = $this->container->get($loggerService); |
180
|
|
|
if (!$logger instanceof LoggerInterface) { |
181
|
|
|
throw new ClassNotSubclassException("$loggerService must be instance of Psr\\Log\\LoggerInterface"); |
182
|
|
|
} |
183
|
|
|
$loop->setLogger($logger); |
184
|
|
|
} |
185
|
|
|
} |
186
|
|
|
|
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:For further information see https://scrutinizer-ci.com/docs/tools/php/php-scrutinizer/#list-dependency-paths