Better cli interface

* [Feature] --reset-all command can be used to reset entire job subsystem.
* [Feature] Add export event to cli jobs.
* [Improvement] CLI component can handle more types of errors now.
* [Improvement] Shutdown handler for resetting execution locks.
* [UX] Added warning notice to the CLI help.
* [Fix] Suppress undefined index notice.
* [Fix] Added export job into CLI jobs list.
This commit is contained in:
Pavel 2020-04-30 14:41:09 +03:00 committed by GitHub
parent 40a0185fa3
commit 9b2a8e1585
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
7 changed files with 127 additions and 20 deletions

View File

@ -1,3 +1,6 @@
## v3.0.6
* Улучшена работа CLI
## v3.0.5
* Возможность установки регулярных задач в `cron`, CLI-интерфейс для запуска задач вручную
* Теперь при отсутствии редактируемого заказа в retailCRM он будет создаваться (ранее попытка редактирования приводила к ошибке)

View File

@ -1 +1 @@
3.0.5
3.0.6

View File

@ -38,6 +38,10 @@
declare(ticks = 1);
if (!isset($_SERVER['REQUEST_METHOD'])) {
$_SERVER['REQUEST_METHOD'] = 'POST';
}
require_once dirname(__FILE__) . '/lib/RetailcrmCli.php';
function retailcrmCliInterruptHandler($signo)

View File

@ -86,7 +86,12 @@ class RetailcrmJobsModuleFrontController extends ModuleFrontController
*/
protected function getData()
{
RetailcrmJobManager::startJobs(RetailCRM::getJobs());
RetailcrmJobManager::startJobs(array(
'RetailcrmAbandonedCartsEvent' => null,
'RetailcrmIcmlEvent' => new \DateInterval('PT4H'),
'RetailcrmSyncEvent' => new \DateInterval('PT7M'),
'RetailcrmInventoriesEvent' => new \DateInterval('PT15M')
));
return array('success' => true);
}

View File

@ -99,19 +99,34 @@ class RetailcrmCli
}
$shortopts = "j:";
$longopts = array("job:", "reset-job-manager");
$longopts = array("job:", "reset-job-manager", "reset-all");
$options = getopt($shortopts, $longopts);
$jobName = isset($options['j']) ? $options['j'] : (isset($options['job']) ? $options['job'] : null);
if (isset($options['reset-job-manager'])) {
$this->resetJobManager();
} elseif (isset($options['reset-all'])) {
$this->resetAll();
} elseif (empty($jobName)) {
$this->help();
} else {
$this->setCleanupOnShutdown();
$this->runJob($jobName);
}
}
/**
* This will register shutdown handler which will clean lock before shutdown
*/
private function setCleanupOnShutdown()
{
RetailcrmJobManager::setCustomShutdownHandler(function ($error) {
if (null !== $error) {
self::clearCurrentJob(null);
}
});
}
/**
* Runs provided job
*
@ -157,7 +172,7 @@ class RetailcrmCli
RetailcrmLogger::output('Available jobs:');
RetailcrmLogger::output();
foreach (array_keys(RetailCRM::getJobs()) as $job) {
foreach ($this->getAllowedJobs() as $job) {
RetailcrmLogger::output(sprintf(' - %s', $job));
}
@ -166,10 +181,21 @@ class RetailcrmCli
RetailcrmLogger::output();
RetailcrmLogger::output(sprintf('> php %s -j <job name> - Runs provided job', $this->cliPath));
RetailcrmLogger::output(sprintf('> php %s --job <job name> - Runs provided job', $this->cliPath));
RetailcrmLogger::output();
RetailcrmLogger::output(
"WARNING: Commands below are dangerous and should be used only when " .
"job manager or cli doesn't work properly."
);
RetailcrmLogger::output("Use them at your own risk.");
RetailcrmLogger::output();
RetailcrmLogger::output(sprintf(
'> php %s --reset-job-manager - Will reset job manager internal timers & current job name',
$this->cliPath
));
RetailcrmLogger::output(sprintf(
'> php %s --reset-all - Will reset the entire job subsystem state, can resolve most problems',
$this->cliPath
));
RetailcrmLogger::output();
}
@ -189,6 +215,16 @@ class RetailcrmCli
}
}
/**
* Resets JobManager and cli internal lock
*/
private function resetAll()
{
$this->resetJobManager();
self::clearCurrentJob(null);
RetailcrmLogger::output('CLI command lock was cleared.');
}
/**
* Sets current running job. Every job must call this in CLI in order to work properly.
* Current running job will be cleared automatically after job was finished (or crashed).
@ -230,4 +266,20 @@ class RetailcrmCli
return true;
}
/**
* Returns list of jobs which are allowed to be executed via cli
*
* @return string[]
*/
private function getAllowedJobs()
{
return array(
'RetailcrmAbandonedCartsEvent',
'RetailcrmIcmlEvent',
'RetailcrmSyncEvent',
'RetailcrmInventoriesEvent',
'RetailcrmExportEvent'
);
}
}

