Manejo de trabajos en cli por php en vez de cron

This commit is contained in:
Juan Pablo Vial
2025-05-10 12:40:06 -04:00
parent 4ca1616dfc
commit 4d5b657b92
11 changed files with 169 additions and 4 deletions

View File

@ -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

View File

@ -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",

View File

@ -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
View File

@ -0,0 +1,6 @@
#/usr/bin/bash
printenv >> /etc/environment
#cron -f -L 11
/code/bin/incoviba loop

View File

@ -0,0 +1,2 @@
<?php
$app->add($app->getContainer()->get(Incoviba\Command\BaseLoop::class));

View File

@ -0,0 +1,2 @@
<?php
$app->add($app->getContainer()->get(Incoviba\Command\Queue::class));

View File

@ -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
];
}
];

View 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
View 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;
}
}

View 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);
}
}

View File

@ -84,6 +84,7 @@ services:
volumes:
- ${CLI_PATH:-.}:/code
- ./logs/cli:/logs
- ${CLI_PATH:-.}/crontab:/var/spool/cron/crontabs/root
volumes:
dbdata: {}