遅延処理

時には、遅延処理を行う必要があります。遅延処理が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, // requestクラスの設定
            'logger' => \support\Log::channel('default'), // ログインスタンス
            'appPath' => app_path(), // appディレクトリの位置
            'publicPath' => public_path() // publicディレクトリの位置
        ]
    ]
];

これにより、遅延インターフェースは http://127.0.0.1:8686/ このグループのプロセスを通過し、他のプロセスのビジネス処理に影響を与えません。

フロントエンドがポートの違いを感じないようにするために、nginxに8686ポートへのプロキシを追加できます。遅延インターフェースのリクエストパスがすべて/tastで始まると仮定すると、全体のnginx設定は次のようになります。

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

# 新しい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;

  # /tastで始まるリクエストは8686ポートを通過します。実際の状況に応じて/tastを必要なプレフィックスに変更してください
  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;
  }

  # 他のリクエストは元の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;
      }
  }
}

これにより、クライアントがdomain.com/tast/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を送信してresponseを終了させる
        });
        // 先にhttpヘッダーを送信し、その後のデータを非同期で送信する
        return response()->withHeaders([
            "Transfer-Encoding" => "chunked",
        ]);
    }
}

ヒント
この例では、workerman/http-clientクライアントを使用してhttp結果を非同期に取得しデータを返していますが、他の非同期クライアント(例えばAsyncTcpConnection)を使用することもできます。