modify
This commit is contained in:
@@ -4,6 +4,8 @@
|
|||||||
namespace Snowflake\Abstracts;
|
namespace Snowflake\Abstracts;
|
||||||
|
|
||||||
|
|
||||||
|
use Snowflake\Core\Json;
|
||||||
|
use Snowflake\Process\CrontabProcess;
|
||||||
use Snowflake\Snowflake;
|
use Snowflake\Snowflake;
|
||||||
use Exception;
|
use Exception;
|
||||||
|
|
||||||
@@ -16,51 +18,40 @@ class Crontab extends Component
|
|||||||
{
|
{
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @param \Snowflake\Crontab $crontab
|
* @param \Snowflake\Crontab $crontab
|
||||||
* @param $executeTime
|
* @param $executeTime
|
||||||
* @throws Exception
|
* @throws Exception
|
||||||
*/
|
*/
|
||||||
public function dispatch(\Snowflake\Crontab $crontab, int $executeTime)
|
public function dispatch(\Snowflake\Crontab $crontab)
|
||||||
{
|
{
|
||||||
$redis = Snowflake::app()->getRedis();
|
/** @var CrontabProcess $redis */
|
||||||
|
$redis = Snowflake::app()->get(CrontabProcess::class);
|
||||||
$redis->zAdd('system:crontab', (string)$executeTime, serialize($crontab));
|
$redis->write(serialize($crontab));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @param string $name
|
* @param string $name
|
||||||
* @throws Exception
|
* @throws Exception
|
||||||
*/
|
*/
|
||||||
public function clear(string $name)
|
public function clear(string $name)
|
||||||
{
|
{
|
||||||
$redis = Snowflake::app()->getRedis();
|
/** @var CrontabProcess $redis */
|
||||||
|
$redis = Snowflake::app()->get(CrontabProcess::class);
|
||||||
$data = $redis->zRevRange('system:crontab', 0, -1);
|
$redis->write(Json::encode(['action' => 'clear', 'name' => $name]));
|
||||||
if (empty($data)) {
|
}
|
||||||
return;
|
|
||||||
}
|
|
||||||
foreach ($data as $datum) {
|
|
||||||
/** @var \Snowflake\Crontab $crontab */
|
|
||||||
$crontab = unserialize($datum);
|
|
||||||
if ($crontab->getName() == $name) {
|
|
||||||
$redis->zRem('system:crontab', $datum);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @throws Exception
|
* @throws Exception
|
||||||
*/
|
*/
|
||||||
public function clearAll()
|
public function clearAll()
|
||||||
{
|
{
|
||||||
$redis = Snowflake::app()->getRedis();
|
/** @var CrontabProcess $redis */
|
||||||
|
$redis = Snowflake::app()->get(CrontabProcess::class);
|
||||||
$redis->del('system:crontab');
|
$redis->write(Json::encode(['action' => 'clearAll']));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
+162
-135
@@ -7,6 +7,7 @@ namespace Snowflake;
|
|||||||
use Closure;
|
use Closure;
|
||||||
use Exception;
|
use Exception;
|
||||||
use Snowflake\Abstracts\BaseObject;
|
use Snowflake\Abstracts\BaseObject;
|
||||||
|
use Swoole\Timer;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Class Async
|
* Class Async
|
||||||
@@ -16,163 +17,189 @@ class Crontab extends BaseObject
|
|||||||
{
|
{
|
||||||
|
|
||||||
|
|
||||||
private array|Closure $handler;
|
private array|Closure $handler;
|
||||||
|
|
||||||
|
|
||||||
private string $name = '';
|
private string $name = '';
|
||||||
|
|
||||||
|
|
||||||
private mixed $params;
|
private mixed $params;
|
||||||
|
|
||||||
|
|
||||||
private int $tickTime = 1;
|
private int $tickTime = 1;
|
||||||
|
|
||||||
|
|
||||||
private bool $isLoop = false;
|
private bool $isLoop = false;
|
||||||
|
|
||||||
|
|
||||||
private int $max_execute_number = -1;
|
private int $timerId = -1;
|
||||||
|
|
||||||
|
|
||||||
private int $execute_number = 0;
|
private int $max_execute_number = -1;
|
||||||
|
|
||||||
/**
|
|
||||||
* @return array|Closure
|
|
||||||
*/
|
|
||||||
public function getHandler(): array|Closure
|
|
||||||
{
|
|
||||||
return $this->handler;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @return string
|
|
||||||
*/
|
|
||||||
public function getName(): string
|
|
||||||
{
|
|
||||||
return $this->name;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @return mixed
|
|
||||||
*/
|
|
||||||
public function getParams(): mixed
|
|
||||||
{
|
|
||||||
return $this->params;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @return int
|
|
||||||
*/
|
|
||||||
public function getTickTime(): int
|
|
||||||
{
|
|
||||||
return $this->tickTime;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @return bool
|
|
||||||
*/
|
|
||||||
public function isLoop(): bool
|
|
||||||
{
|
|
||||||
return $this->isLoop;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @return int
|
|
||||||
*/
|
|
||||||
public function getMaxExecuteNumber(): int
|
|
||||||
{
|
|
||||||
return $this->max_execute_number;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @return int
|
|
||||||
*/
|
|
||||||
public function getExecuteNumber(): int
|
|
||||||
{
|
|
||||||
return $this->execute_number;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
/**
|
private int $execute_number = 0;
|
||||||
* @param array|Closure $handler
|
|
||||||
*/
|
|
||||||
public function setHandler(array|Closure $handler): void
|
|
||||||
{
|
|
||||||
$this->handler = $handler;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @param string $name
|
* @return array|Closure
|
||||||
*/
|
*/
|
||||||
public function setName(string $name): void
|
public function getHandler(): array|Closure
|
||||||
{
|
{
|
||||||
$this->name = $name;
|
return $this->handler;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @param mixed $params
|
* @return string
|
||||||
*/
|
*/
|
||||||
public function setParams(mixed $params): void
|
public function getName(): string
|
||||||
{
|
{
|
||||||
$this->params = $params;
|
return $this->name;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @param int $tickTime
|
* @return mixed
|
||||||
*/
|
*/
|
||||||
public function setTickTime(int $tickTime): void
|
public function getParams(): mixed
|
||||||
{
|
{
|
||||||
$this->tickTime = $tickTime;
|
return $this->params;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @param bool $isLoop
|
* @return int
|
||||||
*/
|
*/
|
||||||
public function setIsLoop(bool $isLoop): void
|
public function getTickTime(): int
|
||||||
{
|
{
|
||||||
$this->isLoop = $isLoop;
|
return $this->tickTime;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @param int $max_execute_number
|
* @return bool
|
||||||
*/
|
*/
|
||||||
public function setMaxExecuteNumber(int $max_execute_number): void
|
public function isLoop(): bool
|
||||||
{
|
{
|
||||||
$this->max_execute_number = $max_execute_number;
|
return $this->isLoop;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @param int $execute_number
|
* @return int
|
||||||
*/
|
*/
|
||||||
public function setExecuteNumber(int $execute_number): void
|
public function getMaxExecuteNumber(): int
|
||||||
{
|
{
|
||||||
$this->execute_number = $execute_number;
|
return $this->max_execute_number;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @return int
|
||||||
|
*/
|
||||||
|
public function getExecuteNumber(): int
|
||||||
|
{
|
||||||
|
return $this->execute_number;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @throws Exception
|
* @param array|Closure $handler
|
||||||
*/
|
*/
|
||||||
public function execute(): void
|
public function setHandler(array|Closure $handler): void
|
||||||
{
|
{
|
||||||
$redis = Snowflake::app()->getRedis();
|
$this->handler = $handler;
|
||||||
try {
|
}
|
||||||
$this->execute_number += 1;
|
|
||||||
call_user_func($this->handler, $this->params);
|
/**
|
||||||
if ($this->isLoop === false) {
|
* @param string $name
|
||||||
return;
|
*/
|
||||||
}
|
public function setName(string $name): void
|
||||||
if ($this->max_execute_number === -1) {
|
{
|
||||||
$redis->zAdd('system:crontab', time() + $this->tickTime, serialize($this));
|
$this->name = $name;
|
||||||
} else if ($this->execute_number < $this->max_execute_number) {
|
}
|
||||||
$redis->zAdd('system:crontab', time() + $this->tickTime, serialize($this));
|
|
||||||
}
|
/**
|
||||||
} catch (\Throwable $throwable) {
|
* @param mixed $params
|
||||||
$this->addError($throwable->getMessage());
|
*/
|
||||||
} finally {
|
public function setParams(mixed $params): void
|
||||||
$redis->release();
|
{
|
||||||
}
|
$this->params = $params;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param int $tickTime
|
||||||
|
*/
|
||||||
|
public function setTickTime(int $tickTime): void
|
||||||
|
{
|
||||||
|
$this->tickTime = $tickTime;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param bool $isLoop
|
||||||
|
*/
|
||||||
|
public function setIsLoop(bool $isLoop): void
|
||||||
|
{
|
||||||
|
$this->isLoop = $isLoop;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param int $max_execute_number
|
||||||
|
*/
|
||||||
|
public function setMaxExecuteNumber(int $max_execute_number): void
|
||||||
|
{
|
||||||
|
$this->max_execute_number = $max_execute_number;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param int $execute_number
|
||||||
|
*/
|
||||||
|
public function setExecuteNumber(int $execute_number): void
|
||||||
|
{
|
||||||
|
$this->execute_number = $execute_number;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @return int
|
||||||
|
*/
|
||||||
|
public function getTimerId(): int
|
||||||
|
{
|
||||||
|
return $this->timerId;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param int $timerId
|
||||||
|
*/
|
||||||
|
public function setTimerId(int $timerId): void
|
||||||
|
{
|
||||||
|
$this->timerId = $timerId;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
public function clearTimer()
|
||||||
|
{
|
||||||
|
$this->warning('crontab timer clear.');
|
||||||
|
if (Timer::exists($this->timerId)) {
|
||||||
|
Timer::clear($this->timerId);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @throws Exception
|
||||||
|
*/
|
||||||
|
public function execute(): void
|
||||||
|
{
|
||||||
|
try {
|
||||||
|
call_user_func($this->handler, $this->params);
|
||||||
|
$this->execute_number += 1;
|
||||||
|
|
||||||
|
if ($this->execute_number < $this->max_execute_number) {
|
||||||
|
$this->clearTimer();
|
||||||
|
}
|
||||||
|
} catch (\Throwable $throwable) {
|
||||||
|
$this->addError($throwable->getMessage());
|
||||||
|
} finally {
|
||||||
|
fire(Event::SYSTEM_RESOURCE_RELEASES);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -5,6 +5,7 @@ namespace Snowflake\Process;
|
|||||||
|
|
||||||
|
|
||||||
use ReflectionException;
|
use ReflectionException;
|
||||||
|
use Snowflake\Core\Json;
|
||||||
use Snowflake\Crontab;
|
use Snowflake\Crontab;
|
||||||
use Snowflake\Exception\ComponentException;
|
use Snowflake\Exception\ComponentException;
|
||||||
use Snowflake\Exception\ConfigException;
|
use Snowflake\Exception\ConfigException;
|
||||||
@@ -23,67 +24,70 @@ use Swoole\Timer;
|
|||||||
class CrontabProcess extends Process
|
class CrontabProcess extends Process
|
||||||
{
|
{
|
||||||
|
|
||||||
|
/** @var Crontab[] $names */
|
||||||
public Channel $channel;
|
public array $names = [];
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @param \Swoole\Process $process
|
* @param \Swoole\Process $process
|
||||||
*/
|
*/
|
||||||
public function onHandler(\Swoole\Process $process): void
|
public function onHandler(\Swoole\Process $process): void
|
||||||
{
|
{
|
||||||
$this->channel = new Channel(5000);
|
while (true) {
|
||||||
|
$content = $process->read();
|
||||||
Coroutine::create([$this, 'execute']);
|
$_content = json_decode($content, true);
|
||||||
|
if (is_null($_content)) {
|
||||||
Timer::tick(1000, [$this, 'systemLoop']);
|
$this->jobDelivery($content);
|
||||||
}
|
} else {
|
||||||
|
$this->otherAction($content);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @throws \Exception
|
* @param $content
|
||||||
*/
|
*/
|
||||||
public function execute()
|
private function otherAction($content)
|
||||||
{
|
{
|
||||||
while (true) {
|
call_user_func(match ($content['action']) {
|
||||||
/** @var Crontab $list */
|
'clear' => function ($content) {
|
||||||
$list = $this->channel->pop(-1);
|
if (!isset($this->names[$content['name']])) {
|
||||||
$list->execute();
|
return;
|
||||||
}
|
}
|
||||||
}
|
$this->names[$content['name']]->clearTimer();
|
||||||
|
},
|
||||||
|
'clearAll' => function () {
|
||||||
|
foreach ($this->names as $name => $crontab) {
|
||||||
|
$crontab->clearTimer();
|
||||||
|
}
|
||||||
|
},
|
||||||
|
default => function () {
|
||||||
|
$this->application->error('unknown action');
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @throws ReflectionException
|
* @param $content
|
||||||
* @throws ComponentException
|
*/
|
||||||
* @throws ConfigException
|
private function jobDelivery($content)
|
||||||
* @throws NotFindClassException
|
{
|
||||||
* @throws Exception
|
$content = unserialize($content);
|
||||||
* @throws \Exception
|
$this->names[$content->getName()] = $content;
|
||||||
*/
|
if (!($content instanceof Crontab)) {
|
||||||
public function systemLoop()
|
return;
|
||||||
{
|
}
|
||||||
$score = time();
|
$runTicker = [$content, 'execute'];
|
||||||
$redis = Snowflake::app()->getRedis();
|
$timer = $content->getTickTime() * 1000;
|
||||||
|
if ($content->isLoop()) {
|
||||||
|
$timerId = Timer::tick($timer, $runTicker);
|
||||||
|
} else {
|
||||||
|
$timerId = Timer::after($timer, $runTicker);
|
||||||
|
}
|
||||||
|
$content->setTimerId($timerId);
|
||||||
|
}
|
||||||
|
|
||||||
$lists = $redis->zRangeByScore('system:crontab', '0', (string)$score);
|
|
||||||
$redis->zRemRangeByScore('system:crontab', '0', (string)$score);
|
|
||||||
|
|
||||||
if (empty($lists)) {
|
|
||||||
$redis->release();
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
$barrier = Barrier::make();
|
|
||||||
foreach ($lists as $list) {
|
|
||||||
$list = unserialize($list);
|
|
||||||
if (!($list instanceof Crontab)) {
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
$this->channel->push($list);
|
|
||||||
}
|
|
||||||
Barrier::wait($barrier);
|
|
||||||
$redis->release();
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user