GitHub Access Token became invalid

It seems like the GitHub access token used for retrieving details about this repository from GitHub became invalid. This might prevent certain types of inspections from being run (in particular, everything related to pull requests).
Please ask an admin of your repository to re-new the access token on this website.
Completed
Pull Request — master (#158)
by Bernardo Vieira da
12:24
created

GearmanExecute::callJob()   C

Complexity

Conditions 10
Paths 160

Size

Total Lines 58

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 18
CRAP Score 17.377

Importance

Changes 0
Metric Value
dl 0
loc 58
ccs 18
cts 31
cp 0.5806
rs 6.6496
c 0
b 0
f 0
cc 10
nc 160
nop 3
crap 17.377

How to fix   Long Method    Complexity   

Long Method

Small methods make your code easier to understand, in particular if combined with a good name. Besides, if your method is small, finding a good name is usually much easier.

For example, if you find yourself adding comments to a method's body, this is usually a good sign to extract the commented part to a new method, and use the comment as a starting point when coming up with a good name for this new method.

Commonly applied refactorings include:

1
<?php
2
3
/**
4
 * Gearman Bundle for Symfony2
5
 *
6
 * For the full copyright and license information, please view the LICENSE
7
 * file that was distributed with this source code.
8
 *
9
 * Feel free to edit as you please, and have fun.
10
 *
11
 * @author Marc Morera <[email protected]>
12
 */
13
14
namespace Mmoreram\GearmanBundle\Service;
15
16
use Symfony\Component\Console\Output\NullOutput;
17
use Symfony\Component\Console\Output\OutputInterface;
18
use Symfony\Component\DependencyInjection\ContainerAwareInterface;
19
use Symfony\Component\DependencyInjection\ContainerInterface;
20
use Symfony\Component\EventDispatcher\EventDispatcherInterface;
21
22
use Mmoreram\GearmanBundle\Command\Util\GearmanOutputAwareInterface;
23
use Mmoreram\GearmanBundle\Event\GearmanWorkExecutedEvent;
24
use Mmoreram\GearmanBundle\Event\GearmanWorkStartingEvent;
25
use Mmoreram\GearmanBundle\GearmanEvents;
26
use Mmoreram\GearmanBundle\Service\Abstracts\AbstractGearmanService;
27
use Mmoreram\GearmanBundle\Exceptions\ServerConnectionException;
28
use Symfony\Component\OptionsResolver\OptionsResolver;
29
30
/**
31
 * Gearman execute methods. All Worker methods
32
 *
33
 * @since 2.3.1
34
 */
35
class GearmanExecute extends AbstractGearmanService
36
{
37
    /**
38
     * @var ContainerInterface
39
     *
40
     * Container instance
41
     */
42
    private $container;
43
44
    /**
45
     * @var EventDispatcherInterface
46
     *
47
     * EventDispatcher instance
48
     */
49
    protected $eventDispatcher;
50
51
    /**
52
     * @var OutputInterface
53
     *
54
     * Output instance
55
     */
56
    protected $output;
57
58
    /**
59
     * @var OptionsResolver
60
     */
61
    protected $executeOptionsResolver;
62
63
    /**
64
     * Boolean to track if a system signal has been received
65
     * @var boolean
66
     */
67
    protected $stopWorkSignalReceived;
68
69
    /**
70
     * Bucket with worker objects configuration for PECL
71
     * @var array
72
     */
73
    protected $workersBucket = [];
74
75
    /**
76
     * Construct method
77
     *
78
     * @param GearmanCacheWrapper $gearmanCacheWrapper GearmanCacheWrapper
79
     * @param array               $defaultSettings     The default settings for the bundle
80
     */
81 2
    public function __construct(GearmanCacheWrapper $gearmanCacheWrapper, array $defaultSettings)
82
    {
83 2
        parent::__construct($gearmanCacheWrapper, $defaultSettings);
84
85 2
        $this->executeOptionsResolver = new OptionsResolver();
86 2
        $this->executeOptionsResolver
87 2
            ->setDefaults(array(
88 2
                'iterations'             => null,
89
                'minimum_execution_time' => null,
90
                'timeout'                => null,
91
            ))
92 2
	    ->setAllowedTypes('iterations', array('null', 'scalar'))
93 2
            ->setAllowedTypes('minimum_execution_time', array('null', 'scalar'))
94 2
            ->setAllowedTypes('timeout', array('null', 'scalar'));
95
        
96
97 2
        $this->stopWorkSignalReceived = false;
98
99
        /**
100
         * If the pcntl_signal exists, subscribe to the terminate and restart events for graceful worker stops.
101
         */
102 2
        if(false !== function_exists('pcntl_signal'))
103
        {
104
            declare(ticks = 1);
105 2
            pcntl_signal(SIGTERM, array($this,"handleSystemSignal"));
106 2
            pcntl_signal(SIGHUP,  array($this,"handleSystemSignal"));
107
108
        }
109 2
    }
110
111
    /**
112
     * Toggles that work should be stopped, we only subscribe to SIGTERM and SIGHUP
113
     * @param int $signno Signal number
0 ignored issues
show
Documentation introduced by
There is no parameter named $signno. Did you maybe mean $signo?

This check looks for PHPDoc comments describing methods or function parameters that do not exist on the corresponding method or function. It has, however, found a similar but not annotated parameter which might be a good fit.

Consider the following example. The parameter $ireland is not defined by the method finale(...).

/**
 * @param array $germany
 * @param array $ireland
 */
function finale($germany, $island) {
    return "2:1";
}

The most likely cause is that the parameter was changed, but the annotation was not.

Loading history...
114
     */
115
    public function handleSystemSignal($signo)
0 ignored issues
show
Unused Code introduced by
The parameter $signo is not used and could be removed.

This check looks from parameters that have been defined for a function or method, but which are not used in the method body.

Loading history...
116
    {
117
        $this->stopWorkSignalReceived = true;
118
    }
119
120
    /**
121
     * Set container
122
     *
123
     * @param ContainerInterface $container Container
124
     *
125
     * @return GearmanExecute self Object
126
     */
127 1
    public function setContainer(ContainerInterface $container)
128
    {
129 1
        $this->container = $container;
130
131 1
        return $this;
132
    }
133
134
    /**
135
     * Set event dispatcher
136
     *
137
     * @param EventDispatcherInterface $eventDispatcher
138
     *
139
     * @return GearmanExecute self Object
140
     */
141 2
    public function setEventDispatcher(EventDispatcherInterface $eventDispatcher)
142
    {
143 2
        $this->eventDispatcher = $eventDispatcher;
144
145 2
        return $this;
146
    }
147
148
    /**
149
     * Set output
150
     *
151
     * @param OutputInterface $output
152
     *
153
     * @return GearmanExecute self Object
154
     */
155 12
    public function setOutput(OutputInterface $output)
156
    {
157 12
        $this->output = $output;
158
159 12
        return $this;
160
    }
161
162
    /**
163
     * Executes a job given a jobName and given settings and annotations of job
164
     *
165
     * @param string $jobName Name of job to be executed
166
     * @param array $options Array of options passed to the callback
167
     * @param \GearmanWorker $gearmanWorker Worker instance to use
168
     */
169 1
    public function executeJob($jobName, array $options = array(), \GearmanWorker $gearmanWorker = null)
170
    {
171 1
        $worker = $this->getJob($jobName);
172
173 1
        if (false !== $worker) {
174 1
            $this->callJob($worker, $options, $gearmanWorker);
175
        }
176 1
    }
177
178
    /**
179
     * Given a worker, execute GearmanWorker function defined by job.
180
     *
181
     * @param array $worker Worker definition
182
     * @param array $options Array of options passed to the callback
183
     * @param \GearmanWorker $gearmanWorker Worker instance to use
184
     *
185
     * @throws ServerConnectionException if a connection to a server was not possible.
186
     *
187
     * @return GearmanExecute self Object
188
     */
189 1
    private function callJob(Array $worker, array $options = array(), \GearmanWorker $gearmanWorker = null)
190
    {
191 1
        if(is_null($gearmanWorker)) {
192
            $gearmanWorker = new \GearmanWorker;
193
        }
194
195 1
        if (isset($worker['job'])) {
196
197 1
            $jobs = array($worker['job']);
198 1
            $iterations = $worker['job']['iterations'];
199 1
            $minimumExecutionTime = $worker['job']['minimumExecutionTime'];
200 1
            $timeout = $worker['job']['timeout'];
201 1
            $successes = $this->addServers($gearmanWorker, $worker['job']['servers']);
202
203
        } else {
204
205
            $jobs = $worker['jobs'];
206
            $iterations = $worker['iterations'];
207
            $minimumExecutionTime = $worker['minimumExecutionTime'];
208
            $timeout = $worker['timeout'];
209
            $successes = $this->addServers($gearmanWorker, $worker['servers']);
210
        }
211
212 1
        $options = $this->executeOptionsResolver->resolve($options);
213
214 1
        $iterations           = $options['iterations']             ?: $iterations;
215 1
        $minimumExecutionTime = $options['minimum_execution_time'] ?: $minimumExecutionTime;
216 1
        $timeout              = $options['timeout']                ?: $timeout;
217
218 1
        if (count($successes) < 1) {
219
            if ($minimumExecutionTime > 0) {
220
                sleep($minimumExecutionTime);
221
            }
222
            throw new ServerConnectionException('Worker was unable to connect to any server.');
223
        }
224
225 1
        $objInstance = $this->createJob($worker);
226
227
        /**
228
         * Start the timer before running the worker.
229
         */
230 1
        $time = time();
231 1
        $this->runJob($gearmanWorker, $objInstance, $jobs, $iterations, $timeout);
232
233
        /**
234
         * If there is a minimum expected duration, wait out the remaining period if there is any.
235
         */
236 1
        if ($minimumExecutionTime > 0) {
237
            $now = time();
238
            $remaining = $minimumExecutionTime - ($now - $time);
239
240
            if ($remaining > 0) {
241
                sleep($remaining);
242
            }
243
        }
244
245 1
        return $this;
246
    }
247
248
    /**
249
     * Given a worker settings, return Job instance
250
     *
251
     * @param array $worker Worker settings
252
     *
253
     * @return Object Job instance
254
     */
255 1
    private function createJob(array $worker)
256
    {
257
        /**
258
         * If service is defined, we must retrieve this class with dependency injection
259
         *
260
         * Otherwise we just create it with a simple new()
261
         */
262 1
        if ($worker['service']) {
263
264
            $objInstance = $this->container->get($worker['service']);
265
266
        } else {
267
268 1
            $objInstance = new $worker['className'];
269
270
            /**
271
             * If instance of given object is instanceof
272
             * ContainerAwareInterface, we inject full container by calling
273
             * container setter.
274
             *
275
             * @see https://github.com/mmoreram/gearman-bundle/pull/12
276
             */
277 1
            if ($objInstance instanceof ContainerAwareInterface) {
278
279
                $objInstance->setContainer($this->container);
280
            }
281
        }
282
283 1
        return $objInstance;
284
    }
285
286
    /**
287
     * Given a GearmanWorker and an instance of Job, run it
288
     *
289
     * @param \GearmanWorker $gearmanWorker Gearman Worker
290
     * @param Object         $objInstance   Job instance
291
     * @param array          $jobs          Array of jobs to subscribe
292
     * @param integer        $iterations    Number of iterations
293
     * @param integer        $timeout       Timeout
294
     *
295
     * @return GearmanExecute self Object
296
     */
297 1
    private function runJob(\GearmanWorker $gearmanWorker, $objInstance, array $jobs, $iterations, $timeout = null)
298
    {
299
        /**
300
         * Set the output of this instance, this should allow workers to use the console output.
301
         */
302 1
        if ($objInstance instanceof GearmanOutputAwareInterface) {
303
            $objInstance->setOutput($this->output ? : new NullOutput());
304
        }
305
306
        /**
307
         * Every job defined in worker is added into GearmanWorker
308
         */
309 1
        foreach ($jobs as $job) {
310
311
            /**
312
             * worker needs to have it's context into separated memory space;
313
             * if it's passed as a value, then garbage collector remove the target
314
             * what causes a segfault
315
             */
316 1
            $this->workersBucket[$job['realCallableName']] = [
317 1
                'job_object_instance' => $objInstance,
318 1
                'job_method' => $job['methodName'],
319 1
                'jobs' => $jobs,
320
            ];
321 1
            $gearmanWorker->addFunction(
322 1
                $job['realCallableName'],
323 1
                array($this, 'handleJob')
324
            );
325
        }
326
327
        /**
328
         * If iterations value is 0, is like worker will never die
329
         */
330 1
        $alive = (0 === $iterations);
331
332 1
        if ($timeout > 0) {
333
            $gearmanWorker->setTimeout($timeout * 1000);
334
        }
335
336
        /**
337
         * Executes GearmanWorker with all jobs defined
338
         */
339 1
        while (false === $this->stopWorkSignalReceived && $gearmanWorker->work()) {
340
341 1
            $iterations--;
342
343 1
            $event = new GearmanWorkExecutedEvent($jobs, $iterations, $gearmanWorker->returnCode());
344 1
            $this->eventDispatcher->dispatch(GearmanEvents::GEARMAN_WORK_EXECUTED, $event);
345
346 1
            if ($gearmanWorker->returnCode() != GEARMAN_SUCCESS) {
347
348
                break;
349
            }
350
351
            /**
352
             * Only finishes its execution if alive is false and iterations
353
             * arrives to 0
354
             */
355 1
            if (!$alive && $iterations <= 0) {
356
357 1
                break;
358
            }
359
        }
360 1
    }
361
362
    /**
363
     * Adds into worker all defined Servers.
364
     * If any is defined, performs default method
365
     *
366
     * @param \GearmanWorker $gmworker Worker to perform configuration
367
     * @param array          $servers  Servers array
368
     *
369
     * @throws ServerConnectionException if a connection to a server was not possible.
370
     *
371
     * @return array         Successfully added servers
372
     */
373 1
    private function addServers(\GearmanWorker $gmworker, array $servers)
374
    {
375 1
        $successes = array();
376
377 1
        if (!empty($servers)) {
378
379
            foreach ($servers as $server) {
380
                if (@$gmworker->addServer($server['host'], $server['port'])) {
381
                    $successes[] = $server;
382
                }
383
            }
384
        } else {
385 1
            if (@$gmworker->addServer()) {
386 1
                $successes[] = array('127.0.0.1', 4730);
387
            }
388
        }
389
390 1
        return $successes;
391
    }
392
393
    /**
394
     * Executes a worker given a workerName subscribing all his jobs inside and
395
     * given settings and annotations of worker and jobs
396
     *
397
     * @param string $workerName Name of worker to be executed
398
     */
399
    public function executeWorker($workerName, array $options = array())
400
    {
401
        $worker = $this->getWorker($workerName);
402
403
        if (false !== $worker) {
404
405
            $this->callJob($worker, $options);
406
        }
407
    }
408
409
    /**
410
     * Wrapper function handler for all registered functions
411
     * This allows us to do some nice logging when jobs are started/finished
412
     *
413
     * @see https://github.com/brianlmoon/GearmanManager/blob/ffc828dac2547aff76cb4962bb3fcc4f454ec8a2/GearmanPeclManager.php#L95-206
414
     *
415
     * @param \GearmanJob $job
416
     * @param mixed $context
0 ignored issues
show
Bug introduced by
There is no parameter named $context. Was it maybe removed?

This check looks for PHPDoc comments describing methods or function parameters that do not exist on the corresponding method or function.

Consider the following example. The parameter $italy is not defined by the method finale(...).

/**
 * @param array $germany
 * @param array $island
 * @param array $italy
 */
function finale($germany, $island) {
    return "2:1";
}

The most likely cause is that the parameter was removed, but the annotation was not.

Loading history...
417
     *
418
     * @return mixed
419
     */
420 1
    public function handleJob(\GearmanJob $job)
421
    {
422 1
        if (!isset($this->workersBucket[$job->functionName()])) {
423
            $context = false;
424
        } else {
425 1
            $context = $this->workersBucket[$job->functionName()];
426
        }
427
428
        if (
429 1
            !is_array($context)
430 1
            || !array_key_exists('job_object_instance', $context)
431 1
            || !array_key_exists('job_method', $context)
432
        ) {
433
            throw new \InvalidArgumentException('$context shall be an array with job_object_instance and job_method key.');
434
        }
435
436 1
        $event = new GearmanWorkStartingEvent($context['jobs']);
437 1
        $this->eventDispatcher->dispatch(GearmanEvents::GEARMAN_WORK_STARTING, $event);
438
439 1
        $result = call_user_func_array(
440 1
            array($context['job_object_instance'], $context['job_method']),
441 1
            array($job, $context)
442
        );
443
444
        /**
445
         * Workaround for PECL bug #17114
446
         * http://pecl.php.net/bugs/bug.php?id=17114
447
         */
448 1
        $type = gettype($result);
449 1
        settype($result, $type);
450
451 1
        return $result;
452
    }
453
}
454