View File

@ -61,6 +61,12 @@ class RetailcrmJobManager
const IN_PROGRESS_NAME = 'RETAILCRM_JOBS_IN_PROGRESS';
const CURRENT_TASK = 'RETAILCRM_JOB_CURRENT';
/** @var callable|null */
private static $customShutdownHandler;
/** @var bool */
private static $shutdownHandlerRegistered;
/**
* Entry point for all jobs.
* Jobs must be passed in this format:
@ -365,6 +371,56 @@ class RetailcrmJobManager
return $result;
}
/**
* Sets custom shutdown handler, it will be called before calling default shutdown handler.
*
* @param callable $shutdownHandler
*/
public static function setCustomShutdownHandler($shutdownHandler)
{
if (is_callable($shutdownHandler)) {
self::$customShutdownHandler = $shutdownHandler;
}
}
/**
* Register default shutdown handler (should be be called before any job execution)
*/
private static function registerShutdownHandler()
{
if (!self::$shutdownHandlerRegistered) {
register_shutdown_function(function() {
$error = error_get_last();
if(null !== $error) {
self::defaultShutdownHandler($error);
}
});
self::$shutdownHandlerRegistered = true;
}
}
/**
* Default handler for shutdown function
*
* @param array $error
*/
private static function defaultShutdownHandler($error)
{
if (is_callable(self::$customShutdownHandler)) {
call_user_func_array(self::$customShutdownHandler, array($error));
}
RetailcrmLogger::writeCaller(
__METHOD__,
'Warning: something disrupted correct process execution. All information will be provided here.'
);
RetailcrmLogger::writeCaller(__METHOD__, print_r($error, true));
self::unlock();
exit(1);
}
/**
* Writes error to log and returns 500
*
@ -447,6 +503,8 @@ class RetailcrmJobManager
$job->setCliMode($cliMode);
self::registerShutdownHandler();
return $job->execute();
}

View File

@ -116,7 +116,7 @@ class RetailCRM extends Module
{
$this->name = 'retailcrm';
$this->tab = 'export';
$this->version = '3.0.5';
$this->version = '3.0.6';
$this->author = 'DIGITAL RETAIL TECHNOLOGIES SL';
$this->displayName = $this->l('retailCRM');
$this->description = $this->l('Integration module for retailCRM');
@ -1134,21 +1134,6 @@ class RetailCRM extends Module
}
}
/**
* Returns jobs list
*
* @return array
*/
public static function getJobs()
{
return array(
'RetailcrmAbandonedCartsEvent' => null,
'RetailcrmIcmlEvent' => new \DateInterval('PT4H'),
'RetailcrmSyncEvent' => new \DateInterval('PT7M'),
'RetailcrmInventoriesEvent' => new \DateInterval('PT15M')
);
}
/**
* Synchronized cartsIds time choice
*