検索

ホームページ  >  に質問  >  本文

请教PHP+Redis实现任务队列的思路

我的PHP网站程序调用了一个外部网站的接口。
当用户输入数据,PHP程序会接收数据,然后根据数据请求那个外部网站的接口,获得数据返回给用户。
但是当多个用户同时提交数据时,PHP会同时请求那个接口,那个接口就会返回错误。

我现在是想用PHP+Redis做个队列,用户的请求会被放在Redis队列中,逐一去外部接口查询,避免同时请求接口的问题。

具体要怎么实现呢?


高洛峰高洛峰2979日前615

全員に返信(1)返信します

  • 三叔

    三叔2016-11-11 09:50:04

    试试这个

    // 创建请求ID标志, uniqid 无法保证唯一, 自己去搜索生成唯一的方法
    $uuid = uniqid();
    $tsk_name = "mytask";
    $time_out = 30000; // 超时策略: 30秒
    $time_start = time();
    $redis->rPush($tsk_name, $uuid); // 右(后)插入队列
    
    // 堵塞等待队列中第一个和$uuid匹配的(到我了)
    while($uuid != $redis->lGet($tsk_name, 0)){
        if((time()-$time_start)> $time_out) {
            break; // 超时跳出(某些原因队列异常了, 可能永远取不到)
        }
        usleep(10); // sleep 10ms, 再次尝试
    }
    
    // 这里执行任务的处理代码....
    
    // $response 已拼装好要返回的内容
    // 处理完成后(数据库等已入库更新), 需要:
    if($redis->lGet($tsk_name, 0) == $uuid){ // 再次确认第一个是本请求
        $redis->lPop($tsk_name); // 完成任务了, 从队列中移除
    }else{ 
        // 出现这种情况, 是因为超时了, 或前面的$uuid没有被消费
        // 若不清除, 后续的请求, 都将无法正常进入队列执行
        // 取队列中的所有$uuid
        $queues = $redis->lRange($tsk_name, 0, -1);
        foreach($queues as $i=>$uid){
            if($uid==$uuid){ 
                // 队列中仍存在当前的$uuid
                // 清除$uuid以前异常的队列, 让后边的请求得以正常排队
                $redis->lTrim($tsk_name, $i+1, -1);
                break;
            }
        }
    }
     
    // 响应内容
    return $response;

    手打未验证, 思路是这样.

    返事
    0
  • キャンセル返事