Completed
Pull Request — master (#27)
by Matthew
16:48
created

RunCommand::setGc()   A

Complexity

Conditions 4
Paths 4

Size

Total Lines 12
Code Lines 6

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 0
CRAP Score 20

Importance

Changes 0
Metric Value
dl 0
loc 12
rs 9.2
c 0
b 0
f 0
ccs 0
cts 0
cp 0
cc 4
eloc 6
nc 4
nop 1
crap 20
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
18
{
19 1
    protected $loggerPrivate = false;
20
    protected $nanoSleepOption = null;
21 1
22 1
    protected function symfonyDetect()
23 1
    {
24 1
        $this->nanoSleepOption = null;
25
        if (class_exists('Symfony\Component\HttpKernel\Kernel')) {
26 1
            if (Kernel::VERSION_ID >= 30000) {
27 1
                $this->nanoSleepOption = 's';
28 1
            }
29
            if (Kernel::VERSION_ID >= 30400) {
30 1
                $this->loggerPrivate = true;
31 1
            }
32 1
        }
33 1
    }
34 1
35 1
    protected function configure()
36 1
    {
37
        $this->symfonyDetect();
38 1
        $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
                InputOption::VALUE_REQUIRED,
45 1
                'Id of Job to run',
46 1
                null
47 1
            ),
48 1
            new InputOption(
49 1
                'max-count',
50 1
                'm',
51
                InputOption::VALUE_REQUIRED,
52 1
                'Maximum number of jobs to work on before exiting',
53 1
                null
54 1
            ),
55 1
            new InputOption(
56 1
                'duration',
57 1
                'd',
58
                InputOption::VALUE_REQUIRED,
59 1
                'Duration to run for in seconds',
60 1
                null
61 1
            ),
62 1
            new InputOption(
63 1
                'timeout',
64 1
                't',
65
                InputOption::VALUE_REQUIRED,
66 1
                'Process timeout in seconds (hard exit of process regardless)',
67 1
                3600
68 1
            ),
69 1
            new InputOption(
70 1
                'nano-sleep',
71
                $this->nanoSleepOption,
72 1
                InputOption::VALUE_REQUIRED,
73
                'If using duration, this is the time to sleep when there\'s no jobs in nanoseconds',
74 1
                500000000
75 1
            ),
76 1
            new InputOption(
77
                'disable-gc',
78 1
                null,
79
                InputOption::VALUE_NONE,
80 1
                'Disable garbage collection'
81 1
            ),
82 1
        );
83 1
84 1
        // Symfony 4 and Symfony 3.4 out-of-the-box makes the logger private
85 1
        if (!$this->loggerPrivate) {
86 1
            $options[] =
87 1
                new InputOption(
88 1
                    'logger',
89 1
                    'l',
90 1
                    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 1
                );
93
        }
94 1
95 1
        $this
96 1
            ->setName('dtc:queue:run')
97 1
            ->setDefinition($options)
98 1
            ->setDescription('Start up a job in queue');
99
    }
100
101 1
    protected function execute(InputInterface $input, OutputInterface $output)
102
    {
103 1
        $start = microtime(true);
104
        $container = $this->getContainer();
105
        $loop = $container->get('dtc_queue.run.loop');
106
        $loop->setOutput($output);
107 1
        $workerName = $input->getArgument('worker-name');
108
        $methodName = $input->getArgument('method');
109
        $maxCount = $input->getOption('max-count');
110 1
        $duration = $input->getOption('duration');
111
        $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
        $disableGc = $input->getOption('disable-gc', false);
115
        $this->setGc($disableGc);
116
117
        $this->setLoggerService($loop, $loggerService);
118
119
        $maxCount = Util::validateIntNull('max_count', $maxCount, 32);
120
        $duration = Util::validateIntNull('duration', $duration, 32);
121
        $nanoSleep = Util::validateIntNull('nano_sleep', $nanoSleep, 63);
122
        $processTimeout = Util::validateIntNull('timeout', $processTimeout, 32);
123
        $loop->checkMaxCountDuration($maxCount, $duration, $processTimeout);
124
125
        // Check to see if there are other instances
126
        set_time_limit($processTimeout); // Set timeout on the process
127
128
        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
        return $loop->runLoop($start, $workerName, $methodName, $maxCount, $duration, $nanoSleep);
133
    }
134
135
    /**
136
     * @param bool $disableGc
137
     */
138
    protected function setGc($disableGc)
139
    {
140
        if ($disableGc) {
141
            if (gc_enabled()) {
142
                gc_disable();
143
            }
144
145
            return;
146
        }
147
148
        if (!gc_enabled()) {
149
            gc_enable();
150
        }
151
    }
152
153
    protected function setLoggerService(Loop $loop, $loggerService)
154
    {
155
        if (!$loggerService) {
156
            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