Socket.io: Safari interrompendo a conexão do soquete da web devido à inatividade quando a página não está em foco

Criado em 25 abr. 2017  ·  26Comentários  ·  Fonte: socketio/socket.io

Você quer:

  • [x] relatar um bug
  • [] solicitar um recurso

Comportamento atual

Não tenho certeza se esse é um problema conhecido (tentei pesquisar, mas não encontrei nada). O Safari para Mac parece estar eliminando silenciosamente as conexões do websocket devido à inatividade / ociosidade se a página / guia não estiver em foco.

Etapas para reproduzir (se o comportamento atual for um bug)

Faça com que a guia / página do Safari não esteja em foco; registrar eventos de websocket.

Comportamento esperado

Websockets devem ser mantidos ativos por meio da funcionalidade de pulsação. Não vendo esse comportamento em outros navegadores, é improvável que seja meu código.

Configuração

  • SO: Mac OSX 10.12.4 (16E195)
  • navegador: Safari 10.1 (12603.1.30.0.34)
  • versão socket.io: 1.7.3

Outras informações (por exemplo, rastreamentos de pilha, problemas relacionados, sugestões de como corrigir)

É possivelmente algum tipo de recurso de economia de energia que está substituindo / ignorando os batimentos cardíacos?

bug

Comentários muito úteis

Acho que é porque a versão atual do socket.io depende do setTimeout no lado do cliente, que pode não ser tão confiável quanto o esperado.

Vamos incluir isso na v3, pois é uma alteração importante.

Relacionado: https://github.com/primus/primus/issues/348

Todos 26 comentários

O servidor em execução com DEBUG = * mostra o seguinte:
socket.io:client client close with reason ping timeout +0ms
socket.io:socket closing socket - reason ping timeout +0ms

o que presumo significa que o Safari fechou a conexão, não o servidor de soquete ou a instância do cliente. No entanto, o mais estranho é que percebi que o Safari às vezes se reconecta cerca de 30 segundos a 1 minuto depois, mas outras vezes não e permanece desconectado até que a página seja colocada em foco. É extremamente frustrante tentar depurar esse tipo de comportamento inconsistente.

Parece que às vezes ele se reconecta esporadicamente muito mais tarde (como 10 minutos). Novamente, completamente inconsistente em ambientes de teste idênticos.

@twistedpixel o atraso de reconexão é exponencial (ou seja, algo como: espere 500ms, tente reconectar, espere 1000ms, tente reconectar ...) ( fonte ), de modo que isso pode explicar o comportamento.

Que tal forçar a reconexão quando a janela obtiver o foco novamente?

window.addEventListener("focus", () => socket.connect());

Pode estar relacionado a https://github.com/primus/primus/issues/348.

Obrigado pela informação, mas o principal problema é que preciso do web socket permanentemente conectado, pois ele é usado para enviar alertas ao usuário enquanto ele está ausente. Portanto, o foco da janela para reconectar não é o ideal.

Acho que é algo mais problemático específico para minha máquina / instalação de qualquer maneira. Percebi o comportamento originalmente no meu iMac, então decidi simplesmente limpar meu MacBook com uma nova versão do Safari e não estou vendo o comportamento lá. Eu deixei uma guia minimizada por um dia inteiro e ela não desconectou nenhuma vez. Portanto, tentei voltar ao iMac e remover todos os plug-ins de internet e desabilitar todas as extensões, mas ainda assim vi esse comportamento.

A Apple não parece fornecer nenhuma maneira de reinstalar o Safari completamente, a não ser excluir suas preferências e alguns outros arquivos. Ou limpando a máquina. Parte de mim quer apenas começar do zero, mas o desenvolvedor em mim odiaria não saber qual é a causa.

Na verdade, ao seu ponto sobre as reconexões exponenciais: certamente a primeira reconexão seria, como você disse, em torno de 500ms após a desconexão ... então por que o servidor a ignoraria? Deve haver algo o impedindo de disparar a reconexão.

É um pouco estranho porque se eu colocar socket.connect() no evento de desconexão, ele se conecta novamente sem problemas. Tem que fazer isso a cada poucos minutos, mas ainda assim o faz sem falhar. Portanto, estou completamente intrigado com o porquê de uma reconexão não estar acontecendo! Vou cavar um pouco mais e ver se consigo descobrir por quê.

Esse é o comportamento típico de um navegador hoje em dia, mesmo em desktops, infelizmente.

Acho que sei o que está acontecendo. O Safari é de fato o problema.

Acho que todos os navegadores limitam os valores setTimeout e setInterval a 1000 quando a guia não está em foco. O Safari - estupidamente - limita em 1000 e faz algo como adicionar exponencialmente um atraso que resulta em cada iteração levando o dobro do tempo da última. É por isso que a conexão morre; Os tempos limites internos de socket.io estão sendo atrasados ​​/ descartados, explicando por que as reconexões não estão acontecendo quando deveriam.

Então, basicamente, a Apple decidiu ir contra a corrente, como de costume, resultando em uma experiência do usuário ruim. Eles são muito bons nisso hoje em dia.

Não descobri por que está afetando o iMac e não o MacBook (eu esperava o contrário), mas continuarei testando para ver se consigo identificar o motivo exato.

@twistedpixel não é apenas o Safari. Consulte http://blog.strml.net/2017/01/chrome-56-now-aggressively-throttles.html

Na Primus, contornamos o problema invertendo a direção das mensagens de pulsação (https://github.com/primus/primus/pull/534).

@lpinca O tempo todo em que estive tentando descobrir esse problema, fiquei me perguntando

@twistedpixel meu ponto é que o mesmo provavelmente pode ser feito no Engine.IO, então não há necessidade de migrar para o Primus.

FWIW, Safari Tech Preview não parece ser afetado pelo afogamento adicional. Talvez a Apple tenha revertido sua decisão. Ainda está acelerando para 1000 ms, mas não parece estar adicionando mais nada.

Estou tendo o mesmo problema no iOS 12 Safari. Se eu reabrir meu safari, a conexão do websocket será perdida. Existe uma solução alternativa limpa para manter o soquete ativo?

O AFAIK iOS Safari suspende certos processos quando o Safari está em segundo plano (para evitar o esgotamento da bateria) e as conexões de websocket quase certamente são um desses processos. É improvável que você encontre uma solução alternativa em dispositivos móveis.

ESTÁ BEM. Mas ainda posso me reconectar se adicionar um ouvinte de evento como onwindowfocus ou algo assim?

Alguém implementou uma solução alternativa? estamos interessados ​​em olhar as opções e saber se outras já estão experimentando

Em vez de usar eventos de foco, você precisará usar a API de visibilidade de página para detectar quando uma janela de aplicativo móvel foi colocada em segundo plano.

Encontrei o problema com o Azure SignalR e graças à sugestão de @techpeace usando atualmente a API de visibilidade da página para fechar a conexão na página oculta e reconectá-la novamente quando a página estiver visível. Mas encontrei problemas com a troca rápida de guias, que podem enviar vários eventos. Atualmente, estou procurando eliminar os eventos .. Também conselhos gerais encontrados na web desencorajam qualquer tipo de tratamento baseado na detecção do agente do usuário .. então minha solução é usar a API de visibilidade da página independentemente do agente do usuário.

Soluções

Testei por várias horas com todos os 3 desses navegadores, alterando os valores de pingTimeout & pingInterval . O que descobri serem as soluções:

  1. Configurando pingTimeout > = 30000 ms

    • ou -

  2. Configurando pingInterval <= 10000 ms

Eu acredito que a melhor solução é mudar pingTimeout = 30000 . O pingInterval padrão é 25000 ms e ​​aumentar a frequência do servidor que faz o ping dos clientes a cada 10s pode ser muito falador para projetos _em escala_.

Acho que é porque a versão atual do socket.io depende do setTimeout no lado do cliente, que pode não ser tão confiável quanto o esperado.

Vamos incluir isso na v3, pois é uma alteração importante.

Relacionado: https://github.com/primus/primus/issues/348

@darrachequesne Também estou enfrentando que quando estou no celular, se a tela do meu celular entrar no modo de espera e eu abrir o navegador novamente no celular, o socket io desconecta o chat. por favor conserte isso. será um grande alívio.

alguma atualização sobre esse bug no socket io?

no meu aplicativo, quando o usuário tenta fazer upload de um arquivo de seu navegador móvel e quando a caixa de diálogo de upload é aberta, o socket io os desconecta se eles levarem 15 segundos ou mais para selecionar um arquivo.

se eles mudarem para outra página ou guia, após 15 segundos, o soquete io novamente os desconecta, há como consertar isso e manter o soquete io ativo / conectado mesmo se o usuário não estiver na página / documento focado?

@darrachequesne

Corrigi esse problema com a API de visibilidade.

Principal problema com o Safari para mim - ele não tem tempo para fechar o socket em visible.hidden === true, então você precisa fechar o websocket após o dispositivo ser desbloqueado e iniciá-lo novamente.

@ JustFly1984 Você tem algum código de amostra para isso. Eu tenho a detecção de visibilidade funcionando corretamente, mas não consigo reconectar o soquete.

Então, agora isso está acontecendo com o MacOS Safari também, FYI.

@calendee @anilanar não estamos usando sockets.io, apenas websockets puros, e também estamos usando React.js, então o código é bem complexo. a ideia principal é que temos dois <ContextProvider /> para cada api, a visibilidade está no topo, os websockets na parte inferior e os websockets usando o contexto de visibilidade.

Obrigado por responder JustFly1984. Na verdade, no final, não precisei da API de visibilidade. Eu simplesmente preciso adicionar tempos limite. Depois de fazer isso, não tive mais problemas de conexão no iOS Safari.

// Establish a Socket.io connection
// Initialize our Feathers client application through Socket.io
// with hooks and authentication.
client.configure(feathers.socketio(socket), {
  timeout: 2000,
});
// Use localStorage to store our login token
client.configure(feathers.authentication(), {
  timeout: 2000,
});
Esta página foi útil?
0 / 5 - 0 avaliações

Questões relacionadas

MichaelJCole picture MichaelJCole  ·  3Comentários

gCurtisCT picture gCurtisCT  ·  4Comentários

varHarrie picture varHarrie  ·  3Comentários

distracteddev picture distracteddev  ·  3Comentários

doughsay picture doughsay  ·  4Comentários