• 定时器
    • 循环执行
      • 函数原型
      • 示例代码
    • 延时执行
      • 函数原型
      • 示例代码
    • 清除定时器
      • 函数原型
      • 示例代码
    • 应用实例
      • 经典案例-订单状态超时监控

    定时器

    框架对原生的毫秒级定时器进行了封装,以便开发者快速调用 Swoole 的原生定时器,定时器类的命名空间为 EasySwoole\Component\Timer

    注意: 定时器传入的时间参数单位为毫秒 按秒执行一定不要忘记 乘以 1000

    循环执行

    设置一个间隔时钟定时器,每隔一定的时间定时触发,直到进行 clear 操作才会停止,对应 Swoole 原生的定时器函数为 swoole_timer_tick

    函数原型

    1. /**
    2. * 循环调用
    3. * @param int $microSeconds 循环执行的间隔毫秒数 传入整数型
    4. * @param \Closure $func 定时器需要执行的操作 传入一个闭包
    5. * @param string $name 定时器名称,用于取消该定时器
    6. * @return int 返回整数型的定时器编号 可以用该编号停止定时器
    7. */
    8. public function loop($microSeconds, \Closure $func, $args = null)

    示例代码

    1. // 每隔 10 秒执行一次
    2. \EasySwoole\Component\Timer::getInstance()->loop(10 * 1000, function () {
    3. echo "this timer runs at intervals of 10 seconds\n";
    4. });

    延时执行

    设置一个延时定时器,延时指定的时间后触发对应的操作,只会执行一次操作,对应 Swoole 原生的定时器函数为 swoole_timer_after

    函数原型

    1. /**
    2. * 延时调用
    3. * @param int $microSeconds 需要延迟执行的时间
    4. * @param \Closure $func 定时器需要执行的操作 传入一个闭包
    5. * @return int 返回整数型的定时器编号
    6. */
    7. public function after($microSeconds, \Closure $func)

    示例代码

    1. // 10 秒后执行一次
    2. \EasySwoole\Component\Timer::getInstance()->after(10 * 1000, function () {
    3. echo "ten seconds later\n";
    4. });

    清除定时器

    注意: 该操作不能用于清除其他进程的定时器,只作用于当前进程

    定时器创建成功时,会返回一个整数型编号,调用本函数传入该编号,即可提前停止定时器,对应 Swoole 原生的定时器函数为 swoole_timer_clear

    函数原型

    1. /**
    2. * 清除定时器
    3. * @param int $timerId|$timeName 定时器编号或名称
    4. * @author : evalor <master@evalor.cn>
    5. */
    6. public function clear($timerId)

    示例代码

    1. // 创建一个2秒定时器
    2. $timerId = \EasySwoole\Component\Timer::getInstance()->loop(2 * 1000, function () {
    3. echo "timeout\n";
    4. },'time');
    5. // 清除该定时器
    6. //var_dump(\EasySwoole\Component\Timer::getInstance()->clear($timerId)); // bool(true)
    7. var_dump($timerId); // int(1)
    8. // 定时器得不到执行 不输出:timeout

    若开启了reload_async配置时,请将定时器移动到自定义进程中,否则会导致worker进程无法reload

    应用实例

    注意:定时器不能在服务启动之前使用。在服务启动以后,添加的定时器仅仅在当前进程中有效。在workerStart事件中添加定时器时,请注意判断需要添加定时器的workerId,否在该定时器在每个进程中均会被执行

    1. // 为第一个 Worker 添加定时器
    2. if ($workerId == 0) {
    3. \EasySwoole\Component\Timer::getInstance()->loop(10 * 1000, function () {
    4. echo "timer in the worker number 0\n";
    5. });
    6. }
    1. public static function mainServerCreate(EventRegister $register)
    2. {
    3. $register->add(EventRegister::onWorkerStart, function (\swoole_server $server, $workerId) {
    4. //如何避免定时器因为进程重启而丢失
    5. //例如在第一个进程 添加一个10秒的定时器
    6. if ($workerId == 0) {
    7. \EasySwoole\Component\Timer::getInstance()->loop(10 * 1000, function () {
    8. // 从数据库,或者是redis中,去获取下个就近10秒内需要执行的任务
    9. // 例如:2秒后一个任务,3秒后一个任务 代码如下
    10. \EasySwoole\Component\Timer::getInstance()->loop(2 * 1000, function () {
    11. //为了防止因为任务阻塞,引起定时器不准确,把任务给异步进程处理
    12. Logger::getInstance()->console("time 2", false);
    13. });
    14. \EasySwoole\Component\Timer::getInstance()->after(3 * 1000, function () {
    15. //为了防止因为任务阻塞,引起定时器不准确,把任务给异步进程处理
    16. Logger::getInstance()->console("time 3", false);
    17. });
    18. });
    19. }
    20. });
    21. }

    经典案例-订单状态超时监控

    场景说明:在很多抢购的场景中,订单下单完成后,需要限制其付款时间,或者是在棋牌游戏中,需要对房间状态进行监控。那么我们
    可以先把待监控的订单或者是房间压入redis队列中。那么利用定时器+异步进程,去实现对订单状态的循环监控。