Обработка медленных операций
Иногда нам необходимо обрабатывать медленные операции. Чтобы избежать влияния медленных операций на обработку других запросов в webman, в зависимости от ситуации можно использовать разные решения.
Решение 1: Использование очереди сообщений
См. очередь Redis очередь Stomp
Преимущества
Может обрабатывать внезапные всплески запросов на обработку
Недостатки
Невозможно напрямую вернуть результат клиенту. При необходимости отправки результата требуется координация с другими сервисами, например использование webman/push для отправки результата обработки.
Решение 2: Добавление нового HTTP-порта
Добавление нового HTTP-порта для обработки медленных запросов. Эти медленные запросы обрабатываются определённой группой процессов через доступ к этому порту, после обработки результат возвращается напрямую клиенту.
Преимущества
Может возвращать данные напрямую клиенту
Недостатки
Не может обрабатывать внезапные всплески запросов
Шаги реализации
Добавьте следующую конфигурацию в config/process.php.
return [
// ... Остальные настройки опущены ...
'task' => [
'handler' => \Webman\App::class,
'listen' => 'http://0.0.0.0:8686',
'count' => 8, // Количество процессов
'user' => '',
'group' => '',
'reusePort' => true,
'constructor' => [
'requestClass' => \support\Request::class, // Настройка класса запроса
'logger' => \support\Log::channel('default'), // Экземпляр логгера
'appPath' => app_path(), // Расположение каталога app
'publicPath' => public_path() // Расположение каталога public
]
]
];
Таким образом, медленные интерфейсы могут обрабатываться группой процессов по адресу http://127.0.0.1:8686/ без влияния на обработку других процессов.
Чтобы фронтенд не замечал разницу портов, можно добавить прокси к порту 8686 в nginx. Если пути медленных запросов начинаются с /task, конфигурация nginx будет выглядеть следующим образом:
upstream webman {
server 127.0.0.1:8787;
keepalive 10240;
}
# Добавить новый upstream 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;
# Запросы, начинающиеся с /task, направляются на порт 8686; при необходимости измените /task на нужный префикс
location /task {
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;
}
# Остальные запросы направляются на порт 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;
}
}
}
При обращении клиента к домен.com/task/xxx запрос будет обработан отдельным портом 8686 без влияния на обработку запросов порта 8787.
Решение 3: Использование HTTP Chunked для асинхронной посылки сегментированных данных
Преимущества
Может возвращать данные напрямую клиенту
Установка 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('')); // Отправка пустого chunk означает конец ответа
});
// Сначала отправляются HTTP-заголовки, данные отправляются асинхронно
return response()->withHeaders([
"Transfer-Encoding" => "chunked",
]);
}
}
Примечание
В этом примере клиентworkerman/http-clientиспользуется для асинхронного получения HTTP-результатов и возврата данных. Также можно использовать другие асинхронные клиенты, например AsyncTcpConnection.