Microsoft Azure SignalR Service は、Azure SignalR Service が SignalR クライアントと SignalR Hub サーバーの間のプロキシとして機能する 既定のモード として構成されている場合に、SignalR Hub サーバーを正常にシャットダウンするための 2 つのモードを提供します。
この機能を使用する主な利点は、顧客が予期せず接続が切断されるのを防ぐことです。
代わりに、ビジネス ロジックに関してクライアント接続が閉じるのを待つか、データを失うことなく別のサーバーにクライアント接続を移行することもできます。
どのように機能するのか
一般に、グレースフル シャットダウン プロセスには次の 4 つの段階があります。
サーバーをオフラインに設定する
これは、もうクライアント接続がこのサーバーにルーティングされなくなることを意味します。
トリガーフック
サーバーに所有しているハブごとにシャットダウン フックを登録できます。 これらは、Azure SignalR Service から FINACK 応答を受け取った直後に、登録された注文に関して呼び出されます。つまり、このサーバーは Azure SignalR Service でオフラインに設定されています。
このステージでは、メッセージをブロードキャストしたり、いくつかのクリーニング ジョブを実行したりできます。すべてのシャットダウン フックが実行されたら、次のステージに進みます。
すべてのクライアント接続が完了するまで待機します。選択するモードによって異なります。次の場合があります。
Mode が WaitForClientsToClose に設定されている
Azure SignalR Service は既存のクライアントを保持します。
閉じるメッセージをすべてのクライアントにブロードキャストし、クライアントが閉じる/再接続するタイミングを決めるなどの方法を設計する必要がある場合があります。
ChatSample を読み取り、シャットダウンフックでクライアントの終了をトリガーする「exit」メッセージを送信する使用例を確認してください。
MigrateClients に設定されたモード
Azure SignalR Service は、このサーバー上のクライアント接続を別の有効なサーバーに再ルーティングしようとします。
このシナリオでは、
OnConnectedAsyncとOnDisconnectedAsyncは、新しいサーバーと古いサーバーでそれぞれトリガーされ、IConnectionMigrationFeatureにContextが設定されます。これを使用して、クライアント接続が移行中か移行済みかを識別できます。この機能は、特にステートフル なシナリオに役立ちます。クライアント接続は、現在のメッセージが配信された直後に移行されます。つまり、次のメッセージは新しいサーバーにルーティングされます。
サーバー接続を停止する
すべてのクライアント接続を閉じたり移行したり、タイムアウト (既定では 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");
});
});
OnConnectedとOnDisconnectedを構成し、グレースフル シャットダウン モードをMigrateClientsに設定します。
接続が移行中かどうかを示す "IConnectionMigrationFeature" が導入されました。
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);
}
}