diff --git a/System/Abstracts/BaseApplication.php b/System/Abstracts/BaseApplication.php index ceb32f11..0cf66de4 100644 --- a/System/Abstracts/BaseApplication.php +++ b/System/Abstracts/BaseApplication.php @@ -28,6 +28,7 @@ use Annotation\Annotation as SAnnotation; use ReflectionException; use Snowflake\Async; use Snowflake\Cache\Redis; +use Snowflake\Crontab; use Snowflake\Di\Service; use Snowflake\Error\ErrorHandler; use Snowflake\Error\Logger; @@ -41,7 +42,6 @@ use Snowflake\Pool\Redis as SRedis; use Snowflake\Snowflake; use Snowflake\Event; use Snowflake\Pool\Pool as SPool; -use Database\DatabasesProviders; use Swoole\Table; /** @@ -445,6 +445,7 @@ abstract class BaseApplication extends Service 'jwt' => ['class' => Jwt::class], 'async' => ['class' => Async::class], 'filter' => ['class' => HttpFilter::class], + 'crontab' => ['class' => Crontab::class], 'object' => ['class' => ObjectPool::class], 'goto' => ['class' => BaseGoto::class], 'http2' => ['class' => Http2::class], diff --git a/System/Abstracts/TraitApplication.php b/System/Abstracts/TraitApplication.php index 7b744018..c2964260 100644 --- a/System/Abstracts/TraitApplication.php +++ b/System/Abstracts/TraitApplication.php @@ -11,11 +11,13 @@ use HttpServer\Client\Curl; use HttpServer\Client\Http2; use HttpServer\Http\Request; use HttpServer\Http\Response; +use HttpServer\HttpFilter; use HttpServer\Route\Router; use HttpServer\Server; use Kafka\Producer; use Snowflake\Async; use Snowflake\Cache\Redis; +use Snowflake\Crontab; use Snowflake\Error\Logger; use Snowflake\Event; use Snowflake\Jwt\Jwt; @@ -43,6 +45,8 @@ use Snowflake\Pool\Pool as SPool; * @property Producer $kafka * @property Client $client * @property Curl $curl + * @property Crontab $crontab + * @property HttpFilter $filter */ trait TraitApplication { diff --git a/System/Crontab.php b/System/Crontab.php new file mode 100644 index 00000000..d6643327 --- /dev/null +++ b/System/Crontab.php @@ -0,0 +1,40 @@ +getRedis(); + + if (is_array($handler) && is_string($handler[0])) { + $handler[0] = Snowflake::createObject($handler[0]); + } + + $executeTime = time() + $tickTime; + + $crontab = ['isLoop' => $isLoop, 'handler' => $handler, 'tick' => $tickTime]; + + $redis->sAdd('system:crontab', $executeTime, serialize($crontab)); + } + +} diff --git a/System/Process/CrontabProcess.php b/System/Process/CrontabProcess.php new file mode 100644 index 00000000..c6105d33 --- /dev/null +++ b/System/Process/CrontabProcess.php @@ -0,0 +1,91 @@ +channel = new Channel(5000); + + Coroutine::create([$this, 'execute']); + + Timer::tick(1000, [$this, 'systemLoop']); + } + + + /** + * @throws \Exception + */ + public function execute() + { + $redis = Snowflake::app()->getRedis(); + while (true) { + $list = $this->channel->pop(-1); + if (isset($list['isLoop']) && isset($list['tick']) && $list['isLoop'] == 1) { + $redis->zAdd('system:crontab', 0, time() + $list['tick'], serialize($list)); + } + try { + call_user_func($list['handler']); + } catch (\Throwable $throwable) { + $this->application->addError($throwable->getMessage()); + } + $redis->release(); + } + } + + + /** + * @throws ReflectionException + * @throws ComponentException + * @throws ConfigException + * @throws NotFindClassException + * @throws Exception + * @throws \Exception + */ + public function systemLoop() + { + $score = time(); + $redis = Snowflake::app()->getRedis(); + + $lists = $redis->zRangeByScore('system:crontab', $score, $score); + $redis->zRemRangeByScore('system:crontab', $score, $score); + + $barrier = Barrier::make(); + foreach ($lists as $list) { + $list = unserialize($list); + if (!isset($_list['handler']) || !is_callable($_list, true)) { + continue; + } + $this->channel->push($list); + } + Barrier::wait($barrier); + $redis->release(); + } + +}