diff --git a/System/Crontab/Consumer.php b/System/Crontab/Consumer.php index f5f92cad..273a65fb 100644 --- a/System/Crontab/Consumer.php +++ b/System/Crontab/Consumer.php @@ -22,94 +22,108 @@ use Swoole\Coroutine; class Consumer extends Process { - public Coroutine\Channel $channel; + public Coroutine\Channel $channel; - /** - * @param \Swoole\Process $process - * @throws Exception - */ - public function onHandler(\Swoole\Process $process): void - { - if (Snowflake::getPlatform()->isLinux()) { - name($this->pid, 'Crontab consumer'); - } + /** + * @param \Swoole\Process $process + * @throws Exception + */ + public function onHandler(\Swoole\Process $process): void + { + if (Snowflake::getPlatform()->isLinux()) { + name($this->pid, 'Crontab consumer'); + } - $this->channel = new Coroutine\Channel(2000); - go(function () { - $this->popChannel(); - }); - $this->tick($process); - } + $this->channel = new Coroutine\Channel(2000); + go(function () { + $this->popChannel(); + }); + + $this->recovery(); + $this->tick($process); + } - /** - * @throws Exception - */ - public function popChannel() - { - /** @var Crontab $crontab */ - $crontab = $this->channel->pop(-1); - go(function () use ($crontab) { - try { - $crontab->increment()->execute(); - if ($crontab->getExecuteNumber() < $crontab->getMaxExecuteNumber()) { - Consumer::addTask($crontab); - } else if ($crontab->isLoop()) { - Consumer::addTask($crontab); - } - } catch (\Throwable $throwable) { - logger()->addError($throwable,'throwable'); - } finally { - fire(Event::SYSTEM_RESOURCE_RELEASES); - } - }); - $this->popChannel(); - } + private function recovery() + { + $redis = redis()->hGetAll('crontab:wait:execute'); + foreach ($redis as $redi) { + $this->channel->push($redi); + } + fire(Event::SYSTEM_RESOURCE_RELEASES); + } - /** - * @param \Swoole\Process $process - * @throws ReflectionException - * @throws ComponentException - * @throws ConfigException - * @throws NotFindClassException - * @throws Exception - */ - public function tick(\Swoole\Process $process) - { - $value = $process->read(40); - - $redis = Snowflake::app()->getRedis(); - - $crontab = swoole_unserialize($redis->get($value)); - $redis->del($value); - if (is_object($crontab)) { - $this->channel->push($crontab); - } - - $redis->release(); - - $this->tick($process); - } + /** + * @throws Exception + */ + public function popChannel() + { + /** @var Crontab $crontab */ + $crontab = $this->channel->pop(-1); + go(function () use ($crontab) { + try { + $crontab->increment()->execute(); + if ($crontab->getExecuteNumber() < $crontab->getMaxExecuteNumber()) { + Consumer::addTask($crontab); + } else if ($crontab->isLoop()) { + Consumer::addTask($crontab); + } + } catch (\Throwable $throwable) { + logger()->addError($throwable, 'throwable'); + } finally { + fire(Event::SYSTEM_RESOURCE_RELEASES); + } + }); + $this->popChannel(); + } - /** - * @param Crontab $crontab - * @throws Exception - */ - private static function addTask(Crontab $crontab) - { - $redis = Snowflake::app()->getRedis(); + /** + * @param \Swoole\Process $process + * @throws ReflectionException + * @throws ComponentException + * @throws ConfigException + * @throws NotFindClassException + * @throws Exception + */ + public function tick(\Swoole\Process $process) + { + $value = $process->read(40); - $name = md5($crontab->getName()); + $redis = Snowflake::app()->getRedis(); - $redis->set('crontab:' . $name, swoole_serialize($crontab)); + /** @var Crontab $crontab */ + $crontab = swoole_unserialize($redis->get($value)); + $redis->hSet('crontab:wait:execute', $crontab->getName(), $redis->get($value)); + $redis->del($value); + if (is_object($crontab)) { + $this->channel->push($crontab); + } - $tickTime = time() + $crontab->getTickTime(); + $redis->release(); - $redis->zAdd(Producer::CRONTAB_KEY, $tickTime, $crontab->getName()); - } + $this->tick($process); + } + + + /** + * @param Crontab $crontab + * @throws Exception + */ + private static function addTask(Crontab $crontab) + { + $redis = Snowflake::app()->getRedis(); + + $name = md5($crontab->getName()); + + $redis->set('crontab:' . $name, swoole_serialize($crontab)); + + $tickTime = time() + $crontab->getTickTime(); + + $redis->zAdd(Producer::CRONTAB_KEY, $tickTime, $crontab->getName()); + } } diff --git a/System/Crontab/Crontab.php b/System/Crontab/Crontab.php index a9ecf4ea..6c8e2f00 100644 --- a/System/Crontab/Crontab.php +++ b/System/Crontab/Crontab.php @@ -200,6 +200,7 @@ class Crontab extends BaseObject public function execute(): void { $params = call_user_func($this->handler, $this->params, $this->name); + \redis()->hDel('crontab:wait:execute', $this->getName()); if ($params !== null) { $name = date('Y_m_d_H_i_s.' . $this->name . '.log'); write(storage($name, '/log/crontab'), serialize($params)); diff --git a/System/Crontab/ZookeeperProcess.php b/System/Crontab/ZookeeperProcess.php index db541ca0..f2a19c8b 100644 --- a/System/Crontab/ZookeeperProcess.php +++ b/System/Crontab/ZookeeperProcess.php @@ -19,68 +19,69 @@ class ZookeeperProcess extends Process { - private Channel $channel; - private WaitGroup $waitGroup; + private Channel $channel; + private WaitGroup $waitGroup; - /** @var Crontab[] $names */ - public array $names = []; + /** @var Crontab[] $names */ + public array $names = []; - public array $scores = []; - public array $timers = []; + public array $scores = []; + public array $timers = []; - /** - * @param \Swoole\Process $process - * @throws Exception - */ - public function onHandler(\Swoole\Process $process): void - { - $crontab = Snowflake::app()->get('crontab'); - $crontab->clearAll(); + /** + * @param \Swoole\Process $process + * @throws Exception + */ + public function onHandler(\Swoole\Process $process): void + { + $crontab = Snowflake::app()->get('crontab'); + $crontab->clearAll(); - if (Snowflake::getPlatform()->isLinux()) { - name($this->pid, 'Crontab zookeeper.'); - } - Timer::tick(1000, function () { - $startTime = time(); + if (Snowflake::getPlatform()->isLinux()) { + name($this->pid, 'Crontab zookeeper.'); + } + Timer::tick(1000, function () { + $startTime = time(); - $redis = Snowflake::app()->getRedis(); + $redis = Snowflake::app()->getRedis(); - $redis->multi(); - $range = $redis->zRangeByScore(Producer::CRONTAB_KEY, '0', (string)$startTime); - $redis->zRemRangeByScore(Producer::CRONTAB_KEY, '0', (string)$startTime); + $redis->multi(); + $range = $redis->zRangeByScore(Producer::CRONTAB_KEY, '0', (string)$startTime); + $redis->zRemRangeByScore(Producer::CRONTAB_KEY, '0', (string)$startTime); $redis->exec(); $redis->release(); - /** @var Consumer $consumer */ - $consumer = Snowflake::app()->get(Consumer::class); + /** @var Consumer $consumer */ + $consumer = Snowflake::app()->get(Consumer::class); - foreach ($range as $value) { - $consumer->write('crontab:' . md5($value)); - } - }); - } + foreach ($range as $value) { + $consumer->write('crontab:' . md5($value)); + } + }); + } - /** - * @param string $name - */ - public function clear(string $name) - { - if (!isset($this->names[$name])) { - return; - } - $timers = $this->timers[$name]; - $search = array_search($name, $this->scores[$timers]); - if ($search !== false) { - unset($this->scores[$timers][$search]); - } - unset($this->timers[$name], $this->names[$name]); - } + /** + * @param string $name + */ + public function clear(string $name) + { + if (!isset($this->names[$name])) { + return; + } + $timers = $this->timers[$name]; + + $search = array_search($name, $this->scores[$timers]); + if ($search !== false) { + unset($this->scores[$timers][$search]); + } + unset($this->timers[$name], $this->names[$name]); + } }