Beanstalkd for jobs

This commit is contained in:
Juan Pablo Vial
2025-07-14 14:29:41 -04:00
parent e6e7470bb2
commit 501151a90e
26 changed files with 693 additions and 390 deletions

View File

@ -6,8 +6,13 @@ then
then
CMD=$1
shift
$CMD -c "$@"
exit
if [[ $# -gt 0 ]]
then
$CMD -c "$@"
exit 0
fi
$CMD
exit 0
fi
fi

View File

@ -9,7 +9,7 @@ use Incoviba\Service;
use Psr\Log\LoggerInterface;
use Symfony\Component\Console;
#[Console\Attribute\AsCommand(name: 'jobs:run', description: 'Run jobs')]
#[Console\Attribute\AsCommand(name: 'jobs:run', description: 'Run job')]
class Run extends Console\Command\Command
{
public function __construct(protected Service\FastCGI $fastcgi, protected LoggerInterface $logger,
@ -18,13 +18,6 @@ class Run extends Console\Command\Command
parent::__construct($name);
}
protected function configure(): void
{
$this->addArgument('job_ids',
Console\Input\InputArgument::IS_ARRAY | Console\Input\InputArgument::REQUIRED, 'Job IDs');
}
protected array $output = [];
public function execute(Console\Input\InputInterface $input, Console\Output\OutputInterface $output): int
{
try {
@ -33,44 +26,13 @@ class Run extends Console\Command\Command
$now = new DateTimeImmutable();
}
$jobIds = $input->getArgument('job_ids');
$jobCount = count($jobIds);
$this->pushOutput('top', ['message' => "[{$now->format('Y-m-d H:i:s e')}] Running {$jobCount} jobs..."]);
$this->pushOutput('bottom', ['table' => [
['Job IDs'],
array_map(function($row) {return [$row];},$jobIds)
]]);
$this->pushOutput('top', ['progress' => $jobCount]);
$result = $this->runJobs($jobIds);
$this->pushOutput('top', ['progress' => 'finish']);
$this->writeOutput($input, $output);
return $result;
$output->writeln("[{$now->format('Y-m-d H:i:s e')}] Running Ready Job...");
$this->runJob();
return $this->getResponses();
}
protected function runJobs(array $jobIds): int
protected function runJob(): bool
{
$pendingJobs = [];
foreach ($jobIds as $jobId) {
if (!$this->runJob($jobId)) {
$pendingJobs []= $jobId;
}
}
$result = $this->getResponses();
if (count($pendingJobs) > 0) {
if ($this->runJobs($pendingJobs) === self::FAILURE) {
$result = self::FAILURE;
}
}
return $result;
}
protected function runJob(int $jobId): bool
{
$uri = "/api/queue/run/{$jobId}";
$this->pushOutput('bottom', ['message' => "GET {$uri}"]);
$uri = "/api/queue/run";
try {
$this->fastcgi->get($uri);
@ -85,7 +47,6 @@ class Run extends Console\Command\Command
$result = self::SUCCESS;
$responses = $this->fastcgi->awaitResponses();
foreach ($responses as $response) {
$this->pushOutput('top', ['progress' => 'advance']);
if ($response->getError() !== '') {
$this->logger->error("Error running job", [
'error' => $response->getError(),
@ -93,100 +54,8 @@ class Run extends Console\Command\Command
'headers' => $response->getHeaders(),
]);
$result = self::FAILURE;
continue;
}
$this->pushOutput('bottom', ['message' => $response->getBody()]);
}
return $result;
}
protected function pushOutput(string $section, array $configuration): void
{
if (!isset($this->output[$section])) {
$this->output[$section] = [];
}
foreach ($configuration as $key => $value) {
if (!isset($this->output[$section][$key])) {
$this->output[$section][$key] = [];
}
$this->output[$section][$key] []= $value;
}
if (isset($this->output[$section]['progress'])) {
usort($this->output[$section]['progress'], function($a, $b) {
if ($a === $b) {
return 0;
}
if (is_int($a)) {
return -1;
}
if (is_int($b)) {
return 1;
}
if ($a === 'finish') {
return 1;
}
if ($b === 'finish') {
return -1;
}
return 0;
});
}
}
protected function writeOutput(Console\Input\InputInterface $input, Console\Output\OutputInterface $output): void
{
$sectionNames = array_keys($this->output);
$ios = [];
foreach ($sectionNames as $sectionName) {
$section = $output->section();
$ios[$sectionName] = new Console\Style\SymfonyStyle($input, $section);
}
foreach ($this->output as $sectionName => $configurations) {
$io = $ios[$sectionName];
$this->writeSection($io, $configurations);
}
}
protected function writeSection(Console\Style\SymfonyStyle $io, array $configurations): void
{
if (array_key_exists('table', $configurations)) {
$this->writeTables($io, $configurations['table']);
}
if (array_key_exists('progress', $configurations)) {
$this->writeProgress($io, $configurations['progress']);
}
if (array_key_exists('message', $configurations)) {
$this->writeMessages($io, $configurations['message']);
}
}
protected function writeTables(Console\Style\SymfonyStyle $io, array $tableConfigurations): void
{
foreach ($tableConfigurations as $tableData) {
$io->table(...$tableData);
}
}
protected function writeMessages(Console\Style\SymfonyStyle $io, array $messages): void
{
foreach ($messages as $message) {
$io->writeln($message);
}
}
protected function writeProgress(Console\Style\SymfonyStyle $io, array $progresses): void
{
$progressBar = null;
foreach ($progresses as $progress) {
if ($progress === 'advance' and $progressBar !== null) {
$progressBar->advance();
continue;
}
if ($progress === 'finish' and $progressBar !== null) {
$progressBar->finish();
continue;
}
if (in_array($progress, ['finish', 'advance'])) {
continue;
}
$progressBar = $io->createProgressBar($progress);
}
$io->newLine();
}
}

View File

@ -37,83 +37,15 @@ class Queue extends Command
$now = new DateTimeImmutable('now', $this->timezone);
$io->title("[{$now->format('Y-m-d H:i:s e')}] Running Queue...");
$jobs = $this->getJobs();
$jobCount = count($jobs);
if ($jobCount === 0) {
return Console\Command\Command::SUCCESS;
}
$io->writeln("Found {$jobCount} jobs to run");
$result = $this->runJob($jobs[0]);
/*$result = $this->runJobs($io, $jobs);
foreach ($this->outputs as $output) {
$this->sections['bottom']->writeln($output);
}*/
return $result;
return $this->runJob();
}
protected array $sections;
protected function getJobs(): array
{
$this->logger->debug("Getting jobs");
$jobs = $this->jobService->getPending();
$jobCount = count($jobs);
if ($jobCount === 0) {
$this->logger->debug("No jobs to run");
return [];
}
$this->logger->debug("Found {$jobCount} jobs");
return array_column($jobs, 'id');
}
protected function runJobs(Console\Style\SymfonyStyle $io, array $jobs): int
{
$chunks = array_chunk($jobs, $this->batchSize);
$chunkCount = count($chunks);
$result = self::SUCCESS;
$progress1 = $io->createProgressBar($chunkCount);
$progress1->start();
foreach ($chunks as $chunk) {
if ($this->runJobBatch($chunk) === self::FAILURE) {
$result = self::FAILURE;
}
$progress1->advance();
}
$progress1->finish();
return $result;
}
protected array $outputs = [];
protected function runJobBatch(array $jobIds): int
protected function runJob(): int
{
$baseCommand = "{$this->baseCommand} jobs:run";
$jobsLine = implode(' ', $jobIds);
$command = "{$baseCommand} {$jobsLine}";
try {
exec($command, $output, $resultCode);
$this->outputs []= $output;
} catch (Throwable $exception) {
$this->logger->error("Failed to run command", [
'command' => $command,
'exception' => $exception
]);
return self::FAILURE;
}
if ($resultCode !== 0) {
$this->logger->error("Failed to run command", [
'command' => $command,
'result_code' => $resultCode
]);
return self::FAILURE;
}
return self::SUCCESS;
}
protected function runJob(int $jobId): int
{
$baseCommand = "{$this->baseCommand} jobs:run";
$command = "{$baseCommand} {$jobId}";
$command = "{$baseCommand}";
try {
exec($command, $output, $resultCode);
$this->outputs []= $output;

View File

@ -11,7 +11,7 @@ use Predis\Connection\ConnectionException;
class Job
{
public function __construct(protected LoggerInterface $logger, protected Redis $redisService)
public function __construct(protected LoggerInterface $logger)
{
$this->redisKey = 'jobs';
}