tp5使用workerman實現異步任務

問題描述:

採集數據時過程很慢,導致無法繼續進行其他任務,,避免主業務被長時間阻塞,故而將其提交給異步任務,當任務完成通知客戶端即可

流程

前端業務:

由於本系統採用iframe結構,爲避免點擊其他頁面業務中斷,所以業務在父頁面執行,

1.用戶在子頁面點擊採集按鈕調用父級方法

function to_collect(ids) {
        window.parent.startCollect(ids);
    }

2.父級頁面進行socket鏈接,當收到服務器處理完任務消息時關閉socket並通知用戶結果

function startCollect(ids)
    {
        var wsServer = 'ws://127.0.0.1:5432';
        var websocket = new WebSocket(wsServer);
        var inter_val = 0;
        websocket.onopen = function (evt) {
            console.log("Connected to WebSocket server.");
            var data = {ids:ids};
            data = JSON.stringify(data);
            websocket.send(data);

            //設置心跳,避免服務器斷開
            inter_val = setInterval(function () {
                websocket.send('hello');
            }, 50000)
        };

        websocket.onclose = function (evt) {
            console.log("Disconnected");
        };

        websocket.onmessage = function (evt) {
            console.log('Retrieved data from server: ' + evt.data);
            if (isJson(evt.data)) {
                var res = JSON.parse(evt.data);
                if(res.code == 0){
                    alert("採集條數:"+res.msg)
                    websocket.close();
                    clearInterval(inter_val);//關閉定時器
                }
            }



        };

        websocket.onerror = function (evt, e) {
            console.log('Error occured: ' + evt.data);
        };
    }


    /**
     * 判斷是否json
     * @param $string
     * @returns {boolean}
     */
    function isJson($string)
    {
        try {
            if(typeof JSON.parse($string) == 'object')
                return true;
            return false;
        } catch (e) {
            console.log(e);
            return false;

        }
    }

服務端

1. 收到前端發來的數據,調用model進行業務處理,然後通知客戶端

<?php
namespace app\http;

use app\common\model\Collect;
use think\worker\Server;
use Workerman\Lib\Timer;
use Workerman\Worker as W;

class Worker2 extends Server
{
    protected $socket = 'websocket://0.0.0.0:5432';
    protected $option = [
        'count'=> 4,
    ];

    /**
     * 每個進程啓動
     * @param $worker
     */


    public function onWorkerStart($worker)
    {


        // 心跳間隔55秒
        define('HEARTBEAT_TIME', 55);
        Timer::add(1, function()use($worker){
            $time_now = time();
            foreach($worker->connections as $connection) {
                // 有可能該connection還沒收到過消息,則lastMessageTime設置爲當前時間
                if (empty($connection->lastMessageTime)) {
                    $connection->lastMessageTime = $time_now;
                    continue;
                }
                // 上次通訊時間間隔大於心跳間隔,則認爲客戶端已經下線,關閉連接
                if ($time_now - $connection->lastMessageTime > HEARTBEAT_TIME) {
                    $connection->close();
                }
            }
        });
    }

    public function onMessage($connection,$data)
    {
        global $worker;
        // 判斷當前客戶端是否已經驗證,即是否設置了uid
        if(!isset($connection->uid))
        {
            // 沒驗證的話把第一個包當做uid(這裏爲了方便演示,沒做真正的驗證)
            $connection->uid = ip2long($connection->getRemoteIp()).time().rand(1,9999);
            /* 保存uid到connection的映射,這樣可以方便的通過uid查找connection,
             * 實現針對特定uid推送數據
             */
            $worker->uidConnections[$connection->uid] = $connection;
            $connection->send('login success, your uid is ' . $connection->uid);
        }
        $ids = json_decode($data,true)['ids'] ?? 0;
        if ($ids)
        {
            $collect_model = new Collect();
            $res = $collect_model->getNewestArticle($ids);
            $res = json_encode(['code' => 0,'msg' =>$res]);
            $connection->send($res);
        }

        // 給connection臨時設置一個lastMessageTime屬性,用來記錄上次收到消息的時間
        $connection->lastMessageTime = time();
        //$connection->send('receive success');
        echo $data;
        echo "\n";
    }

    public function onConnect($connection)
    {

    }

    /**
     * 當連接斷開時觸發的回調函數
     * @param $connection
     */
    public function onClose($connection)
    {
        global $worker;
        if(isset($connection->uid))
        {
            // 連接斷開時刪除映射
            unset($worker->uidConnections[$connection->uid]);
        }
    }
    /**
     * 當客戶端的連接上發生錯誤時觸發
     * @param $connection
     * @param $code
     * @param $msg
     */
    public function onError($connection, $code, $msg)
    {
        echo "error $code $msg\n";
    }


    // 針對uid推送數據
    public function sendMessageByUid($uid, $message)
    {
        global $worker;
        if(isset($worker->uidConnections[$uid]))
        {
            $connection = $worker->uidConnections[$uid];
            $connection->send($message);
            return true;
        }
        return false;
    }


}

啓動  workerman

執行結果

thinkphp5中如何開啓workman請參照https://blog.csdn.net/flysnownet/article/details/96475927

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章