php swoole 多程序傳送微信模板訊息\郵件
年前接到需求做了一個功能,給快到期的微信使用者傳送模板訊息,提醒續費.
首先拿到快到期的使用者, 每天大概800-2000不等,感覺壓力不是很大,直接foreach 陣列 然後傳送,經常出現請求超時 也就是502的問題,緊接著運營同事提出要針對一大批使用者 推模板訊息,年前搞一波促銷,量每天在1萬左右,於是楞沖沖的 直接做了個上傳功能,給運營人員直接上傳發送,然後用是無限的502bad way.
此時 ,感覺模板訊息數量上去了,需要優化,於是採用另外一種方案,redis佇列+守護程序,將上傳的資料跟傳送的解耦, 守護程序檢測redis佇列中是否存在需要傳送的資料,如果存在就開始 一條條往外取,然後傳送.此方案感覺是運營人員不用管結果,肯定能傳送成功,但是時間比較長,量大了 很長時間才發完, 那麼就出現了另外一個問題,發出去的時間不用,想在使用者開啟微信的最高峰時間段傳送給使用者.好繼續優化!
此時改用php+swoole 來進行多程序非同步處理,既然一個程序慢,那咱就多開幾個,於是16個程序一起非同步傳送,1萬模板訊息 10分鐘之內發完,基本改造完成.
下面貼出程式碼 demo
首先啟動server.php
客戶端
class Client
{
public function send($msg){
$client = new swoole_client(SWOOLE_SOCK_TCP);
//連線到伺服器
if (!$client->connect('127.0.0.1', 9501, 0.5))
{
$this->write("connect failed.");
}
//向伺服器傳送資料
if (!$client->send($msg))
{
$this->write("send ".$msg." failed.");
}
//關閉連線
$client->close();
}
private function write($str){
$path = "/sys.log";
$str = "[".date("Y-m-d H:i:s")."]".$str;
$str .= PHP_EOL;
file_put_contents($path,$str,FILE_APPEND);
}
}
服務端
<?php
$serv = new swoole_server("127.0.0.1", 9501);
//設定非同步任務的工作程序數量
$serv->set(array('task_worker_num' =>16));
//監聽資料接收事件
$serv->on('receive', function($serv, $fd, $from_id, $data) {
//投遞非同步任務
$task_id = $serv->task($data);//非阻塞
echo "同步程式碼執行完成\n";
});
//處理非同步任務
$serv->on('task', function ($serv, $task_id, $from_id, $data) {
handleFun($data);
//返回任務執行的結果
$serv->finish("finish");
});
//處理非同步任務的結果
$serv->on('finish', function ($serv, $task_id, $data) {
echo "非同步任務執行完成";
});
$serv->start();
function handleFun($data){
$data=json_decode($data,true);
foreach ($data as $key => $value) {
echo json_encode($value);
$url="xxxx";//呼叫傳送模板訊息介面,服務端沒辦法直接獲取微信的介面的一些資料,此處做了一些加密
$postUrl = $url;
$curlPost = $value;
$ch = curl_init(); //初始化curl
curl_setopt($ch, CURLOPT_URL, $postUrl); //抓取指定網頁
curl_setopt($ch, CURLOPT_HEADER, 0); //設定header
curl_setopt($ch, CURLOPT_RETURNTRANSFER, 1); //要求結果為字串且輸出到螢幕上
curl_setopt($ch, CURLOPT_POST, 1); //post提交方式
curl_setopt($ch, CURLOPT_POSTFIELDS, $curlPost);
$data = curl_exec($ch); //執行curl
curl_close($ch);
}
}
呼叫client.php
<?php
include dirname(__FILE__).'/client.php';
$params=""//介面資料
$msg = json_encode($params);
$client = new Client();$client->send($msg);
echo "[".date("Y-m-d H:i:s")."]執行完成".PHP_EOL;