Swoole筆記(二)


本文示例代碼詳見:https://github.com/52fhy/swoole_demo。

重新打開日志

在1.8.11及之后版本支持重新打開日志:向Server主進程發送SIGRTMIN信號。假設主進程id是3427,那么我們可以:

kill -34 3427

注:SIGRTMIN信號的id是34。通過kill -l查看。

那么如何利用這個特征實現每天自動寫入新的日志文件里面呢?

假設日志文件是/log/swoole.log,我們可以在每天0點運行shell命令:

mv /log/swoole.log /log/$(date -d '-1 day' +%y-%m-%d).log
kill -34 $(ps aux|grep swoole_task|grep swoole_task_matser|grep -v grep|awk '{print $2}') # 找到主進程,需要提前命名

我們也可以把master進程的PID寫入到文件

$server->set(array(
    'pid_file' => __DIR__.'/server.pid',
));

在Server關閉時自動刪除PID文件。此選項在1.9.5或更高版本可用。

信號管理

Swoole支持的信號:

SIGKILL -9 pid 強制殺掉進程
SIGUSR1 -10 master_pid 重啟所有worker進程
SIGUSR2 -12 master_pid 重啟所有task_worker進程
SIGRTMIN -34 master_pid 重新打開日志(版本1.8.11+)

master_pid代表主進程pid。示例(假設主進程名稱是swoole_server,pid是3427):

# 殺掉進程swoole_server
kill -9 $(ps aux|grep swoole_server|grep -v grep|awk '{print $2}')

# 重啟swoole_server的worker進程
kill -10 $(ps aux|grep swoole_server|grep -v grep|awk '{print $2}')

# 重新打開日志
kill -34 3427

Task

我們可以在worker進程中投遞一個異步任務到task_worker池中。此函數是非阻塞的,執行完畢會立即返回。worker進程可以繼續處理新的請求。

通常會把耗時的任務交給task_worker來處理。

我們可以通過如下代碼判斷是Worker進程還是TaskWorker進程:

function onWorkerStart($serv, $worker_id) {
    if ($worker_id >= $serv->setting['worker_num']) {  //超過worker_num,表示這是一個task進程

    }
}

看一個示例:

<?php
$server = new \swoole_server("127.0.0.1",8088);

$server->set(array(
	'daemonize' => false,
	'reactor_num' => 2,
	'worker_num' => 1,
	'task_worker_num' => 1,
));

$server->on('start', function ($serv){ 
	swoole_set_process_name("swoole_task_matser"); //主進程命名
});

$server->on('connect', function ($serv, $fd){ 
	echo "client connect. fd is {$fd}\n";
});

$server->on('receive', function ($serv, $fd, $from_id, $data){
	
	echo sprintf("onReceive. fd: %d , data: %s\n", $fd, json_encode($data) );
	
	$serv->task(json_encode([
		'fd' => $fd,
		'task_name' => 'send_email',
		'email_content' => $data,
		'email' => 'admin@qq.com'
	]));
});

$server->on('close', function ($serv, $fd){
	echo "client close. fd is {$fd}\n";
});

$server->on('task', function (swoole_server $serv, $task_id, $from_id,  $data){
	echo $data;
	
	$data = json_decode($data, true);
	$serv->send($data['fd'], "send eamil to {$data['email']}, content is : {$data['email_content']}\n");
	
	//echo 'task finished';
	//return 'task finished';
	$serv->finish('task finished');
});

$server->on('finish', function (swoole_server $serv, $task_id, $data){
	echo 'onFinish:' .$data;
});

$server -> start();

這里新建了一個tcp服務器,參數里設置worker_num進程為1,task_worker_num為1。

配置了task_worker_num參數后將會啟用task功能,swoole_server務必要注冊onTask/onFinish2個事件回調函數。如果沒有注冊,服務器程序將無法啟動。

onTask回調接收4個參數,分別是serv對象、任務ID、自於哪個worker進程、任務的內容。注意的是,$data必須是字符串。我們可以在worker進程里使用swoole_server->task ($data)進行任務投遞。

onFinish回調用於將處理結果告知worker進程,此回調必須有,但是否被調用由OnTask決定。在OnTask里使用return或者finish()可以將處理結果發生到onFinish回調,否則onFinish回調是不會被調用的。也就是說:finish()是可選的。如果worker進程不關心任務執行的結果,不需要調用此函數。onFinish回調里的$data同樣必須是字符串。

我們新起一個窗口,使用telnet發送消息到服務端進行測試:
client端:

telnet 127.0.0.1 8088
Trying 127.0.0.1...
Connected to 127.0.0.1.

hhh
send eamil to admin@qq.com, content is : hhh

server端:

client connect. fd is 1
onReceive. fd: 1 , data: "hhh\r\n"
{"fd":1,"task_name":"send_email","email_content":"hhh\r\n","email":"admin@qq.com"}
onFinish:task finished

onFinish回調里不使用return或者finish(),我們將看不到server端最后一行輸出。

此時服務器進程模型:

pstree -ap | grep swoole
  |   |       `-php,3190 swoole_task.php
  |   |           |-php,3192 swoole_task.php
  |   |           |   |-php,3194 swoole_task.php
  |   |           |   `-php,3195 swoole_task.php

看到兩個worker進程,其中一個是worker進程,另外一個是task_worker進程。

定時器

Swoole提供強大的異步毫秒定時器,基於timerfd+epoll實現。主要方法:
1、swoole_timer_tick:周期性定時器,類似於JavaScript里的setInterval()
2、swoole_timer_after:一次性定時器。
3、swoole_timer_clear:清除定時器。

# 周期性定時器
int swoole_timer_tick(int $ms, callable $callback, mixed $user_param);

# 一次性定時器
swoole_timer_after(int $after_time_ms, mixed $callback_function, mixed $user_param);

# 清除定時器
bool swoole_timer_clear(int $timer_id)

# 定時器回調函數
function callbackFunction(int $timer_id, mixed $params = null);

注意:

  • $ms 最大不得超過 86400000。
  • manager進程中不能添加定時器。
  • 建議在WorkerStart回調里寫定時器。

定時器示例:

$server->on('WorkerStart', function (\swoole_server $server, $worker_id){
    if ($server->worker_id == 0){//防止重復
        //每隔2000ms觸發一次
        swoole_timer_tick(2000, function ($timer_id) {
            echo "tick-2000ms\n";
        });
        
        //3000ms后執行此函數
        swoole_timer_after(3000, function () {
            echo "after 3000ms.\n";
        });
    }
});


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM