diff --git a/CHANGELOG.md b/CHANGELOG.md index f0ee6aa..088b68f 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,3 +1,6 @@ +## v3.0.6 +* Улучшена работа CLI + ## v3.0.5 * Возможность установки регулярных задач в `cron`, CLI-интерфейс для запуска задач вручную * Теперь при отсутствии редактируемого заказа в retailCRM он будет создаваться (ранее попытка редактирования приводила к ошибке) diff --git a/VERSION b/VERSION index eca690e..818bd47 100644 --- a/VERSION +++ b/VERSION @@ -1 +1 @@ -3.0.5 +3.0.6 diff --git a/retailcrm/cli.php b/retailcrm/cli.php index a0f3049..452d769 100644 --- a/retailcrm/cli.php +++ b/retailcrm/cli.php @@ -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) diff --git a/retailcrm/controllers/front/Jobs.php b/retailcrm/controllers/front/Jobs.php index 347b222..fb910a8 100644 --- a/retailcrm/controllers/front/Jobs.php +++ b/retailcrm/controllers/front/Jobs.php @@ -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); } diff --git a/retailcrm/lib/RetailcrmCli.php b/retailcrm/lib/RetailcrmCli.php index 32c267d..157164d 100644 --- a/retailcrm/lib/RetailcrmCli.php +++ b/retailcrm/lib/RetailcrmCli.php @@ -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 - Runs provided job', $this->cliPath)); RetailcrmLogger::output(sprintf('> php %s --job - 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' + ); + } } diff --git a/retailcrm/lib/RetailcrmJobManager.php b/retailcrm/lib/RetailcrmJobManager.php index 3ce455b..f8f142b 100644 --- a/retailcrm/lib/RetailcrmJobManager.php +++ b/retailcrm/lib/RetailcrmJobManager.php @@ -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(); } diff --git a/retailcrm/retailcrm.php b/retailcrm/retailcrm.php index 3402eb9..17c5bc8 100644 --- a/retailcrm/retailcrm.php +++ b/retailcrm/retailcrm.php @@ -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 *