Increased timeout on db commands to 10 minutes

This commit is contained in:
Alejandro Celaya 2021-02-12 22:59:40 +01:00
parent 08507272ed
commit d932f0a204
11 changed files with 106 additions and 27 deletions

View File

@ -34,6 +34,8 @@ return [
PhpExecutableFinder::class => InvokableFactory::class,
Util\GeolocationDbUpdater::class => ConfigAbstractFactory::class,
Util\ProcessRunner::class => ConfigAbstractFactory::class,
ApiKey\RoleResolver::class => ConfigAbstractFactory::class,
Command\ShortUrl\GenerateShortUrlCommand::class => ConfigAbstractFactory::class,
@ -62,6 +64,7 @@ return [
ConfigAbstractFactory::class => [
Util\GeolocationDbUpdater::class => [DbUpdater::class, Reader::class, LOCAL_LOCK_FACTORY],
Util\ProcessRunner::class => [SymfonyCli\Helper\ProcessHelper::class],
ApiKey\RoleResolver::class => [DomainService::class],
Command\ShortUrl\GenerateShortUrlCommand::class => [
@ -97,14 +100,14 @@ return [
Command\Db\CreateDatabaseCommand::class => [
LockFactory::class,
SymfonyCli\Helper\ProcessHelper::class,
Util\ProcessRunner::class,
PhpExecutableFinder::class,
Connection::class,
NoDbNameConnectionFactory::SERVICE_NAME,
],
Command\Db\MigrateDatabaseCommand::class => [
LockFactory::class,
SymfonyCli\Helper\ProcessHelper::class,
Util\ProcessRunner::class,
PhpExecutableFinder::class,
],
],

View File

@ -6,31 +6,34 @@ namespace Shlinkio\Shlink\CLI\Command\Db;
use Shlinkio\Shlink\CLI\Command\Util\AbstractLockedCommand;
use Shlinkio\Shlink\CLI\Command\Util\LockedCommandConfig;
use Symfony\Component\Console\Helper\ProcessHelper;
use Shlinkio\Shlink\CLI\Util\ProcessRunnerInterface;
use Symfony\Component\Console\Output\OutputInterface;
use Symfony\Component\Lock\LockFactory;
use Symfony\Component\Process\PhpExecutableFinder;
abstract class AbstractDatabaseCommand extends AbstractLockedCommand
{
private ProcessHelper $processHelper;
private ProcessRunnerInterface $processRunner;
private string $phpBinary;
public function __construct(LockFactory $locker, ProcessHelper $processHelper, PhpExecutableFinder $phpFinder)
{
public function __construct(
LockFactory $locker,
ProcessRunnerInterface $processRunner,
PhpExecutableFinder $phpFinder
) {
parent::__construct($locker);
$this->processHelper = $processHelper;
$this->processRunner = $processRunner;
$this->phpBinary = $phpFinder->find(false) ?: 'php';
}
protected function runPhpCommand(OutputInterface $output, array $command): void
{
$command = [$this->phpBinary, ...$command, '--no-interaction'];
$this->processHelper->mustRun($output, $command);
$this->processRunner->run($output, $command);
}
protected function getLockConfig(): LockedCommandConfig
{
return new LockedCommandConfig($this->getName(), true);
return LockedCommandConfig::blocking($this->getName());
}
}

View File

@ -6,7 +6,7 @@ namespace Shlinkio\Shlink\CLI\Command\Db;
use Doctrine\DBAL\Connection;
use Shlinkio\Shlink\CLI\Util\ExitCodes;
use Symfony\Component\Console\Helper\ProcessHelper;
use Shlinkio\Shlink\CLI\Util\ProcessRunnerInterface;
use Symfony\Component\Console\Input\InputInterface;
use Symfony\Component\Console\Output\OutputInterface;
use Symfony\Component\Console\Style\SymfonyStyle;
@ -26,12 +26,12 @@ class CreateDatabaseCommand extends AbstractDatabaseCommand
public function __construct(
LockFactory $locker,
ProcessHelper $processHelper,
ProcessRunnerInterface $processRunner,
PhpExecutableFinder $phpFinder,
Connection $conn,
Connection $noDbNameConn
) {
parent::__construct($locker, $processHelper, $phpFinder);
parent::__construct($locker, $processRunner, $phpFinder);
$this->regularConn = $conn;
$this->noDbNameConn = $noDbNameConn;
}

View File

@ -6,19 +6,29 @@ namespace Shlinkio\Shlink\CLI\Command\Util;
final class LockedCommandConfig
{
private const DEFAULT_TTL = 90.0; // 1.5 minutes
public const DEFAULT_TTL = 600.0; // 10 minutes
private string $lockName;
private bool $isBlocking;
private float $ttl;
public function __construct(string $lockName, bool $isBlocking = false, float $ttl = self::DEFAULT_TTL)
private function __construct(string $lockName, bool $isBlocking, float $ttl = self::DEFAULT_TTL)
{
$this->lockName = $lockName;
$this->isBlocking = $isBlocking;
$this->ttl = $ttl;
}
public static function blocking(string $lockName): self
{
return new self($lockName, true);
}
public static function nonBlocking(string $lockName): self
{
return new self($lockName, false);
}
public function lockName(): string
{
return $this->lockName;

View File

@ -208,6 +208,6 @@ class LocateVisitsCommand extends AbstractLockedCommand implements VisitGeolocat
protected function getLockConfig(): LockedCommandConfig
{
return new LockedCommandConfig($this->getName());
return LockedCommandConfig::nonBlocking($this->getName());
}
}

View File

@ -0,0 +1,54 @@
<?php
declare(strict_types=1);
namespace Shlinkio\Shlink\CLI\Util;
use Shlinkio\Shlink\CLI\Command\Util\LockedCommandConfig;
use Symfony\Component\Console\Helper\DebugFormatterHelper;
use Symfony\Component\Console\Helper\ProcessHelper;
use Symfony\Component\Console\Output\ConsoleOutputInterface;
use Symfony\Component\Console\Output\OutputInterface;
use Symfony\Component\Process\Process;
use function spl_object_hash;
use function sprintf;
use function str_replace;
class ProcessRunner implements ProcessRunnerInterface
{
private ProcessHelper $helper;
public function __construct(ProcessHelper $helper)
{
$this->helper = $helper;
}
public function run(OutputInterface $output, array $cmd): void
{
if ($output instanceof ConsoleOutputInterface) {
$output = $output->getErrorOutput();
}
/** @var DebugFormatterHelper $formatter */
$formatter = $this->helper->getHelperSet()->get('debug_formatter');
$process = new Process($cmd, null, null, null, LockedCommandConfig::DEFAULT_TTL);
if ($output->isVeryVerbose()) {
$output->write(
$formatter->start(spl_object_hash($process), str_replace('<', '\\<', $process->getCommandLine())),
);
}
$callback = $output->isDebug() ? $this->helper->wrapCallback($output, $process) : null;
$process->mustRun($callback);
if ($output->isVeryVerbose()) {
$message = $process->isSuccessful() ? 'Command ran successfully' : sprintf(
'%s Command did not run successfully',
$process->getExitCode(),
);
$output->write($formatter->stop(spl_object_hash($process), $message, $process->isSuccessful()));
}
}
}

View File

@ -0,0 +1,12 @@
<?php
declare(strict_types=1);
namespace Shlinkio\Shlink\CLI\Util;
use Symfony\Component\Console\Output\OutputInterface;
interface ProcessRunnerInterface
{
public function run(OutputInterface $output, array $cmd): void;
}

View File

@ -12,14 +12,13 @@ use Prophecy\Argument;
use Prophecy\PhpUnit\ProphecyTrait;
use Prophecy\Prophecy\ObjectProphecy;
use Shlinkio\Shlink\CLI\Command\Db\CreateDatabaseCommand;
use Shlinkio\Shlink\CLI\Util\ProcessRunnerInterface;
use Symfony\Component\Console\Application;
use Symfony\Component\Console\Helper\ProcessHelper;
use Symfony\Component\Console\Output\OutputInterface;
use Symfony\Component\Console\Tester\CommandTester;
use Symfony\Component\Lock\LockFactory;
use Symfony\Component\Lock\LockInterface;
use Symfony\Component\Process\PhpExecutableFinder;
use Symfony\Component\Process\Process;
class CreateDatabaseCommandTest extends TestCase
{
@ -43,7 +42,7 @@ class CreateDatabaseCommandTest extends TestCase
$phpExecutableFinder = $this->prophesize(PhpExecutableFinder::class);
$phpExecutableFinder->find(false)->willReturn('/usr/local/bin/php');
$this->processHelper = $this->prophesize(ProcessHelper::class);
$this->processHelper = $this->prophesize(ProcessRunnerInterface::class);
$this->schemaManager = $this->prophesize(AbstractSchemaManager::class);
$this->databasePlatform = $this->prophesize(AbstractPlatform::class);
@ -113,12 +112,12 @@ class CreateDatabaseCommandTest extends TestCase
$createDatabase = $this->schemaManager->createDatabase($shlinkDatabase)->will(function (): void {
});
$listTables = $this->schemaManager->listTableNames()->willReturn([]);
$runCommand = $this->processHelper->mustRun(Argument::type(OutputInterface::class), [
$runCommand = $this->processHelper->run(Argument::type(OutputInterface::class), [
'/usr/local/bin/php',
CreateDatabaseCommand::DOCTRINE_SCRIPT,
CreateDatabaseCommand::DOCTRINE_CREATE_SCHEMA_COMMAND,
'--no-interaction',
], Argument::cetera())->willReturn(new Process([]));
]);
$this->commandTester->execute([]);
$output = $this->commandTester->getDisplay();

View File

@ -9,14 +9,13 @@ use Prophecy\Argument;
use Prophecy\PhpUnit\ProphecyTrait;
use Prophecy\Prophecy\ObjectProphecy;
use Shlinkio\Shlink\CLI\Command\Db\MigrateDatabaseCommand;
use Shlinkio\Shlink\CLI\Util\ProcessRunnerInterface;
use Symfony\Component\Console\Application;
use Symfony\Component\Console\Helper\ProcessHelper;
use Symfony\Component\Console\Output\OutputInterface;
use Symfony\Component\Console\Tester\CommandTester;
use Symfony\Component\Lock\LockFactory;
use Symfony\Component\Lock\LockInterface;
use Symfony\Component\Process\PhpExecutableFinder;
use Symfony\Component\Process\Process;
class MigrateDatabaseCommandTest extends TestCase
{
@ -37,7 +36,7 @@ class MigrateDatabaseCommandTest extends TestCase
$phpExecutableFinder = $this->prophesize(PhpExecutableFinder::class);
$phpExecutableFinder->find(false)->willReturn('/usr/local/bin/php');
$this->processHelper = $this->prophesize(ProcessHelper::class);
$this->processHelper = $this->prophesize(ProcessRunnerInterface::class);
$command = new MigrateDatabaseCommand(
$locker->reveal(),
@ -53,12 +52,12 @@ class MigrateDatabaseCommandTest extends TestCase
/** @test */
public function migrationsCommandIsRunWithProperVerbosity(): void
{
$runCommand = $this->processHelper->mustRun(Argument::type(OutputInterface::class), [
$runCommand = $this->processHelper->run(Argument::type(OutputInterface::class), [
'/usr/local/bin/php',
MigrateDatabaseCommand::DOCTRINE_MIGRATIONS_SCRIPT,
MigrateDatabaseCommand::DOCTRINE_MIGRATE_COMMAND,
'--no-interaction',
], Argument::cetera())->willReturn(new Process([]));
]);
$this->commandTester->execute([]);
$output = $this->commandTester->getDisplay();

View File

@ -52,7 +52,7 @@ class LocateVisitsCommandTest extends TestCase
$this->lock->acquire(false)->willReturn(true);
$this->lock->release()->will(function (): void {
});
$locker->createLock(Argument::type('string'), 90.0, false)->willReturn($this->lock->reveal());
$locker->createLock(Argument::type('string'), 600.0, false)->willReturn($this->lock->reveal());
$command = new LocateVisitsCommand(
$this->visitService->reveal(),

View File

@ -2,5 +2,4 @@ parameters:
checkMissingIterableValueType: false
checkGenericClassInNonGenericObjectType: false
ignoreErrors:
- '#mustRun\(\)#'
- '#If condition is always false#'