CronRunCommand::runJob()   B
last analyzed

Complexity

Conditions 8
Paths 17

Size

Total Lines 56
Code Lines 36

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
dl 0
loc 56
c 0
b 0
f 0
rs 7.3333
cc 8
eloc 36
nc 17
nop 2

How to fix   Long Method   

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
namespace Alpixel\Bundle\CronBundle\Command;
4
5
use Alpixel\Bundle\CronBundle\Entity\CronJob;
6
use Alpixel\Bundle\CronBundle\Entity\CronJobResult;
7
use Symfony\Bundle\FrameworkBundle\Command\ContainerAwareCommand;
8
use Symfony\Component\Console\Input\ArgvInput;
9
use Symfony\Component\Console\Input\InputArgument;
10
use Symfony\Component\Console\Input\InputInterface;
11
use Symfony\Component\Console\Output\OutputInterface;
12
13
class CronRunCommand extends ContainerAwareCommand
14
{
15
    protected function configure()
16
    {
17
        $this->setName('cron:run')
18
             ->setDescription('Runs any currently schedule cron jobs')
19
             ->addArgument('job', InputArgument::OPTIONAL, 'Run only this job (if enabled)');
20
    }
21
22
    protected function execute(InputInterface $input, OutputInterface $output)
23
    {
24
        $start = microtime(true);
25
        $entityManager = $this->getContainer()->get('doctrine.orm.entity_manager');
26
        $jobRepo = $entityManager->getRepository('CronBundle:CronJob');
27
28
        $jobsToRun = [];
29
        if ($jobName = $input->getArgument('job')) {
30
            try {
31
                $jobObj = $jobRepo->findOneByCommand($jobName);
32
                if ($jobObj->getEnabled()) {
33
                    $jobsToRun = [$jobObj];
34
                }
35
            } catch (\Exception $e) {
36
                $output->writeln("Couldn't find a job by the name of $jobName");
37
38
                return CronJobResult::FAILED;
39
            }
40
        } else {
41
            $jobsToRun = $jobRepo->findDueTasks();
42
        }
43
44
        $jobCount = count($jobsToRun);
45
        $output->writeln("Running $jobCount jobs:");
46
47
        foreach ($jobsToRun as $job) {
48
            $this->runJob($job, $output);
49
        }
50
51
        $entityManager->flush();
52
53
        $end = microtime(true);
54
        $duration = sprintf('%0.2f', $end - $start);
55
        $output->writeln("Cron run completed in $duration seconds");
56
    }
57
58
    protected function runJob(CronJob $job, OutputInterface $output)
59
    {
60
        $entityManager = $this->getContainer()->get('doctrine.orm.entity_manager');
61
        $output->write('Running '.$job->getCommand().': ');
62
63
        try {
64
            $commandToRun = $this->getApplication()->get($job->getCommand());
65
        } catch (\Symfony\Component\Console\Exception\InvalidArgumentException $ex) {
66
            $output->writeln(' skipped (command no longer exists)');
67
            $this->recordJobResult($entityManager, $job, 0, 'Command no longer exists', CronJobResult::SKIPPED);
0 ignored issues
show
Unused Code introduced by
The call to CronRunCommand::recordJobResult() has too many arguments starting with \Alpixel\Bundle\CronBund...\CronJobResult::SKIPPED.

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.

In this case you can add the @ignore PhpDoc annotation to the duplicate definition and it will be ignored.

Loading history...
68
69
            // No need to reschedule non-existant commands
70
            return;
71
        }
72
73
        $emptyInput = new ArgvInput();
74
        $jobOutput = new MemoryWriter();
75
76
        $jobStart = microtime(true);
77
        try {
78
            $returnCode = $commandToRun->execute($emptyInput, $jobOutput);
79
        } catch (\Exception $ex) {
80
            $returnCode = CronJobResult::FAILED;
81
            $jobOutput->writeln('');
82
            $jobOutput->writeln('Job execution failed with exception '.get_class($ex).':');
83
            $jobOutput->writeln($ex->__toString());
84
        }
85
        $jobEnd = microtime(true);
86
87
        // Clamp the result to accepted values
88
        if ($returnCode < CronJobResult::RESULT_MIN || $returnCode > CronJobResult::RESULT_MAX) {
89
            $returnCode = CronJobResult::FAILED;
90
        }
91
92
        // Output the result
93
        $statusStr = 'unknown';
94
        if ($returnCode == CronJobResult::SKIPPED) {
95
            $statusStr = 'skipped';
96
        } elseif ($returnCode == CronJobResult::SUCCEEDED) {
97
            $statusStr = 'succeeded';
98
        } elseif ($returnCode == CronJobResult::FAILED) {
99
            $statusStr = 'failed';
100
        }
101
102
        $durationStr = sprintf('%0.2f', $jobEnd - $jobStart);
103
        $output->writeln("$statusStr in $durationStr seconds");
104
105
        // Record the result
106
        $this->recordJobResult($job, $jobEnd - $jobStart, $jobOutput->getOutput(), $returnCode);
107
108
        // And update the job with it's next scheduled time
109
        $interval = new \DateInterval($job->getInterval());
110
        $newTime = clone $job->getNextRun();
111
        $newTime->add($interval);
112
        $job->setNextRun($newTime);
113
    }
114
115
    protected function recordJobResult(CronJob $job, $timeTaken, $output, $resultCode)
116
    {
117
        $entityManager = $this->getContainer()->get('doctrine.orm.entity_manager');
118
119
        // Create a new CronJobResult
120
        $result = new CronJobResult();
121
        $result->setJob($job);
122
        $result->setRunTime($timeTaken);
123
        $result->setOutput($output);
124
        $result->setResult($resultCode);
125
126
        // Then update associations and persist it
127
        $job->setMostRecentRun($result);
128
        $entityManager->persist($result);
129
    }
130
}
131