Slow Business Processing
Sometimes we need to handle slow business processes. To prevent slow business from affecting the processing of other requests in Webman, different handling solutions can be used depending on the situation.
Solution 1: Use Message Queues
Refer to Redis Queues and STOMP Queues.
Advantages
Can handle a sudden influx of business processing requests.
Disadvantages
Cannot directly return results to the client. If results need to be pushed, it requires other services, such as using webman/push to push processing results.
Solution 2: Add an HTTP Port
Add an HTTP port to handle slow requests, which will enter a specific set of processes through accessing this port. Once processed, the results will be returned directly to the client.
Advantages
Can directly return data to the client.
Disadvantages
Cannot handle a sudden influx of requests.
Implementation Steps
Add the following configuration in config/process.php
.
return [
// ... other configurations are omitted ...
'task' => [
'handler' => \Webman\App::class,
'listen' => 'http://0.0.0.0:8686',
'count' => 8, // Number of processes
'user' => '',
'group' => '',
'reusePort' => true,
'constructor' => [
'requestClass' => \support\Request::class, // request class settings
'logger' => \support\Log::channel('default'), // log instance
'appPath' => app_path(), // app directory location
'publicPath' => public_path() // public directory location
]
]
];
This way, the slow interface can go through http://127.0.0.1:8686/
without affecting the business processing of other processes.
To make the front end unaware of the port difference, you can add a proxy to port 8686 in nginx. Assuming that the request paths for slow interfaces all start with /tast
, the entire nginx configuration is roughly as follows:
upstream webman {
server 127.0.0.1:8787;
keepalive 10240;
}
# Add a new upstream for 8686
upstream task {
server 127.0.0.1:8686;
keepalive 10240;
}
server {
server_name webman.com;
listen 80;
access_log off;
root /path/webman/public;
# Requests starting with /tast go through port 8686, please change /tast to your required prefix according to actual situation
location /tast {
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header Host $host;
proxy_http_version 1.1;
proxy_set_header Connection "";
proxy_pass http://task;
}
# Other requests go through the original port 8787
location / {
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header Host $host;
proxy_http_version 1.1;
proxy_set_header Connection "";
if (!-f $request_filename){
proxy_pass http://webman;
}
}
}
This way, when the client accesses domain.com/tast/xxx
, it will be processed by the separate port 8686, without affecting the request processing on port 8787.
Solution 3: Use HTTP Chunked Asynchronous Data Segment Sending
Advantages
Can directly return data to the client.
Install workerman/http-client
composer require workerman/http-client
app/controller/IndexController.php
<?php
namespace app\controller;
use support\Request;
use support\Response;
use Workerman\Protocols\Http\Chunk;
class IndexController
{
public function index(Request $request)
{
$connection = $request->connection;
$http = new \Workerman\Http\Client();
$http->get('https://example.com/', function ($response) use ($connection) {
$connection->send(new Chunk($response->getBody()));
$connection->send(new Chunk('')); // Sending an empty chunk represents the end of the response
});
// First send an HTTP header, subsequent data will be sent asynchronously
return response()->withHeaders([
"Transfer-Encoding" => "chunked",
]);
}
}
Tip
This example uses theworkerman/http-client
to asynchronously fetch HTTP results and return data. Other asynchronous clients can also be used, such as AsyncTcpConnection.