Skip to content

Commit

Permalink
j-guyon#185: Dynamic parameters
Browse files Browse the repository at this point in the history
  • Loading branch information
Zul3s committed Jan 16, 2021
1 parent c8a54b9 commit c375f80
Show file tree
Hide file tree
Showing 9 changed files with 230 additions and 37 deletions.
12 changes: 11 additions & 1 deletion Command/ExecuteCommand.php
Original file line number Diff line number Diff line change
Expand Up @@ -178,6 +178,7 @@ private function executeCommand(ScheduledCommand $scheduledCommand, OutputInterf
}

$scheduledCommand = $notLockedCommand;
$lastExecution = $scheduledCommand->getLastExecution();
$scheduledCommand->setLastExecution(new \DateTime());
$scheduledCommand->setLocked(true);
$this->em->persist($scheduledCommand);
Expand Down Expand Up @@ -207,8 +208,17 @@ private function executeCommand(ScheduledCommand $scheduledCommand, OutputInterf
return;
}

$arguments = str_replace(
array('%last_execution%', '%log_file%', '%last_return_code%'),
array(
'"' . $lastExecution->format('Y-m-d H:i:s') . '"',
'"' . $scheduledCommand->getLogFile() . '"',
'"' . $scheduledCommand->getLastReturnCode() .'"'
),
$scheduledCommand->getArguments()
);
$input = new StringInput(
$scheduledCommand->getCommand().' '.$scheduledCommand->getArguments().' --env='.$input->getOption('env')
$scheduledCommand->getCommand().' '.$arguments.' --env='.$input->getOption('env')
);
$command->mergeApplicationDefinition();
$input->bind($command->getDefinition());
Expand Down
57 changes: 57 additions & 0 deletions Fixtures/ORM/AbstractScheduledCommandData.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,57 @@
<?php

namespace JMose\CommandSchedulerBundle\Fixtures\ORM;

use Doctrine\Common\DataFixtures\FixtureInterface;
use Doctrine\Persistence\ObjectManager;
use JMose\CommandSchedulerBundle\Entity\ScheduledCommand;

/**
* Class LoadScheduledCommandData.
*
* @author Julien Guyon <[email protected]>
*/
abstract class AbstractScheduledCommandData implements FixtureInterface
{
/**
* Create a new ScheduledCommand in database.
*
* @param $name
* @param $command
* @param $arguments
* @param $cronExpression
* @param $logFile
* @param $priority
* @param $lastExecution
* @param bool $locked
* @param bool $disabled
* @param bool $executeNow
* @param int $lastReturnCode
*/
protected function createScheduledCommand(
$name, $command, $arguments, $cronExpression, $logFile, $priority, $lastExecution,
$locked = false, $disabled = false, $executeNow = false, $lastReturnCode = null)
{
$scheduledCommand = new ScheduledCommand();
$scheduledCommand
->setName($name)
->setCommand($command)
->setArguments($arguments)
->setCronExpression($cronExpression)
->setLogFile($logFile)
->setPriority($priority)
->setLastExecution($lastExecution)
->setLocked($locked)
->setDisabled($disabled)
->setLastReturnCode($lastReturnCode)
->setExecuteImmediately($executeNow);

$this->getManager()->persist($scheduledCommand);
$this->getManager()->flush();
}

/**
* @return ObjectManager
*/
abstract protected function getManager(): ObjectManager;
}
39 changes: 4 additions & 35 deletions Fixtures/ORM/LoadScheduledCommandData.php
Original file line number Diff line number Diff line change
Expand Up @@ -2,16 +2,14 @@

namespace JMose\CommandSchedulerBundle\Fixtures\ORM;

use Doctrine\Common\DataFixtures\FixtureInterface;
use Doctrine\Persistence\ObjectManager;
use JMose\CommandSchedulerBundle\Entity\ScheduledCommand;

