Корректное завершение работы сервера

Microsoft Служба Azure SignalR предоставляет два режима для корректного завершения работы сервера SignalR Hub при настройке Служба Azure SignalR в качестве режима по умолчанию, который Служба Azure SignalR выступает в качестве прокси-сервера между клиентами SignalR и сервером Центра SignalR.

Ключевым преимуществом этой функции является то, что она предотвращает неожиданные сбои подключения у клиента.

Вместо этого можно либо подождать, пока клиентские подключения закроются самостоятельно в соответствии с бизнес-логикой, либо даже перенести клиентское подключение на другой сервер без потери данных.

Как это работает

Как правило, процесс корректного завершения работы состоит из четырех описанных ниже этапов.

  1. Перевод сервера в автономный режим

    Это означает, что на сервер больше не будут направляться клиентские подключения.

  2. Активация триггеров OnShutdown

    Можно зарегистрировать обработчики завершения для каждого концентратора, принадлежащего серверу. Они будут вызываться в отношении зарегистрированного заказа сразу после получения ответа FINACK от нашей Служба Azure SignalR, что означает, что этот сервер был установлен в автономном режиме в Служба Azure SignalR.

    Вы можете транслировать сообщения или выполнять некоторые задания очистки на этом этапе после выполнения всех перехватчиков завершения работы, мы перейдем к следующему этапу.

  3. Дождитесь завершения всех клиентских подключений. В зависимости от выбранного режима возможны перечисленные ниже варианты.

    Режим WaitForClientsToClose

    Служба Azure SignalR будет удерживать существующие клиенты.

    Возможно, вам придется разработать способ, например транслировать закрываемое сообщение всем клиентам, а затем позволить клиентам решить, когда закрыть или повторно подключиться.

    Ознакомьтесь с примером использования в ChatSample, в котором транслируется сообщение Exit, чтобы активировать закрытие клиента в обработчике завершения.

    Режим MigrateClients

    Служба Azure SignalR попытается перенаправить клиентское подключение с этого сервера на другой допустимый сервер.

    В этом сценарии OnConnectedAsync он OnDisconnectedAsync будет активирован на новом сервере и старом сервере соответственно с набором IConnectionMigrationFeature в наборе Context, который можно использовать для определения того, переносится ли клиентское подключение или выполняется миграция. Эта функция может быть полезна особенно для сценариев с отслеживанием состояния.

    Клиентское подключение будет немедленно перенесено после доставки текущего сообщения, то есть следующее сообщение будет направлено на новый сервер.

  4. Прекращение подключений к серверу

    После того как все клиентские соединения будут закрыты или перенесены либо будет превышено время ожидания (30 с по умолчанию).

    Пакет SDK сервера SignalR продолжит завершение работы на этом этапе и завершит все соединения с сервером.

    Клиентские подключения, которые не удастся закрыть или перенести, будут закрыты (например, если не было обработано соответствующее сообщение целевого сервера или текущего клиента серверу).

Пример кода.

Добавьте следующие параметры при вызове 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.

Мы ввели "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);
    }
}