Procesamiento de Negocios Lentos

A veces necesitamos manejar negocios lentos. Para evitar que estos procesos lentos afecten la gestión de otras solicitudes en webman, podemos utilizar diferentes soluciones según la situación.

Opción 1 Uso de Colas de Mensajes

Consulte cola redis cola stomp

Ventajas

Puede manejar solicitudes de procesamiento de negocios masivos inesperados.

Desventajas

No se puede devolver directamente el resultado al cliente. Si se requiere enviar resultados, se necesita colaborar con otros servicios, como usar webman/push para enviar los resultados del procesamiento.

Opción 2 Agregar Puerto HTTP

Agregar un puerto HTTP para manejar solicitudes lentas; estas solicitudes lentas ingresan a un conjunto específico de procesos a través de este puerto, y los resultados se devuelven directamente al cliente.

Ventajas

Puede devolver datos directamente al cliente.

Desventajas

No puede manejar solicitudes masivas inesperadas.

Pasos de Implementación

Agregue la siguiente configuración en config/process.php.

return [
    // ... otras configuraciones omitidas ...

    'task' => [
        'handler' => \Webman\App::class,
        'listen' => 'http://0.0.0.0:8686',
        'count' => 8, // número de procesos
        'user' => '',
        'group' => '',
        'reusePort' => true,
        'constructor' => [
            'requestClass' => \support\Request::class, // configuración de la clase request
            'logger' => \support\Log::channel('default'), // instancia de log
            'appPath' => app_path(), // ubicación del directorio app
            'publicPath' => public_path() // ubicación del directorio public
        ]
    ]
];

Así, las interfaces lentas pueden dirigirse a http://127.0.0.1:8686/, sin afectar la gestión de negocios de otros procesos.

Para que el front-end no perciba la diferencia de puerto, se puede agregar un proxy en nginx hacia el puerto 8686. Supongamos que las rutas de las solicitudes a las interfaces lentas comienzan con /tast, la configuración de nginx se verá similar a la siguiente:

upstream webman {
    server 127.0.0.1:8787;
    keepalive 10240;
}

# Agregar un upstream para el 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;

  # Las solicitudes que comienzan con /tast utilizan el puerto 8686, cambie /tast según su prefijo necesario
  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;
  }

  # Otras solicitudes utilizan el puerto original 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;
      }
  }
}

Así, cuando el cliente accede a dominio.com/tast/xxx, la solicitud será procesada a través del puerto 8686, sin afectar la gestión de solicitudes del puerto 8787.

Opción 3 Usar HTTP Chunked para Enviar Datos de Forma Asíncrona

Ventajas

Puede devolver datos directamente al cliente.

Instalar 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('')); // enviar un chunk vacío indica el final de la respuesta
        });
        // Enviar primero un encabezado http, los datos posteriores se envían de forma asíncrona
        return response()->withHeaders([
            "Transfer-Encoding" => "chunked",
        ]);
    }
}

Nota
En este ejemplo se ha utilizado el cliente workerman/http-client para obtener el resultado HTTP de forma asíncrona y devolver los datos. También se pueden utilizar otros clientes asíncronos como AsyncTcpConnection.