معالجة الأعمال البطيئة

في بعض الأحيان نحتاج إلى معالجة أعمال بطيئة، ولتجنب تأثير الأعمال البطيئة على معالجة الطلبات الأخرى في webman، يمكن استخدام حلول معالجة مختلفة حسب الظروف.

الحل الأول استخدام قائمة الانتظار

راجع قائمة انتظار redis و قائمة انتظار stomp

الفوائد

يمكن التعامل مع طلبات معالجة الأعمال بكميات ضخمة في وقت واحد.

العيوب

لا يمكن إرجاع النتائج مباشرة إلى العميل. إذا كانت هناك حاجة لإرسال النتائج، يجب تكاملها مع خدمات أخرى، مثل استخدام webman/push لإرسال نتائج المعالجة.

الحل الثاني إضافة منفذ 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(), // موقع دليل التطبيق
            'publicPath' => public_path() // موقع دليل العام
        ]
    ]
];

بهذه الطريقة، يمكن للواجهات البطيئة استخدام مجموعة العمليات هذه في http://127.0.0.1:8686/، دون التأثير على معالجة الأعمال في العمليات الأخرى.

لجعل الواجهة الأمامية غير متأثرة بفرق المنفذ، يمكن إضافة وكيل إلى Nginx إلى المنفذ 8686. لنفترض أن مسارات طلب الواجهة البطيئة كلها تبدأ بـ /tast، سيكون تكوين 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;

  # الطلبات التي تبدأ بـ /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.

الحل الثالث استخدام 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.