Создание надежного websocket с помощью подпротокола

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

Примечание

Надежные протоколы по-прежнему доступны в предварительной версии. Некоторые изменения ожидаются в будущем.

Надежный протокол

Служба поддерживает два надежных подпротокола json.reliable.webpubsub.azure.v1 и protobuf.reliable.webpubsub.azure.v1. Клиенты должны следовать протоколу, в основном включая часть повторного подключения, издателя и подписчика для обеспечения надежности, или доставка сообщений может не работать должным образом или служба может завершить клиент, поскольку он нарушает спецификацию протокола.

Инициализация

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

  • Использование надежного подпротокола Json

    var pubsub = new WebSocket('wss://test.webpubsub.azure.com/client/hubs/hub1', 'json.reliable.webpubsub.azure.v1');
    
  • Использование надежного подпротокола Protobuf

    var pubsub = new WebSocket('wss://test.webpubsub.azure.com/client/hubs/hub1', 'protobuf.reliable.webpubsub.azure.v1');
    

Повторного подключения

Ретранслятор подключений Websocket по протоколу TCP, поэтому если подключение не удаляется, все сообщения должны быть потеряны и в порядке. При возникновении проблем с сетью и подключений все состояния, такие как сведения о группе и сообщения, сохраняются службой и ожидают восстановления повторного подключения. Соединение Websocket владеет сеансом в службе и идентификатором connectionId. Повторное подключение является основой обеспечения надежности и должно быть реализовано. Когда новое подключение подключается к службе с помощью надежных подпротоколов, соединение получит Connected сообщение, connectionId содержащее и reconnectionToken.

{
    "type":"system",
    "event":"connected",
    "connectionId": "<connection_id>",
    "reconnectionToken": "<reconnection_token>"
}

После удаления подключения WebSocket клиент должен сначала попытаться повторно подключиться к тому же connectionId , чтобы сохранить сеанс. Клиентам не нужно вести переговоры с сервером и получать .access_token Вместо этого повторное подключение должно выполнять запрос на подключение websocket к службе напрямую с connection_idreconnection_token помощью следующего URI:

wss://<service-endpoint>/client/hubs/<hub>?awps_connection_id=<connection_id>&awps_reconnection_token=<reconnection_token>

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

  1. Подключение Websocket закрыто с кодом состояния 1008. Код состояния означает, что идентификатор подключения был удален из службы.
  2. Сбой повторного подключения длится более 1 минуты.

Publisher

Клиенты, отправляющие события в обработчик событий или публикующие сообщения другим клиентам, называются издателями в документе. Издатели должны задать ackId сообщение, чтобы получить подтверждение от службы о том, успешно ли публикация сообщения или нет. В ackId сообщении — это идентификатор сообщения, что означает, что разные сообщения должны использовать разные ackIds, а повторное отправку сообщения должно оставаться одинаковым ackId , чтобы служба отменяла повторение.

Пример сообщения о отправке группы:

{
    "type": "sendToGroup",
    "group": "group1",
    "dataType" : "text",
    "data": "text data",
    "ackId": 1
}

Пример ответа ack:

{
    "type": "ack",
    "ackId": 1,
    "success": true
}

Если служба возвращает ошибку, success: trueсообщение обработано службой, и клиент может ожидать, что сообщение будет доставлено всем подписчикам.

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

{
    "type": "ack",
    "ackId": 1,
    "success": false,
    "error": {
        "name": "InternalServerError",
        "message": "Internal server error"
    }
}

Message Failure

Служба может быть удалена из-за удаления подключения WebSockets. Таким образом, издатели должны получать уведомления при удалении подключения Websocket и повторной отправке сообщения с тем же ackId после повторного подключения. Если сообщение фактически обработано службой, оно ответит на сообщение, Duplicate и издатели должны перестать повторно отправить это сообщение.

{
    "type": "ack",
    "ackId": 1,
    "success": false,
    "error": {
        "name": "Duplicate",
        "message": "Message with ack-id: 1 has been processed"
    }
}

Message duplicated

Подписчик

Клиенты, получающие сообщения, отправленные от обработчиков событий или издателей, называются подписчиками в документе. При удалении подключений по сетевым проблемам служба не знает, сколько сообщений фактически отправляется подписчикам. Таким образом, подписчики должны сообщить службе, какое сообщение было получено. Сообщения данных содержатся sequenceId , и подписчики должны взломать идентификатор последовательности с сообщением ack последовательности:

Пример последовательности:

{
    "type": "sequenceAck",
    "sequenceId": 1
}

Идентификатор последовательности — это добавочное число uint64 с сеансом идентификатора соединения. Подписчики должны записывать самый большой идентификатор последовательности, который он когда-либо получал, и принимать все сообщения с большим идентификатором последовательности и удалять все сообщения с меньшим или равным идентификатором последовательности. Пакет ack последовательности поддерживает накопительный ack, что означает, что если вы ack sequence-id=5, служба будет обрабатывать все сообщения с идентификатором последовательности меньше 5 уже получены подписчиками. Подписчики должны указать самый большой идентификатор последовательности, который он записал, чтобы служба может пропустить повторное получение сообщений, которые уже получили подписчики.

Все сообщения доставляются подписчикам по порядку до тех пор, пока подключение WebSockets не падает. С помощью идентификатора последовательности служба может иметь знания о количестве подписчиков сообщений, полученных через подключения WebSockets с сеансом идентификатора подключения. После удаления подключения WebSockets служба будет повторно отправлять сообщения, которые она должна доставлять, но не ack-ed подписчиком. Служба удерживает сообщения, которые не ack-ed с ограничением, если сообщения превышают предел, служба закроет подключение WebSockets и удалит сеанс идентификатора подключения. Таким образом, подписчики должны как можно скорее уволить идентификатор последовательности.