วิธีการดำเนินการงานแบบอะซิงโครนัส

คำถาม:

จะจัดการกับธุรกิจที่มีความยุ่งยากโดยไม่ให้ธุรกิจหลักถูกบล็อกเป็นเวลานานได้อย่างไร ตัวอย่างเช่น ฉันต้องการส่งอีเมลให้กับผู้ใช้ 1000 คน ซึ่งกระบวนการนี้ช้ามาก อาจใช้เวลาบล็อกเป็นเวลาหลายวินาที ในช่วงเวลานั้น เนื่องจากกระบวนการหลักถูกบล็อก จะส่งผลกระทบต่อการร้องขอต่อไป จะทำอย่างไรเพื่อมอบหมายงานที่มีภาระหนักเช่นนี้ให้กับกระบวนการอื่นเพื่อดำเนินการแบบอะซิงโครนัส

คำตอบ:

สามารถสร้างกระบวนการทำงานบางส่วนที่เครื่องนี้หรือเซิร์ฟเวอร์อื่น ๆ หรือแม้แต่คลัสเตอร์เซิร์ฟเวอร์เพื่อจัดการกับธุรกิจที่มีภาระหนักได้ โดยสามารถเปิดกระบวนการงานเพิ่มขึ้นได้ตามต้องการ เช่น จำนวน 10 เท่าของ CPU หลังจากนั้นผู้เรียกใช้จะใช้ AsyncTcpConnection เพื่อส่งข้อมูลไปยังกระบวนการงานเหล่านี้เพื่อดำเนินการแบบอะซิงโครนัสและได้รับผลลัพธ์ที่ประมวลผลแบบอะซิงโครนัส

เซิร์ฟเวอร์กระบวนการงาน

use Workerman\Worker;
use Workerman\Connection\TcpConnection;
require_once __DIR__ . '/vendor/autoload.php';

// task worker ใช้โปรโตคอล Text
$task_worker = new Worker('Text://0.0.0.0:12345');
// จำนวนกระบวนการงานสามารถเปิดเพิ่มขึ้นตามต้องการ
$task_worker->count = 100;
$task_worker->name = 'TaskWorker';
$task_worker->onMessage = function(TcpConnection $connection, $task_data)
{
     // สมมติว่าเป็นข้อมูล json ที่ถูกส่งมา
     $task_data = json_decode($task_data, true);
     // จัดการกับโลจิกของงานที่เกี่ยวข้องตามที่มาจาก $task_data .... และได้รับผลลัพธ์ ซึ่งในที่นี้ขอไม่กล่าวถึง....
     $task_result = ......
     // ส่งผลลัพธ์กลับ
     $connection->send(json_encode($task_result));
};
Worker::runAll();

การเรียกใช้ใน workerman

use Workerman\Worker;
use \Workerman\Connection\AsyncTcpConnection;
use Workerman\Connection\TcpConnection;
require_once __DIR__ . '/vendor/autoload.php';

// บริการ websocket
$worker = new Worker('websocket://0.0.0.0:8080');

$worker->onMessage = function(TcpConnection $ws_connection, $message)
{
    // สร้างการเชื่อมต่อแบบอะซิงโครนัสกับบริการงานระยะไกล โดย IP ของบริการงานระยะไกล หากเป็นเครื่องนี้ IP คือ 127.0.0.1 หากเป็นคลัสเตอร์ก็จะเป็น IP ของ LVS
    $task_connection = new AsyncTcpConnection('Text://127.0.0.1:12345');
    // ข้อมูลงานและพารามิเตอร์
    $task_data = array(
        'function' => 'send_mail',
        'args'       => array('from'=>'xxx', 'to'=>'xxx', 'contents'=>'xxx'),
    );
    // ส่งข้อมูล
    $task_connection->send(json_encode($task_data));
    // รอผลลัพธ์แบบอะซิงโครนัส
    $task_connection->onMessage = function(AsyncTcpConnection $task_connection, $task_result)use($ws_connection)
    {
         // ผลลัพธ์
         var_dump($task_result);
         // หลังได้รับผลลัพธ์แล้วอย่าลืมปิดการเชื่อมต่อแบบอะซิงโครนัส
         $task_connection->close();
         // แจ้งให้ลูกค้าของ websocket ทราบว่างานเสร็จสมบูรณ์
         $ws_connection->send('task complete');
    };
    // ดำเนินการเชื่อมต่อแบบอะซิงโครนัส
    $task_connection->connect();
};

Worker::runAll();

ในลักษณะนี้ งานที่มีภาระหนักจะถูกมอบหมายให้ดำเนินการโดยกระบวนการในเครื่องนี้หรือเซิร์ฟเวอร์อื่น ผลลัพธ์จะถูกส่งกลับมาอย่างอะซิงโครนัสเมื่อเสร็จสิ้น ทำให้กระบวนการธุรกิจหลักไม่ถูกบล็อก