Creare un websocket affidabile con sottoprotocol
Le connessioni client Websocket possono venire interrotte a causa di problemi di rete intermittenti e, quando le connessioni vengono interrotte, i messaggi andranno persi. In un sistema pubsub, gli editori sono separati dai sottoscrittori, quindi gli editori sono difficili da rilevare la perdita di messaggi o l'eliminazione dei sottoscrittori. È fondamentale che i client superino i problemi di rete intermittenti e mantengano l'affidabilità del recapito dei messaggi. A tale scopo, è possibile creare un client Websocket affidabile con l'aiuto di sottoprotocoli affidabili.
Nota
I protocolli reliable sono ancora in anteprima. Alcune modifiche sono previste in futuro.
Reliable Protocol
Il servizio supporta due sottoprotocoli json.reliable.webpubsub.azure.v1
affidabili e protobuf.reliable.webpubsub.azure.v1
. I client devono seguire il protocollo, inclusa principalmente la parte della riconnessione, del server di pubblicazione e del sottoscrittore per ottenere l'affidabilità oppure il recapito dei messaggi potrebbe non funzionare come previsto o il servizio potrebbe terminare il client perché viola la specifica del protocollo.
Inizializzazione
Per usare sottoprotocol reliable, è necessario impostare subprotocol durante la creazione di connessioni Websocket. In JavaScript è possibile usare come segue:
Usare il sottoprotocolo Reliable Json
var pubsub = new WebSocket('wss://test.webpubsub.azure.com/client/hubs/hub1', 'json.reliable.webpubsub.azure.v1');
Usare protobuf reliable subprotocol
var pubsub = new WebSocket('wss://test.webpubsub.azure.com/client/hubs/hub1', 'protobuf.reliable.webpubsub.azure.v1');
Riconnessione
Le connessioni Websocket inoltrino su TCP, quindi se la connessione non viene eseguita, tutti i messaggi devono essere senza perdita di dati e in ordine. Quando si verificano problemi di rete e connessioni si rilasciano, tutti gli stati, ad esempio le informazioni sul gruppo e sui messaggi, vengono mantenuti dal servizio e attendono il ripristino della riconnessione. Una connessione Websocket è proprietaria di una sessione nel servizio e l'identificatore è connectionId
. La riconnessione è la base per ottenere l'affidabilità e deve essere implementata. Quando una nuova connessione si connette al servizio usando sottoprotocoli reliable, la connessione riceverà un Connected
messaggio contenente connectionId
e reconnectionToken
.
{
"type":"system",
"event":"connected",
"connectionId": "<connection_id>",
"reconnectionToken": "<reconnection_token>"
}
Una volta interrotta la connessione WebSocket, il client deve prima provare a riconnettersi con lo stesso connectionId
per mantenere la sessione. I client non devono negoziare con il server e ottenere .access_token
Al contrario, la riconnessione deve effettuare una richiesta di connessione Websocket al servizio direttamente con connection_id
e reconnection_token
con l'URI seguente:
wss://<service-endpoint>/client/hubs/<hub>?awps_connection_id=<connection_id>&awps_reconnection_token=<reconnection_token>
La riconnessione potrebbe non riuscire perché il problema di rete non è stato ancora recuperato. Il client deve continuare a riprovare a riconnettersi fino a quando
- Connessione Websocket chiusa con codice di stato 1008. Il codice di stato indica che connectionId è stato rimosso dal servizio.
- L'errore di riconnessione mantiene più di 1 minuto.
Publisher
I client che inviano eventi al gestore eventi o pubblicano messaggi ad altri client vengono chiamati autori nel documento. I server di pubblicazione devono impostare ackId
sul messaggio per confermare dal servizio se il messaggio ha esito positivo o negativo. Il ackId
nel messaggio è l'identificatore del messaggio, il che significa che i diversi messaggi devono usare s diversi ackId
, mentre il messaggio di nuovo invio deve mantenere lo stesso ackId
per il servizio da annullare.
Messaggio di invio di un gruppo di esempio:
{
"type": "sendToGroup",
"group": "group1",
"dataType" : "text",
"data": "text data",
"ackId": 1
}
Risposta ack di esempio:
{
"type": "ack",
"ackId": 1,
"success": true
}
Se il servizio restituisce ack con success: true
, il messaggio è stato elaborato dal servizio e il client può aspettarsi che il messaggio venga recapitato a tutti i sottoscrittori.
In alcuni casi, tuttavia, Service soddisfa un errore interno temporaneo e il messaggio non può essere inviato al sottoscrittore. In questo caso, il server di pubblicazione riceverà un messaggio simile al seguente e dovrà inviare nuovamente un messaggio con lo stesso ackId
valore se necessario in base alla logica di business.
{
"type": "ack",
"ackId": 1,
"success": false,
"error": {
"name": "InternalServerError",
"message": "Internal server error"
}
}
L'ack del servizio può essere eliminato a causa dell'eliminazione della connessione WebSocket. Pertanto, gli editori devono ricevere una notifica quando la connessione Websocket viene eliminata e inviare nuovamente un messaggio con lo stesso ackId
dopo la riconnessione. Se il messaggio è stato effettivamente elaborato dal servizio, risponderà ack con Duplicate
e i server di pubblicazione smetteranno di inviare di nuovo il messaggio.
{
"type": "ack",
"ackId": 1,
"success": false,
"error": {
"name": "Duplicate",
"message": "Message with ack-id: 1 has been processed"
}
}
Sottoscrittore
I client che ricevono messaggi inviati da gestori eventi o server di pubblicazione vengono chiamati sottoscrittori nel documento. Quando le connessioni diminuiscono per problemi di rete, il servizio non sa quanti messaggi vengono effettivamente inviati ai sottoscrittori. Pertanto, i sottoscrittori devono indicare al servizio quale messaggio è stato ricevuto. I messaggi di dati contengono sequenceId
e i sottoscrittori devono aggiungere l'ID sequenza con un messaggio sequence ack:
Ack sequenza di esempio:
{
"type": "sequenceAck",
"sequenceId": 1
}
Sequence-id è un numero incrementale uint64 con una sessione connection-id. I Sottoscrittori devono registrare l'ID sequenza più grande ricevuto e accettare tutti i messaggi con ID sequenza più grande e eliminare tutti i messaggi con ID sequenza più piccolo o uguale. L'ack sequenza supporta l'ack cumulativo, ovvero se si esegue l'ack sequence-id=5
, il servizio tratterà tutti i messaggi con ID sequenza inferiore a 5 già ricevuti dai sottoscrittori. I sottoscrittori devono ottenere il valore di id sequenza più grande registrato, in modo che il servizio possa ignorare i messaggi di rollforward che i sottoscrittori hanno già ricevuto.
Tutti i messaggi vengono recapitati ai sottoscrittori in ordine fino a quando la connessione WebSocket non viene eliminata. Con sequence-id, il servizio può avere le informazioni sul numero di sottoscrittori di messaggi effettivamente ricevuti tra connessioni WebSocket con una sessione connection-id. Dopo l'eliminazione di una connessione WebSocket, il servizio ridistribuirà i messaggi che deve recapitare, ma non ack-ed dal sottoscrittore. Il servizio contiene messaggi che non sono ack-ed con limite, se i messaggi superano il limite, il servizio chiuderà la connessione WebSocket e rimuoverà la sessione connection-id. Di conseguenza, i sottoscrittori devono ottenere il valore sequence-id il prima possibile.