Completed
Push — master ( 692985...e555b8 )
by Matthew
18:05
created

RunCommand::setRunLoop()   A

Complexity

Conditions 1
Paths 1

Size

Total Lines 2
Code Lines 1

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 2
CRAP Score 1

Importance

Changes 0
Metric Value
cc 1
eloc 1
nc 1
nop 1
dl 0
loc 2
ccs 2
cts 2
cp 1
crap 1
rs 10
c 0
b 0
f 0
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 1
    /** @var Loop */
23
    private $runLoop;
24 1
25 1
    protected function symfonyDetect()
26 1
    {
27 1
        $this->nanoSleepOption = null;
28
        if (class_exists('Symfony\Component\HttpKernel\Kernel')) {
29 1
            if (Kernel::VERSION_ID >= 30000) {
30 1
                $this->nanoSleepOption = 's';
31
            }
32
            if (Kernel::VERSION_ID >= 30400) {
33 1
                $this->loggerPrivate = true;
34
            }
35 1
        }
36
    }
37 1
38
    protected function configure()
39 1
    {
40 1
        $this->symfonyDetect();
41 1
        $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
                InputOption::VALUE_REQUIRED,
48 1
                'Id of Job to run',
49 1
                null
50 1
            ),
51 1
            new InputOption(
52 1
                'max-count',
53 1
                'm',
54
                InputOption::VALUE_REQUIRED,
55 1
                'Maximum number of jobs to work on before exiting',
56 1
                null
57 1
            ),
58 1
            new InputOption(
59 1
                'duration',
60 1
                'd',
61
                InputOption::VALUE_REQUIRED,
62 1
                'Duration to run for in seconds',
63 1
                null
64 1
            ),
65 1
            new InputOption(
66 1
                'timeout',
67 1
                't',
68
                InputOption::VALUE_REQUIRED,
69 1
                'Process timeout in seconds (hard exit of process regardless)',
70 1
                3600
71 1
            ),
72 1
            new InputOption(
73 1
                'nano-sleep',
74 1
                $this->nanoSleepOption,
75
                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 1
            ),
79 1
            new InputOption(
80 1
                'disable-gc',
81
                null,
82
                InputOption::VALUE_NONE,
83
                'Disable garbage collection'
84
            ),
85 1
        );
86
87
        // Symfony 4 and Symfony 3.4 out-of-the-box makes the logger private
88
        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 1
        }
97 1
98 1
        $this
99 1
            ->setName('dtc:queue:run')
100
            ->setDefinition($options)
101 1
            ->setDescription('Start up a job in queue');
102
    }
103 1
104 1
    public function setRunLoop($runLoop) {
105 1
        $this->runLoop = $runLoop;
106 1
    }
107 1
108 1
    protected function execute(InputInterface $input, OutputInterface $output)
109 1
    {
110 1
        $start = microtime(true);
111 1
        // @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
        $duration = $input->getOption('duration');
117 1
        $processTimeout = $input->getOption('timeout');
118
        $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 1
123 1
        $this->setLoggerService($this->runLoop, $loggerService);
124
125
        $maxCount = Util::validateIntNull('max_count', $maxCount, 32);
126 1
        $duration = Util::validateIntNull('duration', $duration, 32);
127
        $nanoSleep = Util::validateIntNull('nano_sleep', $nanoSleep, 63);
128 1
        $processTimeout = Util::validateIntNull('timeout', $processTimeout, 32);
129
        $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
        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 1
141
    /**
142
     * @param bool $disableGc
143
     */
144
    protected function setGc($disableGc)
145
    {
146
        if ($disableGc) {
147
            if (gc_enabled()) {
148 1
                gc_disable();
149
            }
150
151 1
            return;
152
        }
153 1
154
        if (!gc_enabled()) {
155 1
            gc_enable();
156 1
        }
157
    }
158
159
    protected function setLoggerService(Loop $loop, $loggerService)
160
    {
161
        if (!$loggerService) {
162
            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