Ciclo de vida da conexão e reconexão
Uma conexão Realtime é um único WebSocket. Mudanças de rede, dispositivos em suspensão e reinicializações de infraestrutura podem fechá-la. O cliente reconecta automaticamente, e seu app pode exibir o estado atual da conexão.
Os seis estados
bird.connection.state no cliente do navegador, e bird.connectionState em Swift e Kotlin, é sempre um destes (Kotlin os representa como constantes ConnectionState, então unavailable se lê ConnectionState.UNAVAILABLE):
| Estado | O que significa |
|---|---|
| initialized | O cliente existe e ainda não abriu um socket. |
| connecting | Um socket está abrindo, ou está aberto aguardando o handshake. |
| connected | O handshake chegou. A conexão tem um ID e pode se inscrever. |
| unavailable | A conexão caiu e uma reconexão está agendada. |
| disconnected | Você chamou disconnect(). Nada está agendado. |
| failed | O servidor recusou esta conexão. O cliente não tenta novamente. |
Vincule state_change para ver todas as transições, ou vincule um único nome de estado quando apenas um importa:
import { BirdRealtime } from "@messagebird/realtime";
const bird = new BirdRealtime({ appKey: "your-app-key", region: "us1" });
bird.connection.bind("state_change", ({ previous, current }) => {
console.log(previous, "->", current);
});
bird.connection.bind("unavailable", () => showReconnectingBanner());
bird.connection.bind("connected", () => hideReconnectingBanner());import BirdRealtime
let bird = BirdRealtime(options: .init(appKey: "your-app-key", region: "us1"))
bird.onConnectionStateChange { previous, current in
print(previous, "->", current)
if current == .unavailable { showReconnectingBanner() }
if current == .connected { hideReconnectingBanner() }
}import com.bird.realtime.BirdRealtime
import com.bird.realtime.BirdRealtimeOptions
import com.bird.realtime.ConnectionState
val bird = BirdRealtime(BirdRealtimeOptions(appKey = "your-app-key", region = "us1"))
bird.onConnectionStateChange { previous, current ->
println("$previous -> $current")
if (current == ConnectionState.UNAVAILABLE) showReconnectingBanner()
if (current == ConnectionState.CONNECTED) hideReconnectingBanner()
}Swift e Kotlin usam um único observer para todas as transições, então faça branch em current. Handlers rodam na main queue em Swift e no main looper do Android em Kotlin quando disponível. Passe um deliveryQueue ou Executor para usar outro contexto de execução.
Um socket aberto permanece em connecting até o handshake do servidor chegar. O handshake define bird.connection.connectionId antes de o estado se tornar connected, para que a autorização possa assinar esse ID. Se o handshake omitir o ID, o cliente reporta um erro e fecha o socket.
Reconexão automática
Após uma queda inesperada, o cliente espera antes de abrir um novo socket. O atraso usa backoff exponencial com full-jitter, base de um segundo e limite de 30 segundos. Cada handshake bem-sucedido reinicia o backoff.
O close code decide qual das três coisas acontece:
| Close code | Comportamento |
|---|---|
| 4000 a 4099 | Recusado. Sem retry, o estado vai para failed. |
| 4200 a 4299 | Retry imediato. |
| Todo o resto | O estado vai para unavailable, depois retry com backoff. |
Falhas de rede usam o caminho de backoff. Trate os códigos de recusa na sua UI, porque essas falhas terminais não reconectam automaticamente.
A verificação de conexão obsoleta
Um socket pode parecer aberto após a falha do seu caminho de rede. O cliente envia um ping após o timeout de atividade, que por padrão é 120 segundos, a menos que o handshake forneça outro valor. Se nenhum pong chegar dentro do timeout de pong padrão de 30 segundos, o cliente fecha o socket com um código de retry imediato.
O que acontece com seus canais
As inscrições pertencem à conexão, então uma queda as remove. O cliente mantém cada objeto de canal, se reinscreve após o próximo estado connected e preserva seus handlers existentes.
O cliente chama seu authEndpoint novamente para cada canal privado e de presença usando o novo ID de conexão. Ele não pode reutilizar a assinatura anterior porque ela inclui o ID de conexão anterior. Após uma chamada signin(), o cliente também faz sign in em cada nova conexão e reporta falhas posteriores por meio de signin_error.
bird.connection.bind("signin_error", ({ message }) => {
console.warn("connection has no identity:", message);
});bird.onSigninError { error in
print("connection has no identity:", error.message)
}bird.onSigninError { error ->
println("connection has no identity: ${error.message}")
}Enquanto um canal está reconectando, channel.trigger retorna false sem enviar o evento do cliente. Verifique channel.subscribed, ou envie após bird:subscription_succeeded, que dispara após cada reinscrição bem-sucedida.
const room = bird.subscribe("presence-room-1");
room.bind("bird:subscription_succeeded", ({ members }) => {
renderMembers(members);
});guard let room = bird.subscribe("presence-room-1") as? PresenceChannel else { return }
room.bind(BirdProtocol.Event.subscriptionSucceeded) { _ in
renderMembers(room.members)
}val room = bird.subscribe("presence-room-1")
if (room is PresenceChannel) {
room.bind(BirdProtocol.Event.SUBSCRIPTION_SUCCEEDED) {
renderMembers(room.members)
}
}O Realtime não reproduz eventos publicados enquanto um cliente está desconectado. Se uma view precisa se recuperar após uma lacuna, busque o estado atual em bird:subscription_succeeded e aplique os eventos posteriores a partir daí.
Desconectando intencionalmente
bird.disconnect() fecha o socket sem agendar uma reconexão. Use quando um cliente deslogado ou inativo não precisa mais de dados em tempo real. O cliente mantém os canais, então um bird.connect() posterior reabre o socket e se reinscreve.
bird.disconnect(); // state: disconnected, no reconnect
bird.connect(); // reopens and re-subscribesbird.disconnect() // state: disconnected, no reconnect
bird.connect() // reopens and re-subscribesbird.disconnect() // state: DISCONNECTED, no reconnect
bird.connect() // reopens and re-subscribesNo mobile, desconecte quando a view ou activity relevante parar e reconecte quando ela retomar. Objetos de canal e bindings permanecem disponíveis.
Erros na conexão versus erros em um canal
Erros do servidor que pertencem a um canal chegam nesse canal. Uma inscrição recusada é o caso mais comum, e um autorizador que retorna 403 aparece aqui:
room.bind("bird:subscription_error", (err) => {
console.warn("could not join:", err);
});room.bind(BirdProtocol.Event.subscriptionError) { error in
print("could not join:", error ?? "")
}room.bind(BirdProtocol.Event.SUBSCRIPTION_ERROR) { error ->
println("could not join: $error")
}Tudo que o protocolo não atribui a um canal chega na conexão:
bird.connection.bind("error", ({ code, message }) => {
console.warn(code, message);
});bird.onError { error in
print(error.code ?? 0, error.message)
}bird.onError { error ->
println("${error.code} ${error.message}")
}Tratando o close code 4009
O código 4009 está na faixa sem retry, então a conexão entra em failed. Verifique a razão para distinguir estas situações:
- Um membro encerrado. Seu backend chamou o disconnect API para este membro, então todas as conexões que ele mantinha foram fechadas. Veja Encerrando conexões de membros.
- Uma conexão que nunca autorizou. O app exige conexões autorizadas e esta não autorizou a tempo. Veja Exigindo conexões autorizadas.
O cliente não reconecta automaticamente, então seu app decide o que acontece em seguida:
bird.connection.bind("error", ({ code }) => {
if (code === 4009) showSignedOutScreen();
});bird.onError { error in
if error.code == 4009 { showSignedOutScreen() }
}bird.onError { error ->
if (error.code == 4009) showSignedOutScreen()
}Um estado de deslogado é apropriado quando a autenticação terminou. Chamar bird.connect() inicia uma nova conexão e repete a autorização, então reconecte somente após o estado de autorização do usuário mudar.
Próximos passos
- Autorizando canais é o contrato que seu backend implementa e a solicitação que o cliente repete a cada reconexão.
- Exigindo conexões autorizadas transforma uma conexão não autorizada em uma conexão fechada.
- Encerrando conexões de membros é como uma conexão é fechada com 4009 intencionalmente.
- Visão geral do Realtime cobre canais, membros e conexões como modelo.
Recursos relacionados
Continue com a documentação, guias e exemplos sobre este tópico. Os recursos estão em inglês.
Explore a funcionalidadeRealtimeSiga o percurso de aprendizagemBuild your first integrationGuia de implementaçãoSend your first realtime event
Experimente na prática e obtenha um resumo de implementação