Completed
Push — master ( 2f0980...94c998 )
by Matthew
33:32 queued 29:55
created

RunCommand::execute()   A

Complexity

Conditions 3
Paths 4

Size

Total Lines 31
Code Lines 21

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 21
CRAP Score 3.0008

Importance

Changes 7
Bugs 1 Features 0
Metric Value
cc 3
eloc 21
c 7
b 1
f 0
nc 4
nop 2
dl 0
loc 31
ccs 21
cts 22
cp 0.9545
crap 3.0008
rs 9.584
1
<?php
2
3
namespace Dtc\QueueBundle\Command;
4
5
use Dtc\QueueBundle\Exception\ClassNotSubclassException;
6
use Dtc\QueueBundle\Model\Job;
7
use Dtc\QueueBundle\Run\Loop;
8
use Dtc\QueueBundle\Util\Util;
9
use Psr\Log\LoggerInterface;
10
use Symfony\Component\Console\Command\Command;
11
use Symfony\Component\Console\Input\InputArgument;
12
use Symfony\Component\Console\Input\InputInterface;
13
use Symfony\Component\Console\Input\InputOption;
14
use Symfony\Component\Console\Output\OutputInterface;
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
25 1
    protected function symfonyDetect()
26
    {
27 1
        $this->nanoSleepOption = null;
28 1
        if (class_exists('Symfony\Component\HttpKernel\Kernel')) {
29 1
            if (Kernel::VERSION_ID >= 30000) {
30 1
                $this->nanoSleepOption = 's';
31
            }
32 1
            if (Kernel::VERSION_ID >= 30400) {
33 1
                $this->loggerPrivate = true;
34
            }
35
        }
36 1
    }
37
38 1
    protected function configure()
39
    {
40 1
        $this->symfonyDetect();
41
        $options = array(
42 1
            new InputArgument('worker-name', InputArgument::OPTIONAL, 'Name of worker', null),
43 1
            new InputArgument('method', InputArgument::OPTIONAL, 'DI method of worker', null),
44 1
            new InputOption(
45 1
                'id',
46 1
                'i',
47 1
                InputOption::VALUE_REQUIRED,
48 1
                'Id of Job to run',
49 1
                null
50
            ),
51 1
            new InputOption(
52 1
                'max-count',
53 1
                'm',
54 1
                InputOption::VALUE_REQUIRED,
55 1
                'Maximum number of jobs to work on before exiting',
56 1
                null
57
            ),
58 1
            new InputOption(
59 1
                'duration',
60 1
                'd',
61 1
                InputOption::VALUE_REQUIRED,
62 1
                'Duration to run for in seconds',
63 1
                null
64
            ),
65 1
            new InputOption(
66 1
                'timeout',
67 1
                't',
68 1
                InputOption::VALUE_REQUIRED,
69 1
                'Process timeout in seconds (hard exit of process regardless)',
70 1
                3600
71
            ),
72 1
            new InputOption(
73 1
                'nano-sleep',
74 1
                $this->nanoSleepOption,
75 1
                InputOption::VALUE_REQUIRED,
76 1
                'If using duration, this is the time to sleep when there\'s no jobs in nanoseconds',
77 1
                500000000
78
            ),
79 1
            new InputOption(
80 1
                'disable-gc',
81 1
                null,
82 1
                InputOption::VALUE_NONE,
83 1
                'Disable garbage collection'
84
            ),
85
        );
86
87
        // Symfony 4 and Symfony 3.4 out-of-the-box makes the logger private
88 1
        if (!$this->loggerPrivate) {
89
            $options[] =
90
                new InputOption(
91
                    'logger',
92
                    'l',
93
                    InputOption::VALUE_REQUIRED,
94
                    'Log using the logger service specified, or output to console if null (or an invalid logger service id) is passed in'
95
                );
96
        }
97
98
        $this
99 1
            ->setName('dtc:queue:run')
100 1
            ->setDefinition($options)
101 1
            ->setDescription('Start up a job in queue');
102 1
    }
103
104 1
    public function setRunLoop($runLoop) {
105 1
        $this->runLoop = $runLoop;
106 1
    }
