Resetar a replicação PowerSync¶
Status: Aprovado · Responsável: Gustavo Madruga · Atualizado em: 2026-09-14
Operação destrutiva
Zera o estado replicado (slot lógico do Postgres + base do PowerSync no MongoDB) e força todos os clientes mobile a um full re-sync. Leia até o fim antes de executar pela primeira vez.
O que é¶
Endpoint/tela admin que zera o estado replicado e força os clientes a refazer o sync
a partir do estado atual das tabelas bi_*. Usado para colapsar o histórico
acumulado no Mongo (bucket_data/op_log), que cresce sem parar. São 9 steps
(VALIDAR → LOCK → PAUSE → SNAPSHOT_PRE → RESET_SLOT → DROP_MONGO → RESUME →
SAMPLE_POST → FINALIZAR) executados pelo NukeReplicationService; o desenho está na
etapa 05.
Contrato: apesar do título "Resetar a replicação", o endpoint, o header e as envs mantêm o nome "nuke" (
/admin/nuke-replication,X-Confirm-Nuke,POWERSYNC_NUKE_CONFIRMATION) e a chave de sinal permaneceultimo_nuke— são contratos lidos por operadores e pelo cliente Dart; não renomear.
Quando usar¶
- Storage do Mongo passou da faixa de tolerância (limpeza mensal/trimestral).
- Após mudança de schema em
bi_*que invalide os checkpoints. - Diagnóstico de divergência entre PG e Mongo (último recurso).
Quando não usar¶
- Em horário comercial — clientes online sofrem um freeze de alguns segundos; com muitos clientes (50+), o re-bootstrap simultâneo gera carga.
- Sem janela de baixo tráfego confirmada com operação.
- Com restart manual (sem
COOLIFY_API_TOKEN): sem ter parado o PowerSync antes.
Pré-requisitos¶
Variáveis no app (tabela completa em deploy):
POWERSYNC_MONGODB_URI— sem ela, o reset só simula o drop.POWERSYNC_NUKE_CONFIRMATION— habilita o endpoint REST (a tela/adminnão depende dela).- Restart automático (recomendado):
COOLIFY_API_TOKEN+POWERSYNC_COOLIFY_NAME(ps.onpetro) ou_UUID→ a estratégiacoolifyreinicia o recurso PowerSync sozinha ao fim. Sem o token, o restart é manual. Config incompleta degrada para no-op com WARNING (o reset não quebra, mas o PowerSync não reinicia sozinho). - Postgres — aplicar uma vez, como superuser (o step
RESET_SLOTusapg_drop_replication_slot+pg_terminate_backend):Sem isso, o reset falha comALTER ROLE user_onpetro WITH REPLICATION; -- gerenciar slots GRANT pg_signal_backend TO user_onpetro; -- terminar backend de outra sessãopermission denied to use replication slots. Não dar escrita aopowersync_role(ele éSELECT-only, decisão 0013). - PowerSync — o
powersync.yamlprecisa terbi_configuracaono streamrecent_data(priority 0, sem filtro). Após mudar osync_rules, redeploy do recurso PowerSync no Coolify — senão o sinalultimo_nukeé gravado no PG mas nunca chega no cliente. - Tabela
bi_*nova replica em DOIS passos, e o 2º é EXTERNO a este repo. A migração no processador só faz oGRANT SELECTaopowersync_role(ex.V16parabi_fornecedor/bi_compra). Para o dado chegar no cliente é preciso, no repo../powersync/: (1) incluir a tabela napublicationpowersync(se ela não forFOR ALL TABLES) e (2) adicioná-la aosync_rules.yaml+ redeploy do recurso PowerSync. Sem esse passo, a tabela não replica mesmo com o GRANT aplicado — obi_comprafica populado no PG mas o Painel de Compras não vê nada.
Pré-requisitos no Coolify (só para o restart automático): Settings → API
ligado; token de Keys & Tokens com permissão de escrita/deploy; e (se a
COOLIFY_API_URL for a pública) o IP de saída do container na allowlist. Usando a
URL interna http://coolify:8080 (recomendado no mesmo daemon), a allowlist é dispensada.
Checklist antes de chamar:
- [ ] Janela de baixo tráfego confirmada.
- [ ] Só com restart manual: PowerSync parado (
docker stop powersync/kubectl scale deploy/powersync --replicas=0). Comcoolify, pule. - [ ]
POWERSYNC_NUKE_CONFIRMATIONconfigurada (só para o endpoint REST). - [ ] Disparo REST: Bearer em mãos. Disparo UI: acesso à tela
/admin. - [ ] Telegram (canal de ops) sendo monitorado.
Passos¶
Opção A — Tela /admin (recomendado)¶
- Abrir
/admin(login Google), clicar em "Resetar replicação PowerSync". - Preencher Motivo e Operador e digitar
RESETARno modal anti-acidente (a palavra destrava o submit). Confirmar. - A tela redireciona para o progresso (
/admin/nuke-replication/{id}), que recarrega sozinha a cada 3 s — os 9 steps vão sendo marcados. - Ao terminar:
SUCESSO(verde) ouERRO(vermelho, com o step e a mensagem — consultar a matriz de recovery abaixo). O botão fica desabilitado enquanto houver um resetEM_ANDAMENTO(só um por vez).
Com a estratégia coolify ativa, o PowerSync reinicia sozinho ao final.
Opção B — Endpoint REST¶
Sem
COOLIFY_API_TOKEN(restart manual): parar o PowerSync ANTES. Sem isso, o slot fica ativo e oRESET_SLOTfalha (replication slot ... is active) — a falha mais comum. Subir de volta ao fim (step 3). Comcoolify, o PAUSE/RESUME é automático e este passo é dispensável.
BASE="https://excel.onpetro.xadm.biz"
curl -X POST "$BASE/api/comercial/admin/nuke-replication" \
-H "Authorization: Bearer <BI_COMERCIAL_XLS_API_TOKEN>" \
-H "X-Confirm-Nuke: <POWERSYNC_NUKE_CONFIRMATION>" \
-H "X-Operator-Id: $USER" \
-H "Content-Type: application/json" \
-d '{"motivo": "limpeza trimestral 2026Q2"}'
# → 202 { "nukeId": 42, "status": "EM_ANDAMENTO", "linkStatus": ".../nuke-replication/42" }
Polling do status:
curl "$BASE/api/comercial/admin/nuke-replication/42" \
-H "Authorization: Bearer <BI_COMERCIAL_XLS_API_TOKEN>"
Acompanhar status (EM_ANDAMENTO → SUCESSO) e stepsCompletados. Tempo típico:
< 60 s + POWERSYNC_BOOTSTRAP_WAIT.
Subir o PowerSync de volta — só com restart manual:
docker start powersync # ou
kubectl scale deployment/powersync --replicas=1
Verificação¶
- Telegram de ops:
✅ NUKE CONCLUÍDO em N ms. - Smoke em 1 cliente mobile: reabrir o app e confirmar o re-sync (download dos
buckets atuais; o bootstrap escala com o volume de
bi_*). - O sinal
ultimo_nukeembi_configuracaoé atualizado noFINALIZAR— o cliente Dart compara com o valor local, fazdisconnectAndClear()e re-sincroniza do zero (decisão 0014; etapa 07).
Reversão / recovery por step¶
Sem rollback automático. Falha → status ERRO + Telegram ❌ NUKE FALHOU em step X.
A única ação depois da falha é o RESUME quando ela acontece em DROP_MONGO (o slot já é novo).
Resets órfãos em EM_ANDAMENTO (container morreu no meio) são marcados ERRO
automaticamente pelo NukeStartupRecovery no próximo boot ("Interrompido após
reinício da aplicação"; step_atual preservado para debug).
| Step | Estado deixado pelo erro | Recovery |
|---|---|---|
VALIDAR/LOCK |
outro reset em andamento (409 já no POST) | aguardar o concorrente terminar e re-chamar |
PAUSE |
none: no-op. coolify: API não respondeu / UUID não resolveu — nada destrutivo tocado |
sem cleanup; corrigir config/allowlist; re-chamar |
SNAPSHOT_PRE |
PG consultado, Mongo intacto | sem cleanup; re-chamar |
RESET_SLOT |
slot dropado mas não recriado | psql: SELECT * FROM pg_replication_slots WHERE slot_name='powersync'; — se vazio, SELECT pg_create_logical_replication_slot('powersync','pgoutput'); e subir o PowerSync |
DROP_MONGO |
Mongo parcial/intacto (pior caso); o nuke já tentou o RESUME |
mongosh "$URI": use <db>; db.dropDatabase(); reiniciar o PowerSync (bootstrap fresh). O <db> vem do path da POWERSYNC_MONGODB_URI |
RESUME |
destrutivo já feito, PowerSync parado | coolify: reiniciar o recurso no Coolify. none: docker start powersync / kubectl scale --replicas=1 |
SAMPLE_POST/FINALIZAR |
reset de fato OK, só a finalização falhou | SQL de emergência abaixo |
SQL de emergência (finalização falhou — fecha o reset e grava o sinal pros clientes):
-- 1. marca o reset como concluído
UPDATE xls_nuke_replication SET status = 'SUCESSO' WHERE id = N;
-- 2. grava o sinal pros clientes, se o STEP_FINALIZAR não gravou.
-- 'ultimo_nuke' é contrato (lido pelo cliente Dart) — não renomear.
INSERT INTO bi_configuracao (id, valor, tipo, sistema, atualizado_em)
VALUES ('ultimo_nuke', NOW()::TEXT, 'TIMESTAMP', TRUE, NOW())
ON CONFLICT (id) DO UPDATE SET valor = EXCLUDED.valor, atualizado_em = NOW();
Falha mais provável — RESET_SLOT por slot ativo: sintoma
replication slot ... is active; causa = PowerSync não parou antes. Diagnóstico:
SELECT slot_name, active, active_pid FROM pg_replication_slots;. Preferir parar o
PowerSync e re-chamar (a estratégia coolify faz PAUSE/RESUME sozinha). Último
recurso: kill -9 <active_pid>.
Sintomas pós-reset¶
| Sintoma | Causa provável | Ação |
|---|---|---|
| Cliente mobile não re-sincroniza ao reabrir | PowerSync não voltou a rodar | docker ps / kubectl get pods; subir o recurso |
| Bootstrap demorando (> 10 min) | volume grande em bi_* ou conexão fraca |
esperar; checar logs do PowerSync e o storage do Mongo crescendo |
| Storage Mongo voltou a crescer rápido | upsert diff-aware não está filtrando as linhas inalteradas | verificar se xls_processamento.linhas_efetivas está sendo gravado |
| Erros de checkpoint nos clientes | slot novo à frente do esperado | esperar o bootstrap; se persistir, rodar o reset de novo |
Requests prontos (IntelliJ HTTP Client / VS Code REST Client)¶
Cole num arquivo .http local e preencha os segredos com os valores do deploy
(nunca commitar os tokens reais — use variáveis de ambiente/secrets do seu cliente HTTP).
Rode em ordem: POST → GET do status, repetindo o GET até SUCESSO/ERRO.
@base_url = https://excel.onpetro.xadm.biz
@bearer_token = <BI_COMERCIAL_XLS_API_TOKEN>
@nuke_token = <POWERSYNC_NUKE_CONFIRMATION>
@operator_id = seu-usuario
### Dispara o reset — captura o nukeId da resposta
POST {{base_url}}/api/comercial/admin/nuke-replication
Authorization: Bearer {{bearer_token}}
X-Confirm-Nuke: {{nuke_token}}
X-Operator-Id: {{operator_id}}
Content-Type: application/json
{ "motivo": "limpeza trimestral" }
### Polling do status — repetir até status = SUCESSO ou ERRO (< 60s + bootstrap-wait)
GET {{base_url}}/api/comercial/admin/nuke-replication/{{nuke_id}}
Authorization: Bearer {{bearer_token}}
### Override do bootstrap-wait (útil em janela de teste curta)
POST {{base_url}}/api/comercial/admin/nuke-replication?wait_secs=10
Authorization: Bearer {{bearer_token}}
X-Confirm-Nuke: {{nuke_token}}
X-Operator-Id: {{operator_id}}
Content-Type: application/json
{ "motivo": "smoke test" }
### Listagem paginada (mais recentes primeiro; page base 0, size default 20 e máximo 100)
GET {{base_url}}/api/comercial/admin/nuke-replication?page=0&size=20
Authorization: Bearer {{bearer_token}}
A listagem responde o Page do micronaut-data (forma):
execuções em content, cada uma na forma do polling de status; total em totalSize; página e tamanho em
pageable.number/pageable.size.
Smoke checks de segurança (validam o deploy): POST sem Authorization → 401;
sem X-Confirm-Nuke ou com token errado → 403; GET .../nuke-replication/999999999 → 404.