CodeIgniter框架怎么使用队列任务

来源:网站主作者:深圳SEO公司头衔:草根站长
导读:本期聚焦于小伙伴创作的《CodeIgniter框架怎么使用队列任务》,敬请观看详情,探索知识的价值。以下视频、文章将为您系统阐述其核心内容与价值。如果您觉得《CodeIgniter框架怎么使用队列任务》有用,将其分享出去将是对创作者最好的鼓励。

在CodeIgniter框架中处理队列任务,核心是将耗时操作从主请求流程中剥离,先记录任务信息,再由独立的进程异步执行,这样能避免用户请求等待耗时操作完成,提升系统整体体验。常见的实现方式有两种,一种是轻量级的基于数据库的任务队列,适合中小型项目;另一种是结合Redis、RabbitMQ等第三方消息队列服务,适合高并发场景。

CodeIgniter框架怎么使用队列任务

方案一:基于数据库的简单队列实现

这种方式不需要引入额外的服务,仅通过数据库表存储任务信息,适合任务量不大、对实时性要求不高的场景。

1. 创建任务队列表

首先需要在数据库中创建一张存储队列任务的表,结构如下:

CREATE TABLE `ci_queue_tasks` (
  `id` int(11) NOT NULL AUTO_INCREMENT,
  `task_type` varchar(50) NOT NULL COMMENT '任务类型,比如send_email、generate_report',
  `task_data` text NOT NULL COMMENT '任务相关数据,json格式存储',
  `status` tinyint(1) NOT NULL DEFAULT '0' COMMENT '0待处理 1处理中 2处理完成 3处理失败',
  `create_time` int(11) NOT NULL COMMENT '任务创建时间戳',
  `update_time` int(11) DEFAULT NULL COMMENT '任务更新时间戳',
  `retry_count` int(11) NOT NULL DEFAULT '0' COMMENT '重试次数',
  PRIMARY KEY (`id`),
  KEY `idx_status` (`status`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8;

2. 封装队列任务操作类

在CodeIgniter的libraries目录下创建Queue类,封装任务的添加、获取、更新状态等方法:

<?php
defined('BASEPATH') OR exit('No direct script access allowed');

class Queue {
    protected $CI;
    protected $table = 'ci_queue_tasks';

    public function __construct() {
        $this->CI =& get_instance();
        $this->CI->load->database();
    }

    /**
     * 添加队列任务
     * @param string $task_type 任务类型
     * @param array $task_data 任务数据
     * @return int 新增任务ID
     */
    public function add_task($task_type, $task_data) {
        $data = array(
            'task_type' => $task_type,
            'task_data' => json_encode($task_data, JSON_UNESCAPED_UNICODE),
            'status' => 0,
            'create_time' => time(),
            'retry_count' => 0
        );
        $this->CI->db->insert($this->table, $data);
        return $this->CI->db->insert_id();
    }

    /**
     * 获取待处理的任务
     * @param int $limit 每次获取的任务数量
     * @return array 任务列表
     */
    public function get_pending_tasks($limit = 10) {
        $this->CI->db->where('status', 0);
        $this->CI->db->order_by('create_time', 'ASC');
        $this->CI->db->limit($limit);
        $query = $this->CI->db->get($this->table);
        return $query->result_array();
    }

    /**
     * 更新任务状态
     * @param int $task_id 任务ID
     * @param int $status 目标状态
     * @param string $error_msg 错误信息,失败时记录
     * @return bool 是否更新成功
     */
    public function update_task_status($task_id, $status, $error_msg = '') {
        $update_data = array(
            'status' => $status,
            'update_time' => time()
        );
        if ($status == 3 && $error_msg != '') {
            $update_data['task_data'] = json_encode(array('error' => $error_msg), JSON_UNESCAPED_UNICODE);
        }
        $this->CI->db->where('id', $task_id);
        return $this->CI->db->update($this->table, $update_data);
    }

    /**
     * 增加任务重试次数
     * @param int $task_id 任务ID
     * @return bool 是否更新成功
     */
    public function increment_retry($task_id) {
        $this->CI->db->set('retry_count', 'retry_count+1', FALSE);
        $this->CI->db->where('id', $task_id);
        return $this->CI->db->update($this->table);
    }
}

3. 业务层添加任务

在需要添加队列任务的地方,比如用户注册后发送欢迎邮件,调用Queue类添加任务:

<?php
defined('BASEPATH') OR exit('No direct script access allowed');

class User extends CI_Controller {
    public function register() {
        // 假设用户注册逻辑已完成,获取到用户邮箱
        $user_email = 'test@ipipp.com';
        // 加载队列库
        $this->load->library('queue');
        // 添加发送邮件的队列任务
        $task_data = array(
            'email' => $user_email,
            'subject' => '欢迎注册',
            'content' => '感谢您的注册,祝您使用愉快'
        );
        $task_id = $this->queue->add_task('send_email', $task_data);
        if ($task_id > 0) {
            echo '注册成功,邮件将在后台发送';
        } else {
            echo '注册成功,但邮件任务添加失败';
        }
    }
}

4. 编写命令行脚本处理任务

CodeIgniter支持命令行运行控制器,我们可以创建一个命令行控制器来处理队列任务,然后通过定时任务或者守护进程调用这个控制器。

首先在application/controllers目录下创建Cli目录,然后创建Queue_worker.php:

<?php
defined('BASEPATH') OR exit('No direct script access allowed');

class Queue_worker extends CI_Controller {
    public function __construct() {
        parent::__construct();
        // 仅允许命令行访问
        if (!$this->input->is_cli_request()) {
            exit('该控制器仅允许命令行访问');
        }
        $this->load->library('queue');
    }

    /**
     * 处理队列任务的主方法
     */
    public function run() {
        $max_retry = 3; // 最大重试次数
        while (true) {
            // 获取待处理任务
            $tasks = $this->queue->get_pending_tasks(10);
            if (empty($tasks)) {
                // 没有任务时休眠5秒
                sleep(5);
                continue;
            }
            foreach ($tasks as $task) {
                // 标记任务为处理中
                $this->queue->update_task_status($task['id'], 1);
                $task_data = json_decode($task['task_data'], TRUE);
                $result = FALSE;
                try {
                    // 根据任务类型处理不同任务
                    switch ($task['task_type']) {
                        case 'send_email':
                            $result = $this->handle_send_email($task_data);
                            break;
                        case 'generate_report':
                            $result = $this->handle_generate_report($task_data);
                            break;
                        default:
                            throw new Exception('未知的任务类型');
                    }
                } catch (Exception $e) {
                    // 处理失败,记录错误
                    $this->queue->update_task_status($task['id'], 3, $e->getMessage());
                    // 如果重试次数未达上限,重置状态为待处理
                    if ($task['retry_count'] < $max_retry) {
                        $this->queue->increment_retry($task['id']);
                        $this->queue->update_task_status($task['id'], 0);
                    }
                    continue;
                }
                // 处理成功,标记任务完成
                if ($result) {
                    $this->queue->update_task_status($task['id'], 2);
                } else {
                    $this->queue->update_task_status($task['id'], 3, '任务处理返回失败');
                }
            }
        }
    }

    /**
     * 处理发送邮件任务
     * @param array $data 任务数据
     * @return bool 是否处理成功
     */
    private function handle_send_email($data) {
        $this->load->library('email');
        $this->email->from('system@ipipp.com', '系统通知');
        $this->email->to($data['email']);
        $this->email->subject($data['subject']);
        $this->email->message($data['content']);
        return $this->email->send();
    }

    /**
     * 处理生成报表任务
     * @param array $data 任务数据
     * @return bool 是否处理成功
     */
    private function handle_generate_report($data) {
        // 这里写生成报表的具体逻辑,比如查询数据、生成excel等
        // 示例仅返回true模拟成功
        return TRUE;
    }
}

然后通过命令行启动队列 worker:

php /path/to/your/codeigniter/index.php cli/queue_worker run

如果需要后台常驻运行,可以配合nohup或者supervisor工具管理进程。

方案二:结合Redis实现队列

如果项目并发量较高,基于数据库的队列可能存在性能瓶颈,这时候可以使用Redis的list结构实现队列,Redis的lpush和rpop操作是原子性的,性能更好。

1. 安装Redis扩展并配置

首先确保服务器安装了Redis,并且PHP安装了redis扩展,然后在CodeIgniter的config目录下创建redis.php配置文件:

<?php
defined('BASEPATH') OR exit('No direct script access allowed');

$config['redis_host'] = '127.0.0.1';
$config['redis_port'] = 6379;
$config['redis_password'] = '';
$config['redis_database'] = 0;
$config['redis_timeout'] = 0;

2. 封装Redis队列操作类

在libraries目录下创建Redis_queue类:

<?php
defined('BASEPATH') OR exit('No direct script access allowed');

class Redis_queue {
    protected $CI;
    protected $redis;
    protected $queue_key = 'ci_queue_tasks';

    public function __construct() {
        $this->CI =& get_instance();
        $this->CI->config->load('redis', TRUE);
        $redis_config = $this->CI->config->item('redis');
        $this->redis = new Redis();
        $this->redis->connect($redis_config['redis_host'], $redis_config['redis_port'], $redis_config['redis_timeout']);
        if ($redis_config['redis_password'] != '') {
            $this->redis->auth($redis_config['redis_password']);
        }
        $this->redis->select($redis_config['redis_database']);
    }

    /**
     * 添加任务到队列
     * @param string $task_type 任务类型
     * @param array $task_data 任务数据
     * @return int 队列长度
     */
    public function push_task($task_type, $task_data) {
        $task = array(
            'task_type' => $task_type,
            'task_data' => $task_data,
            'create_time' => time()
        );
        return $this->redis->lPush($this->queue_key, json_encode($task, JSON_UNESCAPED_UNICODE));
    }

    /**
     * 从队列获取任务
     * @param int $timeout 阻塞超时时间,0表示不阻塞
     * @return array|bool 任务信息,没有任务返回false
     */
    public function pop_task($timeout = 0) {
        if ($timeout > 0) {
            $result = $this->redis->brPop(array($this->queue_key), $timeout);
            if (empty($result)) {
                return FALSE;
            }
            $task_json = $result[1];
        } else {
            $task_json = $this->redis->rPop($this->queue_key);
        }
        if (!$task_json) {
            return FALSE;
        }
        return json_decode($task_json, TRUE);
    }
}

3. 业务层添加任务

<?php
defined('BASEPATH') OR exit('No direct script access allowed');

class Order extends CI_Controller {
    public function create() {
        // 订单创建逻辑
        $order_id = 123;
        $this->load->library('redis_queue');
        // 添加订单后续处理任务,比如扣库存、发通知
        $task_data = array('order_id' => $order_id);
        $this->redis_queue->push_task('handle_order', $task_data);
        echo '订单创建成功';
    }
}

4. 编写Redis队列 worker

同样创建命令行控制器处理Redis队列任务:

<?php
defined('BASEPATH') OR exit('No direct script access allowed');

class Redis_queue_worker extends CI_Controller {
    public function __construct() {
        parent::__construct();
        if (!$this->input->is_cli_request()) {
            exit('该控制器仅允许命令行访问');
        }
        $this->load->library('redis_queue');
    }

    public function run() {
        while (true) {
            // 阻塞获取任务,超时时间30秒
            $task = $this->redis_queue->pop_task(30);
            if (!$task) {
                continue;
            }
            try {
                switch ($task['task_type']) {
                    case 'handle_order':
                        $this->handle_order($task['task_data']);
                        break;
                    default:
                        throw new Exception('未知任务类型');
                }
            } catch (Exception $e) {
                // 记录错误日志
                log_message('error', '队列任务处理失败:' . $e->getMessage());
            }
        }
    }

    private function handle_order($data) {
        // 处理订单的具体逻辑
        return TRUE;
    }
}

两种方案对比

两种方案各有适用场景,具体对比如下:

对比项数据库队列Redis队列
实现复杂度低,无需额外服务中等,需要安装Redis
性能一般,适合低并发

CodeIgniter队列任务后台任务处理消息队列修改时间:2026-07-23 23:10:03

免责声明:​ 已尽一切努力确保本网站所含信息的准确性。网站内容多为原创整理与精心编撰,观点力求客观中立。本站旨在免费分享,内容仅供个人学习、研究或参考使用。若引用了第三方作品,版权归原作者所有。如内容涉及您的权益,请联系我们处理。
内容垂直聚焦
专注技术核心技术栏目,确保每篇文章深度聚焦于实用技能。从代码技巧到架构设计,为用户提供无干扰的纯技术知识沉淀,精准满足专业提升需求。
知识结构清晰
覆盖从开发到部署的全链路。AI、前端、编程、数据库、服务器、建站、系统层层递进,构建清晰学习路径,帮助用户系统化掌握开发与运维所需的核心技术。
深度技术解析
拒绝泛泛而谈,深入技术细节与实践难点。无论是数据库优化还是服务器配置,均结合真实场景与代码示例进行剖析,致力于提供可直接应用于工作的解决方案。
专业领域覆盖
精准对应开发生命周期。从前端界面到后端编程,从数据库操作到服务器运维,形成完整闭环,一站式满足全栈工程师和运维人员的技术需求。
即学即用高效
内容强调实操性,步骤清晰、代码完整。用户可根据教程直接复现和应用于自身项目,显著缩短从学习到实践的距离,快速解决开发中的具体问题。
持续更新保障
专注既定技术方向进行长期、稳定的内容输出。确保各栏目技术文章持续更新迭代,紧跟主流技术发展趋势,为用户提供经久不衰的学习价值。