Manejo de trabajos en cli por php en vez de cron
This commit is contained in:
@ -1,4 +1,4 @@
|
||||
FROM php:8.2-cli
|
||||
FROM php:8.4-cli
|
||||
|
||||
ENV TZ "${TZ}"
|
||||
ENV APP_NAME "${APP_NAME}"
|
||||
@ -6,9 +6,10 @@ ENV API_URL "${API_URL}"
|
||||
|
||||
RUN apt-get update && apt-get install -y --no-install-recommends cron rsyslog nano && rm -r /var/lib/apt/lists/*
|
||||
|
||||
RUN pecl install xdebug-3.2.2 \
|
||||
&& docker-php-ext-enable xdebug \
|
||||
&& echo "#/bin/bash\nprintenv >> /etc/environment\ncron -f -L 11" > /root/entrypoint && chmod a+x /root/entrypoint
|
||||
RUN pecl install xdebug-3.4.2 \
|
||||
&& docker-php-ext-enable xdebug
|
||||
|
||||
COPY --chmod=550 ./cli/entrypoint /root/entrypoint
|
||||
|
||||
COPY ./php-errors.ini /usr/local/etc/php/conf.d/docker-php-errors.ini
|
||||
|
||||
|
@ -2,6 +2,7 @@
|
||||
"name": "incoviba/cli",
|
||||
"type": "project",
|
||||
"require": {
|
||||
"dragonmantank/cron-expression": "^3.4",
|
||||
"guzzlehttp/guzzle": "^7.8",
|
||||
"monolog/monolog": "^3.5",
|
||||
"php-di/php-di": "^7.0",
|
||||
|
@ -7,3 +7,4 @@
|
||||
0 2 * * * /code/bin/incoviba money:uf >> /logs/commands 2>&1
|
||||
0 2 * * * /code/bin/incoviba money:uf:update >> /logs/commands 2>&1
|
||||
0 2 1 * * /code/bin/incoviba money:ipc >> /logs/commands 2>&1
|
||||
*/5 * * * * /code/bin/incoviba queue >> /logs/commands 2>&1
|
||||
|
6
cli/entrypoint
Normal file
6
cli/entrypoint
Normal file
@ -0,0 +1,6 @@
|
||||
#/usr/bin/bash
|
||||
|
||||
printenv >> /etc/environment
|
||||
|
||||
#cron -f -L 11
|
||||
/code/bin/incoviba loop
|
2
cli/resources/commands/loop.php
Normal file
2
cli/resources/commands/loop.php
Normal file
@ -0,0 +1,2 @@
|
||||
<?php
|
||||
$app->add($app->getContainer()->get(Incoviba\Command\BaseLoop::class));
|
2
cli/resources/commands/queue.php
Normal file
2
cli/resources/commands/queue.php
Normal file
@ -0,0 +1,2 @@
|
||||
<?php
|
||||
$app->add($app->getContainer()->get(Incoviba\Command\Queue::class));
|
@ -13,6 +13,8 @@ return [
|
||||
'ventas:cuotas:hoy' => Incoviba\Command\Ventas\Cuotas\Hoy::class,
|
||||
'ventas:cuotas:pendientes' => Incoviba\Command\Ventas\Cuotas\Pendientes::class,
|
||||
'ventas:cuotas:vencer' => Incoviba\Command\Ventas\Cuotas\PorVencer::class,
|
||||
'queue' => Incoviba\Command\Queue::class,
|
||||
'loop' => Incoviba\Command\BaseLoop::class
|
||||
];
|
||||
}
|
||||
];
|
||||
|
63
cli/src/Command/BaseLoop.php
Normal file
63
cli/src/Command/BaseLoop.php
Normal file
@ -0,0 +1,63 @@
|
||||
<?php
|
||||
namespace Incoviba\Command;
|
||||
|
||||
use Throwable;
|
||||
use DateTimeInterface;
|
||||
use DateTimeImmutable;
|
||||
use Psr\Log\LoggerInterface;
|
||||
use Symfony\Component\Console;
|
||||
use Incoviba\Service\Schedule;
|
||||
|
||||
#[Console\Attribute\AsCommand(
|
||||
name: 'loop',
|
||||
description: 'Run base loop',
|
||||
)]
|
||||
class BaseLoop extends Console\Command\Command
|
||||
{
|
||||
public function __construct(protected LoggerInterface $logger, protected Schedule $scheduleService, ?string $name = null)
|
||||
{
|
||||
parent::__construct($name);
|
||||
}
|
||||
|
||||
public function execute(Console\Input\InputInterface $input, Console\Output\OutputInterface $output): int
|
||||
{
|
||||
$output->writeln("Running Loop...");
|
||||
|
||||
// wait for next minute
|
||||
$now = new DateTimeImmutable();
|
||||
$nextMinute = new DateTimeImmutable($now->format('Y-m-d H:i:00'));
|
||||
$nextMinute->add(new \DateInterval('PT1M'));
|
||||
$diff = $nextMinute->getTimestamp() - $now->getTimestamp();
|
||||
if ($diff > 0) {
|
||||
$output->writeln("Waiting {$diff} seconds...");
|
||||
sleep($diff);
|
||||
}
|
||||
|
||||
$output->writeln('Starting loop...');
|
||||
while (true) {
|
||||
$commands = $this->scheduleService->run();
|
||||
foreach ($commands as $command) {
|
||||
$this->runCommand($input, $output, $command);
|
||||
}
|
||||
}
|
||||
return self::SUCCESS;
|
||||
}
|
||||
protected function runCommand(Console\Input\InputInterface $input, Console\Output\OutputInterface $output, string $commandName): int
|
||||
{
|
||||
try {
|
||||
$command = $this->getApplication()->find($commandName);
|
||||
} catch (Console\Exception\CommandNotFoundException $exception) {
|
||||
$this->logger->warning($exception);
|
||||
}
|
||||
|
||||
$cmd = new Console\Input\ArrayInput([
|
||||
'command' => $commandName
|
||||
]);
|
||||
try {
|
||||
return $this->getApplication()->doRun($cmd, $output);
|
||||
} catch (Throwable $exception) {
|
||||
$this->logger->warning($exception);
|
||||
return self::FAILURE;
|
||||
}
|
||||
}
|
||||
}
|
26
cli/src/Command/Queue.php
Normal file
26
cli/src/Command/Queue.php
Normal file
@ -0,0 +1,26 @@
|
||||
<?php
|
||||
namespace Incoviba\Command;
|
||||
|
||||
use Symfony\Component\Console;
|
||||
use Incoviba\Common\Alias\Command;
|
||||
|
||||
#[Console\Attribute\AsCommand(
|
||||
name: 'queue',
|
||||
description: 'Run queue'
|
||||
)]
|
||||
class Queue extends Command
|
||||
{
|
||||
public function execute(Console\Input\InputInterface $input, Console\Output\OutputInterface $output): int
|
||||
{
|
||||
$this->logger->debug("Running {$this->getName()}");
|
||||
$io = new Console\Style\SymfonyStyle($input, $output);
|
||||
$io->title("Running Queue...");
|
||||
|
||||
$uri = '/api/queue/run';
|
||||
$output->writeln("GET {$uri}");
|
||||
$response = $this->client->get($uri);
|
||||
$output->writeln("Response Code: {$response->getStatusCode()}");
|
||||
|
||||
return Console\Command\Command::SUCCESS;
|
||||
}
|
||||
}
|
60
cli/src/Service/Schedule.php
Normal file
60
cli/src/Service/Schedule.php
Normal file
@ -0,0 +1,60 @@
|
||||
<?php
|
||||
namespace Incoviba\Service;
|
||||
|
||||
use Cron\CronExpression;
|
||||
use DateTimeInterface;
|
||||
use DateTimeImmutable;
|
||||
use Psr\Log\LoggerInterface;
|
||||
|
||||
class Schedule
|
||||
{
|
||||
public function __construct(protected LoggerInterface $logger) {}
|
||||
|
||||
protected string $filename = '/var/spool/cron/crontabs/root';
|
||||
|
||||
public function run(): array
|
||||
{
|
||||
$now = new DateTimeImmutable();
|
||||
$schedule = $this->getCommandList();
|
||||
$commands = [];
|
||||
foreach ($schedule as $line) {
|
||||
$line = trim($line);
|
||||
if ($line === '') {
|
||||
continue;
|
||||
}
|
||||
$data = $this->parseCommandLine($line);
|
||||
if ($this->processSchedule($now, $data)) {
|
||||
$commands[] = $data['command'];
|
||||
}
|
||||
}
|
||||
return $commands;
|
||||
}
|
||||
|
||||
protected function getCommandList(): array
|
||||
{
|
||||
if (!file_exists($this->filename)) {
|
||||
return [];
|
||||
}
|
||||
return explode("\n", file_get_contents($this->filename));
|
||||
}
|
||||
protected function parseCommandLine(string $line): array
|
||||
{
|
||||
$regex = '/^(?<minutes>(\d{1,2}|\*|\*\/\d{1,2})?) (?<hours>(\d{1,2}|\*|\*\/\d{1,2})?) (?<day_month>(\d{1,2}|\*|\*\/\d{1,2})?) (?<month>(\d{1,2}|\*|\*\/\d{1,2})?) (?<day_week>(\d{1,2}|\*|\*\/\d{1,2})?) (?<command>.*)$/';
|
||||
preg_match_all($regex, $line, $matches);
|
||||
|
||||
return [
|
||||
'minutes' => $matches['minutes'][0],
|
||||
'hours' => $matches['hours'][0],
|
||||
'day_month' => $matches['day_month'][0],
|
||||
'month' => $matches['month'][0],
|
||||
'day_week' => $matches['day_week'][0],
|
||||
'command' => trim(str_replace(['/code/bin/incoviba', '>> /logs/commands 2>&1'], '', $matches['command'][0])),
|
||||
];
|
||||
}
|
||||
protected function processSchedule(DateTimeInterface $now, array $schedule): bool
|
||||
{
|
||||
$cronLine = "{$schedule['minutes']} {$schedule['hours']} {$schedule['day_month']} {$schedule['month']} {$schedule['day_week']}";
|
||||
$cron = new CronExpression($cronLine);
|
||||
return $cron->isDue($now);
|
||||
}
|
||||
}
|
@ -84,6 +84,7 @@ services:
|
||||
volumes:
|
||||
- ${CLI_PATH:-.}:/code
|
||||
- ./logs/cli:/logs
|
||||
- ${CLI_PATH:-.}/crontab:/var/spool/cron/crontabs/root
|
||||
|
||||
volumes:
|
||||
dbdata: {}
|
||||
|
Reference in New Issue
Block a user