Pular para conteúdo

Etapa 03 — Object storage do XLS recebido (Garage)

Status: Aprovado · Responsável: Gustavo Madruga · Atualizado em: 2026-06-15

Estende a recepção da etapa 01: onde o binário do .xlsx é gravado e lido.

1. Contexto e escopo

O binário do .xlsx recebido era guardado em BYTEA no Postgres, o que infla o banco com o volume de uploads. O objetivo é mover o binário para object storage S3-compatível (Garage) sem perder a rede de segurança durante a transição.

Dentro do escopo: seam de storage; 3 modos de operação; chave content-addressed; backfill no startup; tratamento de falha de I/O no upload.

Fora do escopo: CDN/cache de leitura; versionamento de objeto.

2. Componentes e modelo de dados

flowchart TB
    rec[receber upload] --> coord[ArmazenamentoArquivoService]
    coord -->|seam ArquivoXlsStorage| s3[S3ArquivoXlsStorage<br/>AWS SDK v2]
    s3 --> garage[(Garage bucket: vantroba)]
    coord -.->|modo PSQL / PSQL_GARAGE| bytea[(xls_processamento.arquivo_bytes)]

Único ponto que conhece o modo: service/ArmazenamentoArquivoService. As referências do objeto vivem em xls_processamento (V8): objeto_bucket (VARCHAR(63)), objeto_chave (VARCHAR(512)), objeto_tamanho_bytes (BIGINT); o binário no Postgres fica em arquivo_bytes (BYTEA, V1). Chave content-addressed {aaaa}/{mm}/{checksum_sha256}.xlsx, particionada pela data de referência do upload (cliente AWS SDK v2 com forcePathStyle(true) — obrigatório para o Garage).

3. Fluxos e estados

app.storage.modo / env S3_FILE_STORAGE (sempre em MAIÚSCULAS; enum ArmazenamentoModo):

Modo Grava Lê (processamento) Backfill no startup
PSQL só Postgres (arquivo_bytes) Postgres no-op
PSQL_GARAGE (default) Postgres e Garage Garage copia legados p/ Garage, mantém arquivo_bytes
GARAGE só Garage Garage migra legados e zera arquivo_bytes
  • Leitura com fallback cruzado: lê da fonte preferida do modo e recorre ao outro backend se vazia — cobre registros em transição de modo.
  • Falha de I/O no upload → StorageIndisponivelException → HTTP 503 (sem linha persistida; o cliente reenvia).
  • Backfill (StorageBackfillService, @Order(-100), roda antes do recovery): idempotente, isola falha por linha, re-enfileira PENDENTE migrado.
  • A coluna arquivo_bytes não é dropada — o "cleanup" do modo GARAGE é zerar em runtime (reversível: voltar para PSQL_GARAGE re-popula no backfill).

4. Configuração

Env Property Default
S3_FILE_STORAGE app.storage.modo PSQL_GARAGE
GARAGE_ENDPOINT garage.endpoint http://localhost:3900
GARAGE_REGION garage.region garage
GARAGE_ACCESS_KEY / GARAGE_SECRET_KEY garage.access-key/garage.secret-key dev keys
GARAGE_BUCKET garage.bucket vantroba
GARAGE_CRIAR_BUCKET garage.criar-bucket false

Prefixo migrado s3.* → garage.* na adoção do xadm-comum-storage 0.2.0 (o S3Config da lib passou a @ConfigurationProperties("garage")). Envs antigas S3_* seguem via fallback ${GARAGE_X:${S3_X:default}}. S3_FILE_STORAGE/app.storage.modo inalterado.

Em testes que não exercitam storage, fixar app.storage.modo=PSQL evita depender do Garage. Setup do cluster Garage (init manual): operacao/deploy.

5. Decisões

Nº Decisão
0008 Object storage Garage com 3 modos

6. Riscos

  • Garage indisponível no modo GARAGE → uploads recusados (503) até voltar; o modo PSQL_GARAGE mitiga durante a transição.
  • Migração irreversível por engano → mitigado: arquivo_bytes não é dropada; o modo GARAGE só zera em runtime.