0002 — Multi-fluxo: N Processador em série num par de arquivos único¶
Status: Aprovado · Responsável: Gustavo Madruga · Atualizado em: 2026-07-30 · Decidido em: 2026-07-30
Contexto¶
O integrador-client é o cliente coringa da plataforma: o mesmo binário envia dados de
várias origens ao X-Adm, cada origem um fluxo (zim/Fluxo.java) com suas tabelas-espelho
e seu literal de handshake. Até esta decisão o Main fixava um único Fluxo.PIED em código —
não havia como uma instalação rodar mais de um fluxo (ex. onpetro e vantroba passarão a rodar
abastecimento + MDF-e juntos). Invariante de deploy: 1 integrador-server ↔ 1
integrador-client por cliente; um cliente multi-fluxo roda um fluxo por vez no par de
arquivos único (dXpEnvio/dXpRetorno) — o handshake por arquivos e a TravaInstancia (uma
trava por pasta de dados) proíbem concorrência e instâncias separadas na mesma pasta.
Decisão¶
N Processador (um por fluxo ativo) + um scheduler serial de thread única (processo/Agendador),
no par de arquivos único. Peças:
- Config
zim.fluxos— lista de chaves de fluxo ativas, obrigatória e sem default (ausente/ vazio = exit 2 com a lista de válidos; a instalação declara o que roda). Resolvida na largada via registryFluxo.porChave(constantes = fonte da verdade; a config só as nomeia); chave inválida = exit 2. Agendadordono do laço de vida (o laço saiu doProcessador, que virou só o miolo de UM fluxo): a cada tick — ou quando o gatilho do PowerSync acorda — rodaexecutarCiclo()de cada fluxo em série, na ordem da config. A falha de um fluxo é isolada (não afoga os demais).- Guarda fluxo×schema na largada — fluxo ativo cuja tabela não está no
SchemaTabelasderruba com exit 2 (impede subir "pela metade"). - Fluxos seguem o MODELO COMUM. Adicionar um fluxo é, no geral, uma constante + um layout no
ArquivoEnvio+ espelhos no schema. OENCERRA_MDFE(tabela únicamdf) foi implementado assim:case "mdf"noArquivoEnvio(contador + tipo +chave_nota), retorno com o mesmo layout do pied. Exceções (só no retorno): o MDF-e casa por contador (Fluxo.getRetornoCasaPorContador()) — tolera vir fora de ordem (o X-Adm reordena por filial) e parcial (o ZIM aborta num conflito; oProcessadorrestaura as posições não cobertas para retentar); e um1XXdispara alerta GlitchTip (getAlertaNoErroTerminal()). Ver contrato §4.
Consequências¶
- Um lote (um
dXpEnvio) carrega somente as tabelas de UM fluxo; a serialização garante que um lote é escrito, processado, lido e apagado por completo antes do próximo — sem colisão. - Preserva o invariante "uma thread só, sem concorrência" (legibilidade é a prioridade do repo).
- O modo debug ganhou um seletor de fluxo (só com >1 ativo); com um fluxo só, console intacto.
- Co-execução real de dois fluxos é provada em integração (SQLite temp + pAbast fake); o e2e
cobre no-regression do pied (o espelho
abastecimento/mdfainda não existe no servidor).
Alternativas consideradas¶
- Diretório/par de arquivos por fluxo — exigiria mudança no lado ZIM ("programa intacto" a proíbe); descartada.
- Multi-thread (um fluxo por thread) — quebra a legibilidade sem concorrência que é a prioridade do repo; descartada.
- Instâncias separadas por fluxo na mesma pasta — a
TravaInstancia(uma por pasta) e o par de arquivos único as impediriam de conviver; multi-fluxo numa instância é a única forma coerente. - Formato de arquivo próprio para o MDF-e (linha só com a ChaveNota, retorno textual
OK/ERRO, casamento por chave) — chegou a ser implementado a partir da amostra crua do ZIM, mas foi colapsado no modelo do pied: o ZIM alinha o lado dele e o cliente reusa a máquina existente (menos código, menos superfície de erro). Sobraram divergências mínimas só no retorno (casa por contador — fora de ordem/parcial — e alerta no1XX), flags noFluxo— não uma máquina paralela. A amostra crua fica como referência.