問題描述:
採集數據時過程很慢,導致無法繼續進行其他任務,,避免主業務被長時間阻塞,故而將其提交給異步任務,當任務完成通知客戶端即可
流程
前端業務:
由於本系統採用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