安装 composer require topthink/think-worker 扩展
配置指令在 app/config/console 文件中定义指令 'timer' => \app\console\command\Timer::class,
配置监听事件 在 app\event 文件中
'listen' => [
// 定时总任务
'MainTask' => [app\console\task\Main::class],
// 定时xx 任务
'Test' => [app\console\task\Test::class]
],
开始创建定时任务目录
1、创建 app\console\command目录,并创建一个Timer.php 文件
<?php
declare (strict_types = 1);
namespace app\console\command;
use think\console\Command;
use think\console\Input;
use think\console\input\Argument;
use think\console\input\Option;
use think\console\Output;
use think\facade\Event;
use Workerman\Worker;
/**
* 定时器 (Workerman)
* 用于执行系统里的定时任务,
* 使用方法: 打开命令行 - 执行命令: php think timer start
* Class Timer
* @package app\common\command
*/
class Timer extends Command
{
// 定时器句柄/ID
protected $timer;
// 时间间隔 (单位: 秒, 默认5秒)
protected $interval = 1;
/**
* 指令配置
* @return void
*/
protected function configure()
{
// 指令配置
$this->setName('timer')
->addArgument('status', Argument::REQUIRED, 'start/stop/reload/status/connections')
->addOption('d', null, Option::VALUE_NONE, 'daemon(守护进程)方式启动')
->addOption('i', null, Option::VALUE_OPTIONAL, '多长时间执行一次')
->setDescription('start/stop/restart 定时任务');
}
/**
* 初始化
* @param Input $input
* @param Output $output
* @return void
*/
protected function init(Input $input, Output $output)
{
global $argv;
if ($input->hasOption('i'))
$this->interval = floatval($input->getOption('i'));
$argv[1] = $input->getArgument('status') ?: 'start';
if ($input->hasOption('d')) {
$argv[2] = '-d';
} else {
unset($argv[2]);
}
}
/**
* 创建定时器
* @param Input $input
* @param Output $output
* @return int|void|null
*/
protected function execute(Input $input, Output $output)
{
$this->init($input, $output);
// 创建定时器任务
$worker = new Worker();
$worker->onWorkerStart = [$this, 'start'];
$worker->runAll();
}
/**
* 定时器执行的内容
* @return false|int
*/
public function start()
{
// 每隔n秒执行一次
return $this->timer = \Workerman\Lib\Timer::add($this->interval, function () {
try {
// 这里执行系统预设的定时任务事件
echo 'timer...' . PHP_EOL;
Event::trigger('MainTask');
} catch (\Throwable $e) {
echo 'ERROR: ' . $e->getMessage() . PHP_EOL;
$this->stop();
}
});
}
/**
* 停止/删除定时器
* @return bool
*/
public function stop()
{
return \Workerman\Lib\Timer::del($this->timer);
}
}
2、创建app\console\task目录,里面创建Task.php、Main.php、Test.php文件。
1.Task.php
<?php
namespace app\console\task;
use think\facade\Cache;
/**
* 定时任务监听器
* Class Listener
* @package app\console\task
*/
class Task
{
/**
* 定时执行任务
* @param string $key
* @param int $expire
* @param callable $callback
*/
protected function setInterval(string $key, int $expire, callable $callback)
{
if (!$this->hasTaskId($key)) {
$this->setTaskId($key, $expire);
return call_user_func($callback);
}
}
/**
* 获取任务ID
* @param string $key
* @return bool
*/
protected function hasTaskId(string $key): bool
{
return Cache::has("Listener:$key");
}
/**
* 设置任务ID
* 用于实现定时任务的间隔时间, 如果任务ID存在并未过期, 则不执行任务
* @param string $key
* @param int $expire 任务ID过期时长(单位:秒)
* @return bool
*/
protected function setTaskId(string $key, int $expire = 60): bool
{
return Cache::set("Listener:$key", true, $expire);
}
}
- Main.php
<?php
namespace app\console\task;
use think\facade\Event;
class Main extends Task
{
/**
* 任务处理
*/
public function handle()
{
Event::trigger('Test',[1,2,3]);
}
}
3.Test.php
<?php
namespace app\console\task;
class Test extends Task
{
// 当前任务唯一标识
private $taskKey = 'xxTest';
// 任务执行间隔时长 (单位:秒)
protected $taskExpire = 10;
/**
* 任务处理
* @param array $param
*/
public function handle(array $param)
{
$this->setInterval($this->taskKey, $this->taskExpire, function () {
echo $this->taskKey . PHP_EOL;
});
}
}