Using swoole extension for delayed asynchronous timing tasks
The business environment used this time is laravel9 + swoole4 + docker lnmp. If you do not have a docker environment, you can only operate the pagoda on linux, and you can install swoole with one click. If you see a lot of asynchronous tasks recently, if you use tp3 or other frameworks with older versions, there is no delay. Asynchronous tasks are not easy to achieve requirements, so I posted this article
. swoole itself is an extension and can be used at any framework level. The writing method is relatively concise and specific, and it only provides an idea.
Business scenario: It is necessary to customize the millisecond level of processing time for each different task. For example : each school can set a custom notification to remind the following students to upload the health code when the time is
up
. Click the notification
to perform an editing and modifying dynamic task
Just take laravel for a demonstration, without the artisan command, these encapsulated simple usages
First create a service directory in the app directory and define a file SwooleService.php This file does not depend on the laravel
code and directly cd to the current directory
<?php
//Create a TCP Server object and listen to the 127.0.0.1:9501 port, which is similar to nginx
$server = new Swoole\Server('127.0.0.1', 2345);
//listen for connection entry event
$server->on('Connect', function ($server, $fd) {
});
//Listen to the data reception event to receive the data sent by the back-end laravel controller (it can also be called the client for fear of being misunderstood)
$server->on('Receive', function ($server, $fd, $reactor_id, $data) {
// received data
/**
【time=>3】Time in seconds
[type=>['open','close']] type publish task, receive task
[tick_id->1] The id obtained by the successful task release can be stored for subsequent closing of the task
**/
$data = trim($data);
$info = json_decode($data);
echo $info->type;
//This should encapsulate a method call
//If the data type is not open, then it represents the release task
if($info->type=="open"){
$time = $info->time;
echo "I received this task and asked me to run this task every ".$time." seconds\n";
//swoole_timer_tick itself is asynchronous + synergistic
// post the task here
$tick_id = swoole_timer_tick($time*1000,function()use($time){
/** The business logic here can use curl to request the controller method corresponding to laravel to do an operation here Shorthand replace it by yourself */
$cli = new \Swoole\Coroutine\Http\Client('httpbin.org', 80);
$cli->get('/get');
echo $cli->body;
$cli->close();
echo "Execute a task every ".$time." seconds\n";
});
echo "This timer id is".$tick_id;
//Return data to the client to detect whether this task has been released. Corresponding to the $client->recv(); method of SwooleClient.php
$server->send($fd, json_encode(['msg'=>"One timer id every ".$time." second The task id is ".$tick_id."\n",'tick_id'=>$tick_id ]));
}
if($info->type=="close"){
$tick_id = $info->tick_id;
echo "I received an interrupt signal requesting an interrupt to close the timer ID".$tick_id." \n";
//Close the currently running timer
swoole_timer_clear($tick_id);
//Return data to the client to detect whether this task has been released. Corresponding to the $client->recv(); method of SwooleClient.php
$server->send($fd, json_encode(['msg'=>"Interrupt timer id is".$tick_id,'tick_id'=>$tick_id]));
}
});
//listen for connection close event
$server->on('Close', function ($server, $fd) {
//echo "Client: Close.\n";
});
//start the server
$server->start();
Execute php SwooleService.php to start listening for requests
If you encounter an error Error: Address already in use means
that the port is occupied, execute
netstat -anp | grep 2345
to get the process ID kill The process id obtained above
laravel define routes
Route::get('/send','\App\Http\Controllers\IndexController@send');
Route::get('/close','\App\Http\Controllers\IndexController@close');
IndexController controller code
<?php
namespace App\Http\Controllers;
class IndexController extends Controller
{
// release task method
public function send(){
// How long to fill in the parameters dynamically and execute in seconds
$time = request()->get("time",2);
//Link the service 127.0.0.1:2345 port just created
$client = new \Swoole\Client(SWOOLE_SOCK_TCP);
if (!$client->connect('127.0.0.1', 2345, -1)) {
exit("connect failed. Error: {$client->errCode}\n");
}
//Send data to server 127.0.0.1:2345 port
$client->send(json_encode(['type'=>'open','time'=>$time]));
//Return tick_id to execute the task id Here is the task id returned by the SwooleService.php server
echo $client->recv();
//*****$client->recv() return value for business logic processing and save the id of this task to facilitate the next task to close monitoring, etc.
//close the client link
$client->close();
}
//stop task method
public function close(){
//Get the id of the task The above send method $client->recv(); the id received by this line of code
$tick_id = request()->get("tick_id");
$client = new \Swoole\Client(SWOOLE_SOCK_TCP);
if (!$client->connect('127.0.0.1', 2345, -1)) {
exit("connect failed. Error: {$client->errCode}\n");
}
//The type is close to trigger the close event of SwooleService.php
$client->send(json_encode(['type'=>'close','tick_id'=>$tick_id]));
//Receive the message returned by the server
echo $client->recv();
//close the client
$client->close();
}
}
Attach the results of the apipost request in order, first open the monitoring post task, then close the task
operation and start monitoring
The task has been successfully closed
The general business logic is that the
ordinary http request requests to the corresponding controller of laravel, and then the laravel controller TCP request carries parameters to the
TCP server, that is, the series written in the corresponding SwooleService.php file The server receives the millisecond timer using swoole Then use curl to request http back to the controller corresponding to laravel for business processing to achieve scheduled tasks
0 Comments