/**
* Class LoadScheduledCommandData.
*
* @author Julien Guyon <[email protected]>
*/
class LoadScheduledCommandData implements FixtureInterface
class LoadScheduledCommandData extends AbstractScheduledCommandData
{
/**
* @var ObjectManager
Expand All @@ -36,39 +34,10 @@ public function load(ObjectManager $manager)
}

/**
* Create a new ScheduledCommand in database.
*
* @param $name
* @param $command
* @param $arguments
* @param $cronExpression
* @param $logFile
* @param $priority
* @param $lastExecution
* @param bool $locked
* @param bool $disabled
* @param bool $executeNow
* @param int $lastReturnCode
* @inheritDoc
*/
protected function createScheduledCommand(
$name, $command, $arguments, $cronExpression, $logFile, $priority, $lastExecution,
$locked = false, $disabled = false, $executeNow = false, $lastReturnCode = null)
protected function getManager(): ObjectManager
{
$scheduledCommand = new ScheduledCommand();
$scheduledCommand
->setName($name)
->setCommand($command)
->setArguments($arguments)
->setCronExpression($cronExpression)
->setLogFile($logFile)
->setPriority($priority)
->setLastExecution($lastExecution)
->setLocked($locked)
->setDisabled($disabled)
->setLastReturnCode($lastReturnCode)
->setExecuteImmediately($executeNow);

$this->manager->persist($scheduledCommand);
$this->manager->flush();
return $this->manager;
}
}
69 changes: 69 additions & 0 deletions Fixtures/ORM/LoadScheduledCommandWithDynamicValuesData.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,69 @@
<?php

namespace JMose\CommandSchedulerBundle\Fixtures\ORM;

use DateTime;
use Doctrine\Persistence\ObjectManager;
use JMose\CommandSchedulerBundle\Tests\App\Command\TestCommand;

/**
* Class LoadScheduledCommandData.
*
* @author Julien Guyon <[email protected]>
*/
class LoadScheduledCommandWithDynamicValuesData extends AbstractScheduledCommandData
{
const LAST_EXECUTION_DATE = '2021-01-02 08:01:02';
const LAST_RETURN_CODE_0 = 0;
const LAST_RETURN_CODE_NEGATIVE_1 = -1;
const LOG_FILE = 'LoadScheduledCommandWithDynamicValuesData_log_file.log';

/**
* @var ObjectManager
*/
protected $manager;

/**
* {@inheritdoc}
*/
public function load(ObjectManager $manager)
{
$this->manager = $manager;

$this->createScheduledCommand(
__CLASS__ . '_one',
'scheduler:execute:test',
'%last_execution% %log_file% --' . TestCommand::LAST_RETURN_CODE . '=%last_return_code%',
'@daily',
self::LOG_FILE,
40,
new DateTime(self::LAST_EXECUTION_DATE),
false,
false,
true,
self::LAST_RETURN_CODE_0
);
$this->createScheduledCommand(
__CLASS__ . '_one',
'scheduler:execute:test',
'%last_execution% %log_file% --' . TestCommand::LAST_RETURN_CODE . '=%last_return_code%',
'@daily',
self::LOG_FILE,
40,
new DateTime(self::LAST_EXECUTION_DATE),
false,
false,
true,
self::LAST_RETURN_CODE_NEGATIVE_1
);

}

/**
* @inheritDoc
*/
protected function getManager(): ObjectManager
{
return $this->manager;
}
}
7 changes: 6 additions & 1 deletion Resources/doc/index.md
Original file line number Diff line number Diff line change
Expand Up @@ -212,6 +212,12 @@ The `scheduler:execute` command will do following actions :
- Check if the command has to be executed at current time, based on its cron expression and on its last execution time
- Execute eligible commands (without `exec` php function)

Use dynamic parameters :

- %last_execution% : last execution date (format : Y-m-d H:i:s). Available for arguments and options
- %log_file% : output file. Available for arguments and options
- %last_return_code% : last return code. ONLY available for options (possible value -1 is not working for Argument)

The `scheduler:unlock` command is capable of unlock all or a single scheduled command with a `lock-timeout` parameter.
It can be usefull if you don't have a full control about server restarting, which can a command in a lock state.

Expand All @@ -223,7 +229,6 @@ Note that with this mode, if a command with an error, it will stop all the sched
This system avoid to have simultaneous process for the same command.
Thus, if an non-catchable error occurs, the command won't be executed again unless the problem is solved and the task is unlocked manually.


Monitoring
=============

Expand Down
55 changes: 55 additions & 0 deletions Tests/App/Command/TestCommand.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,55 @@
<?php


namespace JMose\CommandSchedulerBundle\Tests\App\Command;

use Symfony\Component\Console\Command\Command;
use Symfony\Component\Console\Input\InputArgument;
use Symfony\Component\Console\Input\InputInterface;
use Symfony\Component\Console\Input\InputOption;
use Symfony\Component\Console\Output\OutputInterface;

