异步延时任务

基于redis的异步延时任务

项目中有时候经常用到到特定时间去执行的任务,比如订单15分钟取消,3天发货提醒等等,如果利用crontab直接去查找数据库数据有点太过浪费,因而考虑使用redis去存储这些任务,然后crontab执行,效果就好得多。

废话不多说,上代码。

// 异步延时任务抽象类,所有异步延时任务继承他
<?php
/**
 * User: 13sai
 * Date: 2018/9/1
 * Time: 16:35
 */
namespace DelayTask;
abstract class DelayTask
{
    const DELAY_TASK = 'delayTask';
    /**
     * 延时时间
     * @param $pushDelayTime
     */
    public function startAfter(int $pushDelayTime)
    {
        RedisManager::getRedis()->zAdd(self::DELAY_TASK, time() + $pushDelayTime, serialize($this));
    }
    /**
     * 定时时间
     * @param $pushDelayAt
     */
    public function startAt(int $pushDelayAt)
    {
        RedisManager::getRedis()->zAdd(self::DELAY_TASK, $pushDelayAt, serialize($this));
    }
    /**
     * 实际执行的动作
     */
    abstract function run();
}


// 测试类,继承抽象类
<?php
/**
 * User: 13sai
 * Date: 2018/9/1
 * Time: 17:55
 */
class TestDelayTask extends DelayTask
{
    public function __construct($id)
    {
        $this->id = $id;
    }
    public function run()
    {
        $file  = 'text.txt';//要写入文件的文件名(可以是任意文件名),如果文件不存在,将会创建一个
        $content = "写入的内容".time()."\n";
        if($f = file_put_contents($file, $content,FILE_APPEND)){// 这个函数支持版本(PHP 5)
            echo "写入成功。<br />";
        }
    }
}
复制代码

其中有个RedisManager,简单封装了一下redis操作,主要利用了有序集合。

<?php
/**
 * User: 13sai
 * Date: 2018/9/1
 * Time: 16:36
 */
class RedisManager
{
    private static $_instance = null;
    private function __construct()
    {
        self::$_instance = new \Redis();
        $config = require 'redis.config.php'; //配置可自行修改
        self::$_instance->connect($config['host'], $config['port'], $config['timeout']);
        if (isset($config['password'])) {
            self::$_instance->auth($config['password']);
        }
    }
    /**
     * 获取静态实例
     */
    public static function getRedis()
    {
        if (!self::$_instance) {
            new self;
        }
        return self::$_instance;
    }
    /**
     * 禁止clone
     */
    private function __clone()
    {
    }
}
复制代码

插入延时任务:

(new TestDelayTask(4))->startAfter(120);
(new TestDelayTask(3))->startAt(153120384);
复制代码

我没创建一个任务,来执行上面的测试类:

<?php
/**
 * User: 13sai
 * Date: 2018/9/5
 * Time: 12:00
 */
class DelayTaskTask
{
    const QueneName = 'delayTask';
    private $currentTime;
    private $once = 5;
    public function run()
    {
        $this->currentTime = time();
        while (true) {
            // 每次取出5条,可适当调整,内存不要占用过大即可
            $list = RedisManager::getRedis()->zRange(self::QueneName, 0, $this->once, true);
            if (!empty($list)) {
                foreach ($list as $val=>$score) {
                    if ($score < $this->currentTime) {
                        unserialize($val)->run();
                        RedisManager::getRedis()->zDelete(self::QueneName, $val);
                    } else {
                        break 2;
                    }
                }
            } else {
                break;
            }
        }
    }
}
复制代码

我没只需要创建一个任务,每分钟执行上面的DelayTaskTask的run方法即可。

tips:注意每次插入任务的实例务必不同,否则在redis会被覆盖掉。

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值