/** * 所有聊天消息和广播消息都压入到redis队列中 */ public static function msgIntoQueue($msgData) { Redisq::rpush(array('serverName' => 'webChat', 'key' => Storekey::MSG_CHAT_LIST, 'value' => serialize($msgData))); }
public static function mqHander($paramArr) { $options = array('queueType' => 'RedisQ', 'serverName' => 'ResysQ', 'queueName' => '', 'jobName' => '', 'cnName' => '', 'function' => false, 'msgNumAtm' => 10, 'maxSleep' => 30, 'adminMail' => '', 'eagleeyeDb' => 'Eagleeye', 'phpFile' => '', 'life' => 0); if (is_array($paramArr)) { $options = array_merge($options, $paramArr); } foreach ($options as $k => $v) { #下面有sql操作,防注入处理 $options[$k] = addslashes($v); } extract($options); if (!$function || !function_exists($function)) { echo "[ERROR]数据处理函数function有误!"; return false; } if (!$queueName) { echo "[ERROR]消息队列名称不可为空!"; return false; } if (!$jobName) { $jobName = $queueName; } $sleepSec = 0; $startTm = 0; $life = (int) $life; $maxSleep = (int) $maxSleep > 10 ? (int) $maxSleep : 10; if (isset($_SERVER['SERVER_ADDR'])) { $serverIp = $_SERVER['SERVER_ADDR']; #当前服务器的IP } else { if (isset($_SERVER['SSH_CONNECTION'])) { $serverIp = explode(" ", $_SERVER['SSH_CONNECTION']); } $serverIp = isset($serverIp) ? $serverIp[2] : ''; #当前服务器的IP } $runCnt = 0; $lifeStartTm = time(); #计算生命期用 #采用始终循环的方式进行处理 while (true) { #从队列中获得数据 if ('RedisQ' == $queueType) { #判断队列的类型 $dataArr = Redisq::pops(array('serverName' => $serverName, 'key' => $queueName, 'num' => $msgNumAtm)); } if ($dataArr) { foreach ($dataArr as $d) { #执行要调用的函数 $function($d); $runCnt++; #记录处理消息的个数 } $sleepSec = 0; } else { $sleepSec = intval(($sleepSec + 2) % $maxSleep); #递增,但限制最大sleep数字,不可等待过长 if ($sleepSec == 0) { $sleepSec = 1; } sleep($sleepSec); } #定时将自动运行的存活状态记录到数据库主中,便于监控和统计 #用这种方法模拟心跳,让监控程序知道这循环还活着 $tm = time(); $mustDie = $life && $tm - $lifeStartTm > $life ? true : false; #判断生命期,是否该结束了 if ($tm - $startTm > 240 || $mustDie) { $db = \GatewayWorker\Lib\Db::instance($eagleeyeDb); #便于记录运行状态用 $startTm = $tm; $nowD = date("d"); $sql = "select * from queue_deamon_status where job_name = '{$jobName}' and queue_name = '{$queueName}' "; $info = $db->query($sql); if ($info && is_array($info)) { $info = $info[0]; #因为我用的是workerman自带的mysql操作 #获得当天处理的消息数量 $todaycnt = $info['msgcnt_date'] != $nowD ? $runCnt : 'msgcnt_day + ' . $runCnt; $sql = "update queue_deamon_status\n set tm = '{$tm}',server = '{$serverIp}',func='{$function}',filepath='{$phpFile}',admin='{$adminMail}',dostop=0,\n msgcnt_all = msgcnt_all + {$runCnt} , msgcnt_day = {$todaycnt},msgcnt_date='{$nowD}',cnname='{$cnName}'\n where job_name = '{$jobName}' and queue_name = '{$queueName}' "; $db->query($sql); #判断是否要停止,这个标志在后台中设置 if ((int) $info["dostop"]) { echo "手动设置了停止"; exit; } $runCnt = 0; } else { $sql = "insert into queue_deamon_status(job_name,queue_name,tm,server,func,filepath,admin,msgcnt_date,cnname)\n values('{$jobName}','{$queueName}',{$tm},'{$serverIp}','{$function}','{$phpFile}','{$adminMail}','{$nowD}','{$cnName}') "; $db->query($sql); } } #判断生命期 if ($mustDie) { exit; #生命结束,期待crontab } } }
/** * 保留每路最新的n条message(历史消息),到redis中 */ function storeMessageList($data) { if ($data['type'] == \Config\St\Storekey::BROADCAST_MSG_TYPE) { return false; } Redisq::lpush(array('serverName' => 'webChat', 'key' => $data['chatid'] . \Config\St\Storekey::MSG_HISTORY, 'value' => serialize($data))); //保存最新20条 Redisq::ltrim(array('serverName' => 'webChat', 'key' => $data['chatid'] . \Config\St\Storekey::MSG_HISTORY, 'offset' => 0, 'len' => 20)); }
/** * 获取某路聊天的最近的历史消息 */ public static function getHistoryMsg($chatid) { $historyList = \Vendors\Redis\Redisq::range(array('serverName' => 'webChat', 'key' => $chatid . \Config\St\Storekey::MSG_HISTORY, 'offset' => 0, 'len' => -1)); if (!$historyList) { return false; } $historyList = array_reverse($historyList, false); //反序,并丢弃原键名 foreach ($historyList as $key => $val) { $historyList[$key] = unserialize($val); } return $historyList; }