PWA iOS: Salvar Edição travado em Salvando, compositor inacessível e texto ditado perdido

Encontrei um problema intermitente ao editar uma postagem existente na minha instância self-hosted do Discourse em 21 de outubro de 2026. O compositor ficou travado no estado Salvando, e não consegui retornar ao editor para recuperar alguns textos ditados.

Desde então, examinei os logs de acesso do Caddy e nginx e o histórico de revisões de postagens do Discourse.

Ambiente

  • Cliente: iPhone 16 Pro, PWA da Home Screen do Safari

  • iOS: 27.0.1

  • Discourse: 2026.10.0-latest +406 commits, conforme exibido no painel administrativo naquele dia (162 atualizações mais novas disponíveis)

  • Hospedagem: self-hosted, arquivo privado de estudo

  • Proxy reverso: Caddy v2.11.4, fornecendo HTTP/3 sobre QUIC

  • Backend: nginx do Discourse atrás do Caddy usando um socket Unix

  • Rede: inicialmente Wi-Fi universitário, seguido por celular EE

O que aconteceu

Eu estava editando uma postagem contendo uma imagem de um slide de aula de física.

Ditei notas matemáticas adicionais, incluindo frações, abaixo da imagem e, em seguida, pressionei rapidamente Salvar Edição.

A barra horizontal azul de Salvando permaneceu visível na parte inferior da tela e não concluiu.

Tentei tocar na barra de Salvando, mas isso não reabriu o compositor. Como resultado, não consegui selecionar ou copiar o texto não salvo para outro lugar.

Esperei mais tempo do que o normal.

Somente depois que a operação de Salvando já estava travada, desativei manualmente o Wi-Fi, na esperança de que a troca para o celular permitisse que a requisição fosse concluída.

A interface não se recuperou imediatamente. Também experimentei buffering ao tentar navegar usando o logotipo do site.

Quando pude editar a postagem novamente, as frações ditadas estavam ausentes.

Investigação no lado do servidor

O horário relevante foi aproximadamente 12:20 BST em 21 de outubro de 2026.

Meus logs do Caddy mostram:

Hora (BST) Requisição Resultado
12:19:39 POST /drafts.json 200
12:19:40 POST /uploads.json 200
12:19:44 POST /drafts.json 200
12:20:08 PUT /posts/70695 Status Caddy 0
12:20:55 PUT /posts/70695 200

A requisição PUT malsucedida usou HTTP/3. O Caddy registrou uma duração de aproximadamente 110 ms, enquanto o nginx registrou uma resposta HTTP 400 sem a execução do controlador de atualização de postagem do Discourse.

Numerosas outras requisições originadas da conexão celular também receberam status Caddy 0 aproximadamente no mesmo momento.

O próprio Caddy não reiniciou. O Docker relata zero reinícios desde 15 de outubro, e os logs operacionais não contêm nenhum evento correspondente de recarga ou encerramento.

Recuperação de rascunho

Houve requisições bem-sucedidas de salvamento de rascunho imediatamente antes do incidente.

No entanto, lembro o conteúdo anterior como sendo a imagem do slide sem o texto adicional ditado. Eu inseri as frações depois e pressionei Salvar Edição pouco tempo após isso.

Portanto, não posso estabelecer que a ditadura ausente estivesse incluída em qualquer um dos autosaves bem-sucedidos.

Quando inspecionei posteriormente as revisões da postagem, a revisão bem-sucedida às 12:20:55 continha a imagem, mas não as frações ditadas.

Também verifiquei os registros atuais de rascunhos, mas nem a chave antiga nem a nova de rascunho do tópico tinham um rascunho remanescente no momento da inspeção.

Comportamento esperado

Se uma requisição de edição ficar travada ou for interrompida, eu esperaria que o compositor preservasse seu conteúdo não salvo e fornecesse uma maneira de tentar novamente, cancelar ou voltar a editar.

Em particular, a interface idealmente não deve tornar o texto não salvo inacessível indefinidamente enquanto exibe Salvando.

Comportamento real

O compositor permaneceu inacessível, tocar na barra de Salvando não o reabriu, e o texto ditado não estava mais disponível quando a edição retomou.

Perguntas

  1. É esperado que o compositor permaneça inacessível indefinidamente enquanto uma requisição de edição está pendente?

  2. Existe algum mecanismo de timeout ou recuperação destinado a restaurar a edição quando uma requisição de rede é interrompida?

  3. Uma operação de Salvar Edição interrompida deveria preservar o texto em memória ou o conteúdo do rascunho, mesmo que a requisição nunca alcance o controlador de atualização de postagem do Rails?

  4. Algum registro ou instrumentação específica no lado do cliente seria útil se isso acontecer novamente no iOS?

