Pular para conteúdo

0011 — int-pied native-ready (GraalVM); imagem/deploy na fábrica

Status: Aprovado · Responsável: Gustavo Madruga · Atualizado em: 2026-09-11 · Decidido em: 2026-08-23

Contexto

A constituição fixa GraalVM native-image como o alvo de deploy do server Micronaut elegível (RD central 0022): RSS ~3× menor, imagem menor, boot rápido, e — sobretudo — o build sai do host de produção (o build-spike do shadowJar/native na VM do Coolify foi gatilho de freeze). O int-pied é elegível: server Micronaut sem Apache POI (a lib hostil ao native), então não cai na exceção JVM.

Faltava torná-lo native-ready. Este trabalho habilita o build native e prova que compila, sem trocar o deploy.

Decisão

O int-pied é native-ready: ./gradlew nativeCompile compila. A imagem native e o deploy ficam para a fábrica de imagens (central 0003) — este repo não os faz.

  • Perfil GraalVM CE no build.gradle.kts (configure<GraalVMExtension>): -Os (prod) / -Ob (-PnativeQuick, loop) + --gc=serial, baseName=app. CE 25 não tem G1/PGO/build-report; -O3==-O2.
  • docs/app.json marca native: true — discriminador que o gate do CI e o e2e native leem.
  • Gate no repo do app = nativeCompile compilar (0022 §Gate). Runtime/boot/e2e native ficam num repo de e2e separado; a imagem é buildada na fábrica (0003), fora daqui.
  • Sentry native-safe: SentryInitializer.inicializar() no main (SDK sobe antes do contexto) + reflect-config do SentryAppender em META-INF/native-image/ (o Joran o instancia por reflexão — o único hint manual recorrente da casa). Demais gaps (jackson-databind, OkHttp, @Scheduled) foram resolvidos sozinhos pelo reachability-metadata do native-build-tools + serde build-time — zero hint extra.
  • IntegradorClient deixou OkHttp e passou a falar pelo HttpClient do Micronaut (build-time, native-limpo), alinhando o transporte app↔app da casa (central 0020).

Consequências

Revisão (2026-09-09) — o native saiu do "compila" e virou alvo de deploy, aqui no repo. A primeira consequência abaixo ("não há Dockerfile.native neste repo") não vale mais: o repo ganhou o Dockerfile.native — par hermético do Dockerfile JVM — e docs/app.json declara build.targets: [jar, native]. O CI (.github/workflows/pipeline.yml) tem o job build_native (GraalVM, ~13min, mode=min e sem cache-dance — mode=max já travou o exporting to image e estourou o timeout), publica :native-amd64 e deploya jar e native lado a lado no mesmo banco (targets resolvidos por nome no control-plane, sem uuid nem ponte SSH — central 0026). Há ainda um gate de paridade Dockerfile × Dockerfile.native nos dirs app-writable sob /app, para os dois não divergirem em silêncio.

O que não mudou: o perfil GraalVM (-Os/-Ob, --gc=serial, baseName=app), o hint manual do SentryAppender, e o IntegradorClient no HttpClient do Micronaut.

Revisão (2026-09-11) — o hint do SentryAppender saiu deste repo. A xadm-comum-web 0.9.1 embarca META-INF/native-image/br.com.xadm/xadm-comum-web/reflect-config.json com as três entradas que o logback exige no native: SentryAppender e SentryOptions com construtor e métodos públicos, e ch.qos.logback.classic.Level.valueOf(String). A cópia local registrava só o appender — com ela, <options> e <minimumEventLevel> eram ignorados em silêncio e o evento do native chegava ao GlitchTip sem environment (o DSN sobrevivia porque o SDK o lê da env). O repo subiu para a 0.9.1 e apagou o reflect-config.json local no mesmo commit, como manda o §Migração da lib. A prova no binário (evento de teste com o environment certo) é do e2e native.

  • O Dockerfile JVM continua sendo o deploy (0022 §Topologia — durante a migração o repo mantém a cara JVM). Não há Dockerfile.native neste repo; a receita dockerfile-java-native vive/roda na fábrica. (Superado — ver a revisão acima.)
  • Build native local usou Oracle GraalVM (o native-image da máquina do dev) como proxy — o gate autoritativo é a fábrica em CE. O perfil (-Os/-Ob, --gc=serial) roda nos dois.
  • micronaut-http-client virou implementation. OkHttp permanece só para PIED e Resend (terceiros externos) — decisão consciente, não dívida.
  • Conflito casa×repo declarado: [0020] pede @Client declarativo, mas a integração nasce desligada (INTEGRADOR_BASE_URL vazio) e o app tem de bootar assim — um @Client(id) resolveria a URL no startup e a vazia arriscaria o boot. Escolhido HttpClient low-level (URL absoluta por chamada, guarda o vazio antes do request): tira OkHttp sem quebrar o disabled-by-default.

Pendências declaradas (§1.6 / REGRA Nº 3)

  • Reflect-config do SentryAppender deve subir para a xadm-comum-web (dona do SentryInitializer), via reachability-metadata da lib — hoje é cópia local byte-idêntica à de bi-transporte-xls/central-backend/webstorm-ecom. Enquanto não sobe, fica aqui. (Resolvida em 2026-09-11 — subiu na xadm-comum-web 0.9.1; ver a revisão acima.)
  • Imagem native + deploy Coolify + rollout/rollback + e2e ponta-a-ponta = trabalho posterior (fábrica + repo de e2e), fora deste escopo.

Alternativas descartadas

  • Buildar a imagem native no repo do app (dockerBuildNative, plugin). Contraria 0022 §Topologia (o native builda na fábrica; a wolfi-base do plugin nem traz curl, quebrando o HEALTHCHECK §5). Native aqui é só nativeCompile provando compilação.
  • Manter OkHttp no IntegradorClient. Compila em native (reachability-metadata), mas diverge do transporte app↔app da casa (0020). Trocado.