Skip to content

Ipc Broadcaster

在 Hyperf Server Worker 和使用者程序之間廣播可序列化訊息。

安裝

shell
composer require friendsofhyperf/ipc-broadcaster

該包會自動註冊 ConfigProvider,將 BroadcasterInterface 繫結到 AllProcessesBroadcaster,並註冊 Server Worker 接收訊息所需的監聽器。該元件沒有需要釋出的配置檔案。

該包的 composer.json 僅聲明瞭 hyperf/event ~3.2.0,且沒有宣告可選依賴。請在提供廣播器所需 Server、Process、容器和 DI 執行時類的 Hyperf Server 應用中使用。

廣播訊息

broadcast() 函式接受 IpcMessageInterface 例項或閉包。預設透過 AllProcessesBroadcaster 將訊息傳送到其他所有 Server Worker 和所有已註冊的協程使用者程序。

類訊息

繼承 IpcMessage 並實現 handle()IpcMessage 還透過 InteractsWithFromWorkerId 提供 getFromWorkerId()setFromWorkerId()。Server Worker 收到訊息時,getFromWorkerId() 包含傳送方的 Worker ID。

php
<?php

namespace App\Broadcasting;

use FriendsOfHyperf\IpcBroadcaster\IpcMessage;

use function FriendsOfHyperf\IpcBroadcaster\broadcast;

class FooMessage extends IpcMessage
{
    public function __construct(private string $foo)
    {
    }

    public function handle(): void
    {
        echo $this->foo;
    }
}

broadcast(new FooMessage('bar'));

訊息物件及其屬性必須可序列化,才能跨程序傳輸。

閉包訊息

閉包在廣播前會包裝為 ClosureIpcMessage 並進行序列化,因此閉包捕獲的值也必須可序列化。在常規 Hyperf DI 環境中,有型別宣告的閉包引數可從容器解析。

php
use function FriendsOfHyperf\IpcBroadcaster\broadcast;

broadcast(function () {
    echo 'Hello world';
});

選擇目標

注入 BroadcasterInterface 可使用預設的全程序廣播行為,也可以構造特定廣播器來選擇目標:

php
use FriendsOfHyperf\IpcBroadcaster\ServerBroadcaster;
use FriendsOfHyperf\IpcBroadcaster\UserProcessesBroadcaster;

$serverBroadcaster = new ServerBroadcaster($container, id: 1);
$serverBroadcaster->broadcast($message);

$userProcessBroadcaster = new UserProcessesBroadcaster(name: 'reporting', id: 0);
$userProcessBroadcaster->broadcast($message);

ServerBroadcaster 接受容器和可選的 Worker ID;未傳 ID 時,會發送到當前 Worker 之外的所有 Server Worker。UserProcessesBroadcaster 接受可選的程序名稱和程序 ID;兩者均未傳時,會發送到 Hyperf ProcessCollector 收集的所有已註冊程序。

在使用者程序中處理訊息

元件會為 Server Worker 收到的訊息自動呼叫 handle()。在使用者程序中,Hyperf 會派發 Hyperf\Process\Event\PipeMessage,元件不會自動呼叫其中訊息的 handle() 方法。需要讓使用者程序 執行訊息時,請註冊監聽器:

php
use FriendsOfHyperf\IpcBroadcaster\Contract\IpcMessageInterface;
use Hyperf\Event\Contract\ListenerInterface;
use Hyperf\Process\Event\PipeMessage;

class UserProcessPipeMessageListener implements ListenerInterface
{
    public function listen(): array
    {
        return [PipeMessage::class];
    }

    public function process(object $event): void
    {
        if ($event instanceof PipeMessage && $event->data instanceof IpcMessageInterface) {
            $event->data->handle();
        }
    }
}

在當前 Worker 中執行

廣播預設不會在當前 Server Worker 中執行。給訊息新增 RunsInCurrentWorker 後,會先在當前 Worker 中呼叫一次 handle(),再發送到所選目標:

php
use FriendsOfHyperf\IpcBroadcaster\IpcMessage;
use FriendsOfHyperf\IpcBroadcaster\Traits\RunsInCurrentWorker;

class RefreshMessage extends IpcMessage
{
    use RunsInCurrentWorker;

    public function handle(): void
    {
        // Refresh local state.
    }
}

協程伺服器限制

觸發 MainCoroutineServerStart 後,跨程序廣播會被停用,廣播器呼叫不會發送訊息便直接返回。使用 RunsInCurrentWorker 的訊息仍會在廣播器返回前在本地執行一次。