Aprecio que a mudança de rede possa explicar as cancelamentos eventuais das requisições. No entanto, a interface de Salvando já havia ficado travada antes de eu mudar manualmente de rede.

Não estabeleci se o atraso inicial originou-se no JavaScript do Discourse, na rede iOS/WebKit ou na conexão universitária.

Discussões relacionadas

Tenho uma discussão existente sobre MPTCP / continuidade de conexão iOS, onde descrevi este mesmo incidente sob a perspectiva de transporte.

Também reportei anteriormente postagens editadas ocasionalmente permanecem desatualizadas no DiscourseHub no iOS. Aquele problema separado envolvia edições que haviam chegado com sucesso ao servidor, mas a postagem já renderizada não atualizava até uma renovação. Outro usuário relatou ter notado esse comportamento também.

Não sei se os dois problemas compartilham uma causa. O incidente atual é diferente porque a requisição inicial de edição de postagem não foi processada com sucesso.

Também encontrei dois relatórios anteriores envolvendo um compositor travado em Salvando:

Ambos tinham causas identificadas diferentes, e não estou assumindo que expliquem este incidente.

Anexei um ZIP discourse_ios_save_evidence_2026-10-21_domain_redacted.zip (6,3 KB) contendo extratos selecionados e redigidos de diagnósticos do Caddy/nginx, informações de revisão e a cronologia descrita acima.

Apreciaria qualquer conselho sobre como o compositor deve se recuperar de uma requisição estagnada, especialmente quando alterações não salvas não podem ser copiadas antes de uma interrupção de rede.

Atualização adicional após alguns problemas com PWA no iOS em 28 de outubro de 2026, agora no iOS 27.2 (iPhone 16 Pro).

Estes não foram reproduções exatas do problema original de ditado perdido, mas verifiquei os logs do Caddy e do nginx para entender o que aconteceu.

10:58 GMT — Operação de tópico travada

Ao sair da biblioteca, uma operação de tópico pareceu ficar presa na interface.

O Caddy registrou duas requisições HTTP/3 para POST /t/13515/merge-topic:

  • 10:58:16: status 0, duração aproximada de 0,15 ms.
  • 10:58:41: HTTP 200, duração aproximada de 595 ms.

A requisição bem-sucedida também aparece no nginx como topics/merge_topic, HTTP 200.

Isso confirma que uma requisição posterior foi processada com sucesso, mas não estabelece por que a requisição anterior terminou sem uma resposta concluída.

12:26 GMT — Problemas de carregamento da PWA

Enquanto estava em um auditório, não consegui carregar a PWA normalmente.

O Caddy registrou quatro requisições HTTP/3 para o bundle principal de JavaScript do Discourse, concluídas entre 12:27:05 e 12:27:42.

Todas retornaram HTTP 200 e registraram 627.219 bytes de resposta, mas suas durações foram de aproximadamente 31,4, 27,1, 29,4 e 17,3 segundos.

O mesmo recurso normalmente se completava em menos de um segundo, tanto antes quanto depois desse intervalo.

12:42 GMT — Outro problema de carregamento da PWA

Outra requisição HTTP/3 para o mesmo bundle de JavaScript levou aproximadamente 24,3 segundos.

Às 12:42:41, o Caddy também registrou uma resposta incompleta de proxy reverso HTTP/2:

aborting with incomplete response
writing: write tcp ...: connection reset by peer

O upstream era o socket Unix existente para o nginx. O erro ocorreu enquanto o Caddy estava escrevendo para a conexão TCP voltada para o cliente, em vez de ser uma falha identificada no socket Unix.

Os logs não permitem estabelecer se o reset foi iniciado pelo iOS ou pela infraestrutura de rede entre o cliente e o VPS.

Não alterei manualmente as configurações de rede do iPhone durante os dois incidentes no auditório.

Relevância para o relatório original

Reconheço que esses problemas de carregamento e de operação de tópico podem ter uma causa diferente do problema original de Salvar Edição.

No entanto, eles demonstram que a PWA do iOS encontrou atrasos substanciais nas requisições e uma resposta interrompida em circunstâncias em que dependo dela para editar notas.

Minha principal pergunta permanece se o compositor é esperado para preservar e tornar acessível o texto não salvo quando uma requisição de Salvar Edição trava, em vez de deixá-lo inacessível atrás do estado Salvando.

Ficaria grato por qualquer orientação sobre diagnósticos úteis no lado do cliente ou comportamento de recuperação pretendido do compositor.