Passed
Push — master ( 4d8734...991786 )
by Matthew
09:35 queued 06:44
created

RunCommand   A

Complexity

Total Complexity 17

Size/Duplication

Total Lines 152
Duplicated Lines 0 %

Test Coverage

Coverage 82%

Importance

Changes 0
Metric Value
eloc 97
dl 0
loc 152
ccs 82
cts 100
cp 0.82
rs 10
c 0
b 0
f 0
wmc 17

5 Methods

Rating   Name   Duplication   Size   Complexity  
A setGc() 0 12 4
A execute() 0 32 3
A setLoggerService() 0 16 4
A symfonyDetect() 0 9 4
A configure() 0 64 2
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\Bundle\FrameworkBundle\Command\ContainerAwareCommand;
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 ContainerAwareCommand
0 ignored issues
show
Deprecated Code introduced by
The class Symfony\Bundle\Framework...d\ContainerAwareCommand has been deprecated: since Symfony 4.2, use {@see Command} instead. ( Ignorable by Annotation )

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

17
class RunCommand extends /** @scrutinizer ignore-deprecated */ ContainerAwareCommand
Loading history...
18
{
19
    protected $loggerPrivate = false;
20
    protected $nanoSleepOption = null;
21
22 1
    protected function symfonyDetect()
23
    {
24 1
        $this->nanoSleepOption = null;
25 1
        if (class_exists('Symfony\Component\HttpKernel\Kernel')) {
26 1
            if (Kernel::VERSION_ID >= 30000) {
27 1
                $this->nanoSleepOption = 's';
28
            }
29 1
            if (Kernel::VERSION_ID >= 30400) {
30 1
                $this->loggerPrivate = true;
31
            }
32
        }
33 1
    }
34
35 1
    protected function configure()
36
    {
37 1
        $this->symfonyDetect();
38
        $options = array(
39 1
            new InputArgument('worker-name', InputArgument::OPTIONAL, 'Name of worker', null),
40 1
            new InputArgument('method', InputArgument::OPTIONAL, 'DI method of worker', null),
41 1
            new InputOption(
42 1
                'id',
43 1
                'i',
44 1
                InputOption::VALUE_REQUIRED,
45 1
                'Id of Job to run',
46 1
                null
47
            ),
48 1
            new InputOption(
49 1
                'max-count',
50 1
                'm',
51 1
                InputOption::VALUE_REQUIRED,
52 1
                'Maximum number of jobs to work on before exiting',
53 1
                null
54
            ),
55 1
            new InputOption(
56 1
                'duration',
57 1
                'd',
58 1
                InputOption::VALUE_REQUIRED,
59 1
                'Duration to run for in seconds',
60 1
                null
61
            ),
62 1
            new InputOption(
63 1
                'timeout',
64 1
                't',
65 1
                InputOption::VALUE_REQUIRED,
66 1
                'Process timeout in seconds (hard exit of process regardless)',
67 1
                3600
68
            ),
69 1
            new InputOption(
70 1
                'nano-sleep',
71 1
                $this->nanoSleepOption,
72 1
                InputOption::VALUE_REQUIRED,
73 1
                'If using duration, this is the time to sleep when there\'s no jobs in nanoseconds',
74 1
                500000000
75
            ),
76 1
            new InputOption(
77 1
                'disable-gc',
78 1
                null,
79 1
                InputOption::VALUE_NONE,
80 1
                'Disable garbage collection'
81
            ),
82
        );
83
84
        // Symfony 4 and Symfony 3.4 out-of-the-box makes the logger private
85 1
        if (!$this->loggerPrivate) {
86
            $options[] =
87
                new InputOption(
88
                    'logger',
89
                    'l',
90
                    InputOption::VALUE_REQUIRED,
91
                    'Log using the logger service specified, or output to console if null (or an invalid logger service id) is passed in'
92
                );
93
        }
94
95
        $this
96 1
            ->setName('dtc:queue:run')
97 1
            ->setDefinition($options)
98 1
            ->setDescription('Start up a job in queue');
99 1
    }
100
101 1
    protected function execute(InputInterface $input, OutputInterface $output)
102
    {
103 1
        $start = microtime(true);
104 1
        $container = $this->getContainer();
105 1
        $loop = $container->get('dtc_queue.run.loop');
106 1
        $loop->setOutput($output);
107 1
        $workerName = $input->getArgument('worker-name');
108 1
        $methodName = $input->getArgument('method');
109 1
        $maxCount = $input->getOption('max-count');
110 1
        $duration = $input->getOption('duration');
111 1
        $processTimeout = $input->getOption('timeout');
112 1
        $nanoSleep = $input->getOption('nano-sleep');
113 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

113
        $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...
114 1
        $disableGc = $input->getOption('disable-gc', false);
115 1
        $this->setGc($disableGc);
116
117 1
        $this->setLoggerService($loop, $loggerService);
118
119 1
        $maxCount = Util::validateIntNull('max_count', $maxCount, 32);
120 1
        $duration = Util::validateIntNull('duration', $duration, 32);
121 1
        $nanoSleep = Util::validateIntNull('nano_sleep', $nanoSleep, 63);
122 1
        $processTimeout = Util::validateIntNull('timeout', $processTimeout, 32);
123 1
        $loop->checkMaxCountDuration($maxCount, $duration, $processTimeout);
124
125
        // Check to see if there are other instances
126 1
        set_time_limit($processTimeout); // Set timeout on the process
127
128 1
        if ($jobId = $input->getOption('id')) {
129
            return $loop->runJobById($start, $jobId); // Run a single job
0 ignored issues
show
Bug introduced by
Are you sure the usage of $loop->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...
130
        }
131
132 1
        return $loop->runLoop($start, $workerName, $methodName, $maxCount, $duration, $nanoSleep);
133
    }
134
135
    /**
136
     * @param bool $disableGc
137
     */
138 1
    protected function setGc($disableGc)
139
    {
140 1
        if ($disableGc) {
141
            if (gc_enabled()) {
142
                gc_disable();
143
            }
144
145
            return;
146
        }
147
148 1
        if (!gc_enabled()) {
149
            gc_enable();
150
        }
151 1
    }
152
153 1
    protected function setLoggerService(Loop $loop, $loggerService)
154
    {
155 1
        if (!$loggerService) {
156 1
            return;
157
        }
158
159
        $container = $this->getContainer();
160
        if (!$container->has($loggerService)) {
161
            return;
162
        }
163
164
        $logger = $container->get($loggerService);
165
        if (!$logger instanceof LoggerInterface) {
166
            throw new ClassNotSubclassException("$loggerService must be instance of Psr\\Log\\LoggerInterface");
167
        }
168
        $loop->setLogger($logger);
169
    }
170
}
171