107
108 1
    protected function execute(InputInterface $input, OutputInterface $output)
109
    {
110 1
        $start = microtime(true);
111
        // @TODO: move this to dependency injection.
112 1
        $this->runLoop->setOutput($output);
113 1
        $workerName = $input->getArgument('worker-name');
114 1
        $methodName = $input->getArgument('method');
115 1
        $maxCount = $input->getOption('max-count');
116 1
        $duration = $input->getOption('duration');
117 1
        $processTimeout = $input->getOption('timeout');
118 1
        $nanoSleep = $input->getOption('nano-sleep');
119 1
        $loggerService = !$this->loggerPrivate ? $input->getOption('logger', null) : null;
0 ignored issues
show
Unused Code introduced by
The call to Symfony\Component\Consol...tInterface::getOption() has too many arguments starting with null. ( Ignorable by Annotation )

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

119
        $loggerService = !$this->loggerPrivate ? $input->/** @scrutinizer ignore-call */ getOption('logger', null) : null;

This check compares calls to functions or methods with their respective definitions. If the call has more arguments than are defined, it raises an issue.

If a function is defined several times with a different number of parameters, the check may pick up the wrong definition and report false positives. One codebase where this has been known to happen is Wordpress. Please note the @ignore annotation hint above.

Loading history...
120 1
        $disableGc = $input->getOption('disable-gc', false);
121 1
        $this->setGc($disableGc);
122
123 1
        $this->setLoggerService($this->runLoop, $loggerService);
124
125 1
        $maxCount = Util::validateIntNull('max_count', $maxCount, 32);
126 1
        $duration = Util::validateIntNull('duration', $duration, 32);
127 1
        $nanoSleep = Util::validateIntNull('nano_sleep', $nanoSleep, 63);
128 1
        $processTimeout = Util::validateIntNull('timeout', $processTimeout, 32);
129 1
        $this->runLoop->checkMaxCountDuration($maxCount, $duration, $processTimeout);
130
131
        // Check to see if there are other instances
132 1
        set_time_limit($processTimeout); // Set timeout on the process
133
134 1
        if ($jobId = $input->getOption('id')) {
135
            return $this->runLoop->runJobById($start, $jobId); // Run a single job
0 ignored issues
show
Bug introduced by
Are you sure the usage of $this->runLoop->runJobById($start, $jobId) targeting Dtc\QueueBundle\Run\Loop::runJobById() seems to always return null.

This check looks for function or method calls that always return null and whose return value is used.

class A
{
    function getObject()
    {
        return null;
    }

}

$a = new A();
if ($a->getObject()) {

The method getObject() can return nothing but null, so it makes no sense to use the return value.

The reason is most likely that a function or method is imcomplete or has been reduced for debug purposes.

Loading history...
136
        }
137
138 1
        return $this->runLoop->runLoop($start, $workerName, $methodName, $maxCount, $duration, $nanoSleep);
139
    }
140
141
    /**
142
     * @param bool $disableGc
143
     */
144 1
    protected function setGc($disableGc)
145
    {
146 1
        if ($disableGc) {
147
            if (gc_enabled()) {
148
                gc_disable();
149
            }
150
151
            return;
152
        }
153
154 1
        if (!gc_enabled()) {
155
            gc_enable();
156
        }
157 1
    }
158
159 1
    protected function setLoggerService(Loop $loop, $loggerService)
160
    {
161 1
        if (!$loggerService) {
162 1
            return;
163
        }
164
165
        $container = $this->getContainer();
0 ignored issues
show
Bug introduced by
The method getContainer() does not exist on Dtc\QueueBundle\Command\RunCommand. ( Ignorable by Annotation )

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

165
        /** @scrutinizer ignore-call */ 
166
        $container = $this->getContainer();

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...
166
        if (!$container->has($loggerService)) {
167
            return;
168
        }
169
170
        $logger = $container->get($loggerService);
171
        if (!$logger instanceof LoggerInterface) {
172
            throw new ClassNotSubclassException("$loggerService must be instance of Psr\\Log\\LoggerInterface");
173
        }
174
        $loop->setLogger($logger);
175
    }
176
}
177