class TestCommand extends Command
{
const OUTPUT_LOG_FILE = __DIR__ . '/../logs/TEST_COMMAND_OUTPUT_LOG_FILE.txt';
const LAST_EXECUTION_TIME = 'last_execution_time';
const LOG_FILE = 'log_file';
const LAST_RETURN_CODE = 'last_return_code';

private static $index = 0;

/**
* {@inheritdoc}
*/
protected function configure()
{
$this
->setName('scheduler:execute:test')
->setDescription('Fake command')
->addArgument(self::LAST_EXECUTION_TIME, null, InputArgument::REQUIRED, 'Last execution time params')
->addArgument(self::LOG_FILE, null, InputArgument::OPTIONAL, 'Log file')
->addOption(self::LAST_RETURN_CODE, null, InputOption::VALUE_REQUIRED, 'Last return Code');
}

/**
* @param InputInterface $input
* @param OutputInterface $output
*
* @return int
*/
protected function execute(InputInterface $input, OutputInterface $output)
{
$content = array();
if (file_exists(self::OUTPUT_LOG_FILE)) {
$content = json_decode(file_get_contents(self::OUTPUT_LOG_FILE), true);
}
$content[self::$index] = array(
self::LAST_EXECUTION_TIME => $input->getArgument(self::LAST_EXECUTION_TIME),
self::LOG_FILE => $input->getArgument(self::LOG_FILE),
self::LAST_RETURN_CODE => (int) $input->getOption(self::LAST_RETURN_CODE)
);
file_put_contents(self::OUTPUT_LOG_FILE, json_encode($content));
self::$index++;
return 0;
}
}
4 changes: 4 additions & 0 deletions Tests/App/config/config_test.yml
Original file line number Diff line number Diff line change
Expand Up @@ -49,3 +49,7 @@ services:
JMose\CommandSchedulerBundle\Fixtures\ORM\:
resource: '../../../Fixtures/ORM/*'
tags: ['doctrine.fixture.orm']

JMose\CommandSchedulerBundle\Tests\App\Command\:
resource: '../Command/*'
tags: [ 'console.command' ]
22 changes: 22 additions & 0 deletions Tests/Command/ExecuteCommandTest.php
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,8 @@
namespace JMose\CommandSchedulerBundle\Tests\Command;

use JMose\CommandSchedulerBundle\Fixtures\ORM\LoadScheduledCommandData;
use JMose\CommandSchedulerBundle\Fixtures\ORM\LoadScheduledCommandWithDynamicValuesData;
use JMose\CommandSchedulerBundle\Tests\App\Command\TestCommand;
use Liip\FunctionalTestBundle\Test\WebTestCase;
use Liip\TestFixturesBundle\Test\FixturesTrait;

Expand Down Expand Up @@ -75,4 +77,24 @@ public function testExecuteWithDump()
$this->assertRegExp('/Command debug:container should be executed/', $output);
$this->assertRegExp('/Immediately execution asked for : debug:router/', $output);
}

/**
* Test scheduler:execute without option.
*/
public function testExecuteWithParameters()
{
// DataFixtures create 4 records
$this->loadFixtures([LoadScheduledCommandWithDynamicValuesData::class]);

$this->runCommand('scheduler:execute', [], true);
$result = json_decode(file_get_contents(TestCommand::OUTPUT_LOG_FILE), true);

$this->assertSame($result[0][TestCommand::LOG_FILE], LoadScheduledCommandWithDynamicValuesData::LOG_FILE);
$this->assertSame($result[0][TestCommand::LAST_RETURN_CODE], LoadScheduledCommandWithDynamicValuesData::LAST_RETURN_CODE_0);
$this->assertSame($result[0][TestCommand::LAST_EXECUTION_TIME], LoadScheduledCommandWithDynamicValuesData::LAST_EXECUTION_DATE);

$this->assertSame($result[1][TestCommand::LOG_FILE], LoadScheduledCommandWithDynamicValuesData::LOG_FILE);
$this->assertSame($result[1][TestCommand::LAST_RETURN_CODE], LoadScheduledCommandWithDynamicValuesData::LAST_RETURN_CODE_NEGATIVE_1);
$this->assertSame($result[1][TestCommand::LAST_EXECUTION_TIME], LoadScheduledCommandWithDynamicValuesData::LAST_EXECUTION_DATE);
}
}
2 changes: 2 additions & 0 deletions composer.json
Original file line number Diff line number Diff line change
Expand Up @@ -26,7 +26,9 @@
"symfony/validator": "^3.4|^4.3|^5.0"
},
"require-dev": {
"ext-pdo_sqlite": "*",
"ext-pcntl": "*",
"ext-json": "*",
"phpunit/phpunit": "^8.5",
"php-coveralls/php-coveralls": "^2.0",
"doctrine/doctrine-fixtures-bundle": "^3.0.0",
Expand Down

0 comments on commit c375f80

Please sign in to comment.