伺服器正常關機

當 Azure SignalR 服務設定為 Azure SignalR Service 做為 SignalR 用戶端與 SignalR Hub 伺服器之間的 Proxy 時,Microsoft Azure SignalR Service 提供兩種模式,以正常關閉 SignalR Hub 伺服器。

使用這項功能的主要優點是防止客戶發生非預期的連線中斷。

相反地,您可以等候用戶端連線以在商務邏輯方面自行關閉,或甚至將用戶端連線移轉至另一部伺服器,而不會遺失資料。

運作方式

一般而言,正常關機程式會有四個階段:

  1. 離線設定伺服器

    這表示不會再將用戶端連線路由至此伺服器。

  2. 觸發 OnShutdown 程式攔截

    您可以註冊伺服器中擁有之每個中樞的關機攔截。 我們會在收到來自 Azure SignalR 服務的 FINACK 回應之後 ,立即呼叫註冊訂單,這表示此伺服器已在 Azure SignalR 服務中離線設定。

    您可以在此階段廣播訊息或執行一些清除作業,一旦執行所有關機攔截,我們會繼續進行下一個階段。

  3. 等候所有用戶端連線完成 ,視您選擇的模式而定,可能是:

    模式設定為 WaitForClientsToClose

    Azure SignalR Service 將保留現有的用戶端。

    您可能必須設計一種方式,例如將所有用戶端廣播關閉訊息,然後讓您的用戶端決定何時關閉/重新連線。

    閱讀 ChatSample 以取得範例使用方式,我們會廣播「結束」訊息,以在關機攔截中觸發用戶端關閉。

    模式設定為 MigrateClients

    Azure SignalR 服務會嘗試將此伺服器上的用戶端連線重新路由至另一個有效的伺服器。

    在此案例中, OnConnectedAsyncOnDisconnectedAsync 分別 IConnectionMigrationFeature 在新的伺服器和舊伺服器上觸發 ,並在 中 Context 設定 ,用來識別用戶端連線是否已移入或移出。這項功能特別適用于具狀態案例。

    用戶端連線會在傳遞目前訊息之後立即移轉,這表示下一個訊息將會路由傳送至新的伺服器。

  4. 停止伺服器連線

    關閉/移轉所有用戶端連線之後,或超過逾時 (預設為 30 秒) 之後,

    SignalR Server SDK 會繼續進行關機程式到此階段,並關閉所有伺服器連線。

    如果用戶端連線無法關閉/移轉,仍會卸載。 例如,沒有適當的目標伺服器 /目前的用戶端對伺服器訊息尚未完成。

範例程式碼。

在 時 AddAzureSignalR 新增下列選項:

services.AddSignalR().AddAzureSignalR(option =>
{
    option.GracefulShutdown.Mode = GracefulShutdownMode.WaitForClientsClose;
    // option.GracefulShutdown.Mode = GracefulShutdownMode.MigrateClients;
    option.GracefulShutdown.Timeout = TimeSpan.FromSeconds(30);

    option.GracefulShutdown.Add<Chat>(async (c) =>
    {
        await c.Clients.All.SendAsync("exit");
    });
});

將 正常關機模式設定為 MigrateClients 時,設定 OnConnectedOnDisconnected

我們引進了「I連線ionMigrationFeature」,以指出連線是否已移入/移出。

public class Chat : Hub {

    public override async Task OnConnectedAsync()
    {
        Console.WriteLine($"{Context.ConnectionId} connected.");

        var feature = Context.Features.Get<IConnectionMigrationFeature>();
        if (feature != null)
        {
            Console.WriteLine($"[{feature.MigrateTo}] {Context.ConnectionId} is migrated from {feature.MigrateFrom}.");
            // Your business logic.
        }

        await base.OnConnectedAsync();
    }

    public override async Task OnDisconnectedAsync(Exception e)
    {
        Console.WriteLine($"{Context.ConnectionId} disconnected.");

        var feature = Context.Features.Get<IConnectionMigrationFeature>();
        if (feature != null)
        {
            Console.WriteLine($"[{feature.MigrateFrom}] {Context.ConnectionId} will be migrated to {feature.MigrateTo}.");
            // Your business logic.
        }

        await base.OnDisconnectedAsync(e);
    }
}