webcron/src/Command/DaemonCommand.php

107 lines
4.3 KiB
PHP
Raw Normal View History

2021-05-24 18:36:16 +02:00
<?php
2022-04-27 14:24:48 +02:00
namespace App\Command;
2021-05-24 18:36:16 +02:00
2022-04-27 14:24:48 +02:00
use App\Entity\Job;
use App\Repository\JobRepository;
use Doctrine\Persistence\ManagerRegistry;
2022-10-04 12:17:28 +02:00
use Symfony\Component\Console\Attribute\AsCommand;
2021-05-24 18:36:16 +02:00
use Symfony\Component\Console\Command\Command;
use Symfony\Component\Console\Input\InputInterface;
use Symfony\Component\Console\Input\InputOption;
use Symfony\Component\Console\Output\OutputInterface;
2022-04-27 14:24:48 +02:00
use Symfony\Component\HttpKernel\KernelInterface;
2021-05-24 18:36:16 +02:00
2022-10-04 12:17:28 +02:00
#[AsCommand(name: 'webcron:daemon', description: 'The master script of Webcron Management')]
2021-05-24 18:36:16 +02:00
class DaemonCommand extends Command
{
protected $kernel;
2022-04-27 14:24:48 +02:00
protected $doctrine;
2021-05-24 18:36:16 +02:00
2022-04-28 16:25:34 +02:00
public function __construct(KernelInterface $kernel, ManagerRegistry $doctrine)
2021-05-24 18:36:16 +02:00
{
$this->kernel = $kernel;
2022-04-27 14:24:48 +02:00
$this->doctrine = $doctrine;
2021-05-24 18:36:16 +02:00
parent::__construct();
}
protected function configure()
{
$this
->setHelp('This command is the daemon process of webcron, enabling webcron to actually run jobs on time')
2022-05-17 16:06:46 +02:00
->addOption('time-limit', 't', InputOption::VALUE_REQUIRED, 'Time limit in seconds before stopping the daemon.')
->addOption('async', 'a', InputOption::VALUE_NEGATABLE, 'Time limit in seconds before stopping the daemon.');
2021-05-24 18:36:16 +02:00
}
2022-10-04 13:29:27 +02:00
protected function execute(InputInterface $input, OutputInterface $output) : int
2021-05-24 18:36:16 +02:00
{
ini_set('memory_limit', '4G');
2022-04-27 14:24:48 +02:00
$jobRepo = $this->doctrine->getRepository(Job::class);
2021-05-24 18:36:16 +02:00
$timelimit = $input->getOption('time-limit') ?? false;
2022-05-17 16:06:46 +02:00
$async = $input->getOption('async') ?? function_exists('pcntl_fork');
2021-05-24 18:36:16 +02:00
if ($timelimit === false) {
$endofscript = false;
} elseif(is_numeric($timelimit)) {
$endofscript = time() + $timelimit;
} else {
throw new \InvalidArgumentException('Time limit has incorrect value');
}
2021-05-29 14:20:05 +02:00
$jobRepo->unlockJob();
file_put_contents($this->kernel->getCacheDir() . '/daemon-running.lock', time());
2021-05-24 18:36:16 +02:00
while(1) {
if($endofscript !== false && time() > $endofscript) break;
2021-10-22 12:16:21 +02:00
2021-05-24 18:36:16 +02:00
$jobsToRun = $jobRepo->getJobsDue();
if(!empty($jobsToRun)) {
foreach($jobsToRun as $key=>$job) {
if ($job->getData('crontype') == 'reboot') {
$str = @file_get_contents('/proc/uptime');
$num = floatval($str);
2022-05-17 16:06:46 +02:00
$rebootedself = ($num < $job->getData('reboot-duration') * 60);
$consolerun = $jobRepo->getTempVar($job, 'consolerun', false);
if ($consolerun && !$rebootedself) continue;
}
$manual = '';
if($jobRepo->getTempVar($job, 'webhook', false)) {
$manual = 'Webhook';
} elseif($job->getRunning() > 1) {
$manual = 'Manual';
};
$jobRepo->setJobRunning($job, true);
2022-05-17 16:06:46 +02:00
$output->writeln('Running Job ' . $job->getId());
if($async) {
declare(ticks = 1);
pcntl_signal(SIGCHLD, SIG_IGN);
$pid = pcntl_fork();
$this->doctrine->getConnection()->close();
$jobRepo = $this->doctrine->getRepository(Job::class);
}
if((!$async || $pid == -1) || $pid == 0) {
$result = $jobRepo->RunJob($job, $manual);
if ($result['status'] == 'ran') $jobRepo->setJobRunning($job, false);
if ($pid == 0) exit;
2021-05-24 18:36:16 +02:00
}
unset($jobsToRun[$key]);
unset($job);
2021-05-24 18:36:16 +02:00
}
}
2022-05-20 19:34:45 +02:00
$this->doctrine->getManager()->clear();
file_put_contents($this->kernel->getCacheDir() . '/daemon-running.lock', time());
2022-08-23 16:40:12 +02:00
$maxwait = time() + 30;
$nextrun = max($jobRepo->getTimeOfNextRun(), time() + 1);
2022-08-23 16:40:12 +02:00
$sleepuntil = min($maxwait, $nextrun);
if($sleepuntil > time()) time_sleep_until($sleepuntil);
gc_collect_cycles();
2021-05-24 18:36:16 +02:00
}
$output->writeln('Ended after ' . $timelimit . ' seconds');
pcntl_wait($status);
2022-02-04 14:21:42 +01:00
unlink($this->kernel->getCacheDir() . '/daemon-running.lock');
2021-05-24 18:36:16 +02:00
return Command::SUCCESS;
}
2021-05-26 01:22:36 +02:00
}