<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom" xmlns:dc="http://purl.org/dc/elements/1.1/">
  <channel>
    <title>Forem: Luis Fabrício De Llamas</title>
    <description>The latest articles on Forem by Luis Fabrício De Llamas (@dellamas).</description>
    <link>https://forem.com/dellamas</link>
    <image>
      <url>https://media2.dev.to/dynamic/image/width=90,height=90,fit=cover,gravity=auto,format=auto/https:%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Fuser%2Fprofile_image%2F1142606%2F17bf7886-1330-4c13-bd13-f6e1dcbf713a.jpg</url>
      <title>Forem: Luis Fabrício De Llamas</title>
      <link>https://forem.com/dellamas</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://forem.com/feed/dellamas"/>
    <language>en</language>
    <item>
      <title>Java 26: o que são Lazy Constants e por que elas aposentam o double-checked locking (JEP 526)</title>
      <dc:creator>Luis Fabrício De Llamas</dc:creator>
      <pubDate>Fri, 03 Apr 2026 17:28:01 +0000</pubDate>
      <link>https://forem.com/dellamas/java-26-o-que-sao-lazy-constants-e-por-que-elas-aposentam-o-double-checked-locking-jep-526-4b8l</link>
      <guid>https://forem.com/dellamas/java-26-o-que-sao-lazy-constants-e-por-que-elas-aposentam-o-double-checked-locking-jep-526-4b8l</guid>
      <description>&lt;p&gt;O Java 26 trouxe o JEP 526: Lazy Constants. Uma forma nativa e thread-safe de inicializar um valor uma única vez, só quando ele for usado de verdade. Aquele synchronized com double-checked locking que você escreveu há anos? Agora tem alternativa de primeira classe.&lt;/p&gt;




&lt;h2&gt;
  
  
  O que é o JEP 526 do Java 26?
&lt;/h2&gt;

&lt;p&gt;O JEP 526 traz a classe &lt;code&gt;java.lang.LazyConstant&amp;lt;T&amp;gt;&lt;/code&gt;: um container que guarda um valor imutável, inicializado no máximo uma vez. No Java 25, a feature se chamava "Stable Values" (JEP 502). No Java 26, foi renomeada, ganhou uma API mais simples e entrou em second preview.&lt;/p&gt;

&lt;p&gt;O problema que ela resolve é antigo: campos &lt;code&gt;final&lt;/code&gt; garantem imutabilidade, mas exigem inicialização imediata. Campos não-&lt;code&gt;final&lt;/code&gt; permitem inicialização tardia, mas perdem as garantias de concorrência. &lt;code&gt;LazyConstant&lt;/code&gt; junta os dois mundos: você inicializa quando quiser, mas só uma vez, com a mesma segurança de um &lt;code&gt;final&lt;/code&gt;.&lt;/p&gt;




&lt;h2&gt;
  
  
  Por que o double-checked locking existe e qual é o problema?
&lt;/h2&gt;

&lt;p&gt;Todo dev Java já escreveu algo assim:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight java"&gt;&lt;code&gt;&lt;span class="kd"&gt;public&lt;/span&gt; &lt;span class="kd"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;MetricRegistry&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;

    &lt;span class="kd"&gt;private&lt;/span&gt; &lt;span class="kd"&gt;static&lt;/span&gt; &lt;span class="kd"&gt;volatile&lt;/span&gt; &lt;span class="nc"&gt;MetricRegistry&lt;/span&gt; &lt;span class="n"&gt;instance&lt;/span&gt;&lt;span class="o"&gt;;&lt;/span&gt;

    &lt;span class="kd"&gt;public&lt;/span&gt; &lt;span class="kd"&gt;static&lt;/span&gt; &lt;span class="nc"&gt;MetricRegistry&lt;/span&gt; &lt;span class="nf"&gt;getInstance&lt;/span&gt;&lt;span class="o"&gt;()&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
        &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;instance&lt;/span&gt; &lt;span class="o"&gt;==&lt;/span&gt; &lt;span class="kc"&gt;null&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
            &lt;span class="kd"&gt;synchronized&lt;/span&gt; &lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="nc"&gt;MetricRegistry&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;class&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
                &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;instance&lt;/span&gt; &lt;span class="o"&gt;==&lt;/span&gt; &lt;span class="kc"&gt;null&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
                    &lt;span class="n"&gt;instance&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nc"&gt;MetricRegistry&lt;/span&gt;&lt;span class="o"&gt;();&lt;/span&gt;
                &lt;span class="o"&gt;}&lt;/span&gt;
            &lt;span class="o"&gt;}&lt;/span&gt;
        &lt;span class="o"&gt;}&lt;/span&gt;
        &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;instance&lt;/span&gt;&lt;span class="o"&gt;;&lt;/span&gt;
    &lt;span class="o"&gt;}&lt;/span&gt;
&lt;span class="o"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Funciona. Mas exige &lt;code&gt;volatile&lt;/code&gt;, dois &lt;code&gt;null&lt;/code&gt; checks e um &lt;code&gt;synchronized&lt;/code&gt;. Quem lê pela primeira vez não entende rápido. A alternativa com classe interna estática é mais segura, mas continua sendo um workaround.&lt;/p&gt;

&lt;p&gt;Nenhuma dessas opções é uma abstração de primeira classe pro problema real: "inicialize isso uma vez, quando precisar, de forma segura".&lt;/p&gt;




&lt;h2&gt;
  
  
  Como o LazyConstant funciona na prática?
&lt;/h2&gt;

&lt;p&gt;Imagine um serviço de pagamento com um cliente HTTP caro de criar, que só faz sentido existir se a rota for chamada:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight java"&gt;&lt;code&gt;&lt;span class="kd"&gt;public&lt;/span&gt; &lt;span class="kd"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;PaymentService&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;

    &lt;span class="kd"&gt;private&lt;/span&gt; &lt;span class="kd"&gt;final&lt;/span&gt; &lt;span class="nc"&gt;LazyConstant&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nc"&gt;HttpClient&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;httpClient&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt;
        &lt;span class="nc"&gt;LazyConstant&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;of&lt;/span&gt;&lt;span class="o"&gt;(()&lt;/span&gt; &lt;span class="o"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="nc"&gt;HttpClient&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;newBuilder&lt;/span&gt;&lt;span class="o"&gt;()&lt;/span&gt;
            &lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;connectTimeout&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="nc"&gt;Duration&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;ofSeconds&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;5&lt;/span&gt;&lt;span class="o"&gt;))&lt;/span&gt;
            &lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;build&lt;/span&gt;&lt;span class="o"&gt;());&lt;/span&gt;

    &lt;span class="kd"&gt;public&lt;/span&gt; &lt;span class="nc"&gt;String&lt;/span&gt; &lt;span class="nf"&gt;charge&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="nc"&gt;String&lt;/span&gt; &lt;span class="n"&gt;orderId&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="nc"&gt;BigDecimal&lt;/span&gt; &lt;span class="n"&gt;amount&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
        &lt;span class="nc"&gt;HttpClient&lt;/span&gt; &lt;span class="n"&gt;client&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;httpClient&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;get&lt;/span&gt;&lt;span class="o"&gt;();&lt;/span&gt;
        &lt;span class="c1"&gt;// usa o client para chamar o gateway&lt;/span&gt;
    &lt;span class="o"&gt;}&lt;/span&gt;
&lt;span class="o"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;O &lt;code&gt;HttpClient&lt;/code&gt; só é criado na primeira chamada a &lt;code&gt;httpClient.get()&lt;/code&gt;. Depois disso, a JVM retorna o mesmo valor e pode até aplicar constant-folding. Thread-safe por construção, sem &lt;code&gt;synchronized&lt;/code&gt;, sem &lt;code&gt;volatile&lt;/code&gt;.&lt;/p&gt;




&lt;h2&gt;
  
  
  O que mudou do Java 25 para o Java 26 no JEP 526?
&lt;/h2&gt;

&lt;p&gt;No Java 25, a API coloca métodos de baixo nível como &lt;code&gt;setOrThrow&lt;/code&gt;, &lt;code&gt;trySet&lt;/code&gt; e &lt;code&gt;orElseSet&lt;/code&gt;, o que transformava a coisa num primitivo de sincronização. Ia contra o objetivo da feature.&lt;/p&gt;

&lt;p&gt;No Java 26, ficou só o &lt;code&gt;LazyConstant.of(supplier)&lt;/code&gt;. Você fornece a função de inicialização e a JVM cuida do resto.&lt;/p&gt;

&lt;p&gt;As factory methods para listas e mapas lazy também mudaram de lugar, saindo de &lt;code&gt;StableValue&lt;/code&gt; para &lt;code&gt;List&lt;/code&gt; e &lt;code&gt;Map&lt;/code&gt; diretamente:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight java"&gt;&lt;code&gt;&lt;span class="c1"&gt;// Lista lazy com 10 slots, cada um inicializado de forma independente&lt;/span&gt;
&lt;span class="nc"&gt;List&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nc"&gt;OrderProcessor&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;processors&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nc"&gt;List&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;ofLazy&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;10&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="n"&gt;_&lt;/span&gt; &lt;span class="o"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nc"&gt;OrderProcessor&lt;/span&gt;&lt;span class="o"&gt;());&lt;/span&gt;

&lt;span class="c1"&gt;// Mapa lazy com chaves definidas, valores inicializados sob demanda&lt;/span&gt;
&lt;span class="nc"&gt;Map&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nc"&gt;String&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="nc"&gt;RateLimiter&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;limiters&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nc"&gt;Map&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;ofLazy&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;
    &lt;span class="nc"&gt;Set&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;of&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"payments"&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="s"&gt;"refunds"&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="s"&gt;"reports"&lt;/span&gt;&lt;span class="o"&gt;),&lt;/span&gt;
    &lt;span class="n"&gt;key&lt;/span&gt; &lt;span class="o"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="nc"&gt;RateLimiter&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;create&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;requestsPerSecond&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;key&lt;/span&gt;&lt;span class="o"&gt;))&lt;/span&gt;
&lt;span class="o"&gt;);&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Cada slot da lista e cada entry do mapa tem seu próprio ciclo de inicialização. O slot &lt;code&gt;payments&lt;/code&gt; pode existir sem que &lt;code&gt;refunds&lt;/code&gt; tenha sido criado.&lt;/p&gt;




&lt;h2&gt;
  
  
  Qual é a diferença entre LazyConstant e um campo final normal?
&lt;/h2&gt;

&lt;p&gt;Um campo &lt;code&gt;final&lt;/code&gt; exige que o valor exista na construção do objeto. Nem sempre isso é possível: a dependência pode não estar pronta, a inicialização pode ser cara demais pro startup, ou o valor depende de algo que só acontece depois.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight java"&gt;&lt;code&gt;&lt;span class="c1"&gt;// final obriga inicialização imediata&lt;/span&gt;
&lt;span class="kd"&gt;private&lt;/span&gt; &lt;span class="kd"&gt;final&lt;/span&gt; &lt;span class="nc"&gt;ExpensiveClient&lt;/span&gt; &lt;span class="n"&gt;client&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nc"&gt;ExpensiveClient&lt;/span&gt;&lt;span class="o"&gt;();&lt;/span&gt; &lt;span class="c1"&gt;// roda no construtor&lt;/span&gt;

&lt;span class="c1"&gt;// LazyConstant inicializa na primeira chamada a .get()&lt;/span&gt;
&lt;span class="kd"&gt;private&lt;/span&gt; &lt;span class="kd"&gt;final&lt;/span&gt; &lt;span class="nc"&gt;LazyConstant&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nc"&gt;ExpensiveClient&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;client&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt;
    &lt;span class="nc"&gt;LazyConstant&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;of&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="nl"&gt;ExpensiveClient:&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt;&lt;span class="k"&gt;new&lt;/span&gt;&lt;span class="o"&gt;);&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Depois de inicializado, a JVM pode tratar o &lt;code&gt;LazyConstant&lt;/code&gt; como constante e aplicar as mesmas otimizações de um &lt;code&gt;final&lt;/code&gt; estático.&lt;/p&gt;




&lt;h2&gt;
  
  
  O que preciso saber antes de usar Lazy Constants no Java 26?
&lt;/h2&gt;

&lt;p&gt;Ainda é preview. Para compilar e rodar, você precisa de &lt;code&gt;--enable-preview&lt;/code&gt;:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;javac &lt;span class="nt"&gt;--enable-preview&lt;/span&gt; &lt;span class="nt"&gt;--release&lt;/span&gt; 26 PaymentService.java
java &lt;span class="nt"&gt;--enable-preview&lt;/span&gt; PaymentService
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;code&gt;LazyConstant&lt;/code&gt; não é &lt;code&gt;Serializable&lt;/code&gt;. Se você precisa serializar o objeto, não vai funcionar.&lt;/p&gt;

&lt;p&gt;O valor do container é imutável, mas o objeto dentro pode não ser. O &lt;code&gt;LazyConstant&lt;/code&gt; garante que a referência é atribuída uma vez. O que você faz com o objeto depois é problema seu.&lt;/p&gt;




&lt;h2&gt;
  
  
  Quando usar e quando não usar LazyConstant?
&lt;/h2&gt;

&lt;p&gt;Use quando o objeto é caro de criar, nem sempre necessário e precisa ser thread-safe sem que você gerencie sincronização na mão. Conexões de banco, clients HTTP, caches de configuração, registros de métricas.&lt;/p&gt;

&lt;p&gt;Não use quando um &lt;code&gt;final&lt;/code&gt; comum resolve, quando precisa de serialização, ou quando quer controle exato de quando a inicialização acontece. &lt;code&gt;LazyConstant&lt;/code&gt; garante que ela ocorre antes do primeiro &lt;code&gt;.get()&lt;/code&gt;, mas não no momento específico que você escolher.&lt;/p&gt;




&lt;h2&gt;
  
  
  Por que isso importa agora, sendo ainda preview?
&lt;/h2&gt;

&lt;p&gt;O double-checked locking está em produção em milhares de sistemas Java. Não porque alguém goste da complexidade, mas porque não tinha alternativa melhor. O JEP 526 é a resposta do OpenJDK pra isso.&lt;/p&gt;

&lt;p&gt;Pode mudar antes de ser finalizado. A segunda preview serve pra isso. Mas a direção é clara: a plataforma quer tratar esse padrão como abstração de primeira classe, com suporte do compilador e da JVM, não como receita de código que cada dev implementa do seu jeito.&lt;/p&gt;

&lt;p&gt;Experimentar agora com &lt;code&gt;--enable-preview&lt;/code&gt; é a forma mais direta de entender o impacto no seu código antes que a feature chegue como estável.&lt;/p&gt;




&lt;h2&gt;
  
  
  Perguntas frequentes sobre LazyConstant e JEP 526 no Java 26
&lt;/h2&gt;

&lt;p&gt;&lt;strong&gt;LazyConstant é thread-safe?&lt;/strong&gt;&lt;br&gt;
Sim. A inicialização única vale em ambientes multithread sem precisar de &lt;code&gt;synchronized&lt;/code&gt; ou &lt;code&gt;volatile&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Posso usar LazyConstant com Serializable?&lt;/strong&gt;&lt;br&gt;
Não. Se o objeto precisa de serialização, use &lt;code&gt;final&lt;/code&gt; ou outro mecanismo.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;LazyConstant substitui o padrão Singleton com classe interna estática?&lt;/strong&gt;&lt;br&gt;
Pra maioria dos casos, sim. O resultado é o mesmo, mas o código fica mais direto e a intenção fica explícita no tipo.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Preciso de Java 26 para usar essa feature?&lt;/strong&gt;&lt;br&gt;
Sim, com &lt;code&gt;--enable-preview&lt;/code&gt;. O JEP 526 é second preview e ainda não é estável.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;O que acontece se a função de inicialização lançar uma exceção?&lt;/strong&gt;&lt;br&gt;
A exceção é propagada pra quem chamou &lt;code&gt;.get()&lt;/code&gt; e o &lt;code&gt;LazyConstant&lt;/code&gt; não fica marcado como inicializado. A próxima chamada tenta de novo.&lt;/p&gt;




&lt;p&gt;Eu sou o Luis De Llamas, Developer Advocate na act digital, Oracle ACE e IBM Champion. Se quiser acompanhar mais conteúdo sobre Quarkus, Java e o que rola no ecossistema, me encontra aqui:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;a href="https://www.linkedin.com/in/luisfabriciodellamas/" rel="noopener noreferrer"&gt;LinkedIn&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://github.com/dellamas" rel="noopener noreferrer"&gt;GitHub&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;

</description>
      <category>java</category>
      <category>backend</category>
      <category>performance</category>
      <category>braziliandevs</category>
    </item>
    <item>
      <title>Java 26: o que muda quando você altera um campo final com reflection (JEP 500)</title>
      <dc:creator>Luis Fabrício De Llamas</dc:creator>
      <pubDate>Wed, 25 Mar 2026 00:16:52 +0000</pubDate>
      <link>https://forem.com/dellamas/java-26-o-que-muda-quando-voce-altera-um-campo-final-com-reflection-jep-500-4bch</link>
      <guid>https://forem.com/dellamas/java-26-o-que-muda-quando-voce-altera-um-campo-final-com-reflection-jep-500-4bch</guid>
      <description>&lt;p&gt;Outro dia eu estava preparando material para o DevConverge Buenos Aires, que acontece dia 11 de abril, e resolvi montar um exemplo rápido sobre uma das mudanças do Java 26 que eu acho que vai pegar muita gente de surpresa.&lt;/p&gt;

&lt;p&gt;Não é HTTP/3. Não é o G1 mais rápido. É algo que parece simples, mas mexe com a fundação de como a gente escreve Java há anos: o JEP 500, chamado "Prepare to Make Final Mean Final", que começa a emitir warnings quando alguém muta um campo &lt;code&gt;final&lt;/code&gt; usando reflection.&lt;/p&gt;

&lt;p&gt;E sim, eu sei. Você provavelmente já fez isso. Eu também já fiz.&lt;/p&gt;

&lt;h2&gt;
  
  
  O que é o JEP 500 do Java 26?
&lt;/h2&gt;

&lt;p&gt;O JEP 500 é uma mudança no Java 26 que emite um aviso em tempo de execução sempre que um campo declarado como &lt;code&gt;final&lt;/code&gt; é alterado via deep reflection. Essa alteração faz parte da iniciativa "Integrity by Default" do OpenJDK, que pretende garantir que o modificador &lt;code&gt;final&lt;/code&gt; seja respeitado de verdade pela JVM.&lt;/p&gt;

&lt;p&gt;No Java 26, o comportamento padrão é emitir um warning. Em uma versão futura do JDK, esse warning será substituído por uma &lt;code&gt;IllegalAccessException&lt;/code&gt;, bloqueando a mutação de campos &lt;code&gt;final&lt;/code&gt; por padrão.&lt;/p&gt;

&lt;h2&gt;
  
  
  Por que era possível alterar campos final com reflection em Java?
&lt;/h2&gt;

&lt;p&gt;Quando você declara um campo como &lt;code&gt;final&lt;/code&gt; em Java, a ideia é clara: esse valor não muda depois que o objeto é construído. É um contrato. O compilador confia nisso. &lt;/p&gt;

&lt;p&gt;Mas desde o JDK 5, a API de reflection permite quebrar essa promessa. Chamando &lt;code&gt;setAccessible(true)&lt;/code&gt; e depois &lt;code&gt;Field.set(...)&lt;/code&gt;, o campo &lt;code&gt;final&lt;/code&gt; era alterado sem nenhum aviso. &lt;/p&gt;

&lt;p&gt;Isso nasceu para suportar serialização. A JVM precisava reconstruir objetos a partir de streams, inclusive com campos &lt;code&gt;final&lt;/code&gt;, e não tinha outro jeito. Com o tempo, frameworks de injeção de dependência, ORMs como Hibernate, libs de mocking como Mockito e ferramentas de teste adotaram o mesmo truque. A brecha virou padrão de mercado.&lt;/p&gt;

&lt;p&gt;O resultado? O modificador &lt;code&gt;final&lt;/code&gt; nunca significou imutabilidade real na JVM. Até o Java 26.&lt;/p&gt;

&lt;h2&gt;
  
  
  Como o warning do JEP 500 aparece na prática?
&lt;/h2&gt;

&lt;p&gt;Quando um campo &lt;code&gt;final&lt;/code&gt; é mutado via reflection no Java 26, o runtime emite uma mensagem como esta:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;WARNING: final field apiKey in class PaymentGatewayConfig has been mutated
reflectively by class ConfigOverrideTest in module ALL-UNNAMED.
WARNING: Use --enable-final-field-mutation=ALL-UNNAMED to avoid a warning
WARNING: Mutating final fields will be blocked in a future release unless
final field mutation is enabled
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;O código continua rodando. Mas o recado é claro: essa prática tem data de validade.&lt;/p&gt;

&lt;h2&gt;
  
  
  Exemplo prático: configuração de gateway de pagamento
&lt;/h2&gt;

&lt;p&gt;Para não ficar abstrato, pensa num cenário que todo dev backend já viu. Uma classe de configuração de gateway de pagamento com campos &lt;code&gt;final&lt;/code&gt;:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight java"&gt;&lt;code&gt;&lt;span class="kd"&gt;public&lt;/span&gt; &lt;span class="kd"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;PaymentGatewayConfig&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;

    &lt;span class="kd"&gt;private&lt;/span&gt; &lt;span class="kd"&gt;final&lt;/span&gt; &lt;span class="nc"&gt;String&lt;/span&gt; &lt;span class="n"&gt;apiKey&lt;/span&gt;&lt;span class="o"&gt;;&lt;/span&gt;
    &lt;span class="kd"&gt;private&lt;/span&gt; &lt;span class="kd"&gt;final&lt;/span&gt; &lt;span class="nc"&gt;String&lt;/span&gt; &lt;span class="n"&gt;merchantId&lt;/span&gt;&lt;span class="o"&gt;;&lt;/span&gt;
    &lt;span class="kd"&gt;private&lt;/span&gt; &lt;span class="kd"&gt;final&lt;/span&gt; &lt;span class="nc"&gt;String&lt;/span&gt; &lt;span class="n"&gt;environment&lt;/span&gt;&lt;span class="o"&gt;;&lt;/span&gt;

    &lt;span class="kd"&gt;public&lt;/span&gt; &lt;span class="nf"&gt;PaymentGatewayConfig&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="nc"&gt;String&lt;/span&gt; &lt;span class="n"&gt;apiKey&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="nc"&gt;String&lt;/span&gt; &lt;span class="n"&gt;merchantId&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="nc"&gt;String&lt;/span&gt; &lt;span class="n"&gt;environment&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
        &lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;apiKey&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;apiKey&lt;/span&gt;&lt;span class="o"&gt;;&lt;/span&gt;
        &lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;merchantId&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;merchantId&lt;/span&gt;&lt;span class="o"&gt;;&lt;/span&gt;
        &lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;environment&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;environment&lt;/span&gt;&lt;span class="o"&gt;;&lt;/span&gt;
    &lt;span class="o"&gt;}&lt;/span&gt;

    &lt;span class="kd"&gt;public&lt;/span&gt; &lt;span class="nc"&gt;String&lt;/span&gt; &lt;span class="nf"&gt;apiKey&lt;/span&gt;&lt;span class="o"&gt;()&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt; &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;apiKey&lt;/span&gt;&lt;span class="o"&gt;;&lt;/span&gt; &lt;span class="o"&gt;}&lt;/span&gt;
    &lt;span class="kd"&gt;public&lt;/span&gt; &lt;span class="nc"&gt;String&lt;/span&gt; &lt;span class="nf"&gt;merchantId&lt;/span&gt;&lt;span class="o"&gt;()&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt; &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;merchantId&lt;/span&gt;&lt;span class="o"&gt;;&lt;/span&gt; &lt;span class="o"&gt;}&lt;/span&gt;
    &lt;span class="kd"&gt;public&lt;/span&gt; &lt;span class="nc"&gt;String&lt;/span&gt; &lt;span class="nf"&gt;environment&lt;/span&gt;&lt;span class="o"&gt;()&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt; &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;environment&lt;/span&gt;&lt;span class="o"&gt;;&lt;/span&gt; &lt;span class="o"&gt;}&lt;/span&gt;
&lt;span class="o"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Esses campos são &lt;code&gt;final&lt;/code&gt; por uma razão. Depois que o gateway é configurado, ninguém deveria conseguir trocar a &lt;code&gt;apiKey&lt;/code&gt; em runtime. Não é só boa prática, é integridade de negócio.&lt;/p&gt;

&lt;p&gt;Agora imagina um teste, ou pior, uma lib, que faz isso nos bastidores:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight java"&gt;&lt;code&gt;&lt;span class="nc"&gt;PaymentGatewayConfig&lt;/span&gt; &lt;span class="n"&gt;config&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nc"&gt;PaymentGatewayConfig&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;
    &lt;span class="s"&gt;"sk_live_abc123"&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="s"&gt;"merchant_456"&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="s"&gt;"production"&lt;/span&gt;
&lt;span class="o"&gt;);&lt;/span&gt;

&lt;span class="nc"&gt;Field&lt;/span&gt; &lt;span class="n"&gt;apiKeyField&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nc"&gt;PaymentGatewayConfig&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;class&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;getDeclaredField&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"apiKey"&lt;/span&gt;&lt;span class="o"&gt;);&lt;/span&gt;
&lt;span class="n"&gt;apiKeyField&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;setAccessible&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="kc"&gt;true&lt;/span&gt;&lt;span class="o"&gt;);&lt;/span&gt;
&lt;span class="n"&gt;apiKeyField&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;set&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;config&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="s"&gt;"sk_test_override"&lt;/span&gt;&lt;span class="o"&gt;);&lt;/span&gt;

&lt;span class="nc"&gt;System&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;out&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;println&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;config&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;apiKey&lt;/span&gt;&lt;span class="o"&gt;());&lt;/span&gt; &lt;span class="c1"&gt;// sk_test_override&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Até o Java 25, isso passava sem nenhum sinal. No Java 26, o warning aparece. E ele está te dizendo: arruma isso enquanto dá tempo.&lt;/p&gt;

&lt;h2&gt;
  
  
  Quais são os modos de controle do JEP 500?
&lt;/h2&gt;

&lt;p&gt;O JEP 500 introduz a flag de linha de comando &lt;code&gt;--illegal-final-field-mutation&lt;/code&gt; com três comportamentos possíveis:&lt;/p&gt;

&lt;p&gt;O modo &lt;code&gt;warn&lt;/code&gt; é o padrão no Java 26. O campo &lt;code&gt;final&lt;/code&gt; é mutado normalmente, mas o runtime emite o aviso na primeira ocorrência.&lt;/p&gt;

&lt;p&gt;O modo &lt;code&gt;debug&lt;/code&gt; funciona igual ao &lt;code&gt;warn&lt;/code&gt;, mas inclui a stack trace completa. Se você tem um projeto grande com dezenas de dependências, esse é o modo que vai te mostrar de onde vem cada mutação.&lt;/p&gt;

&lt;p&gt;O modo &lt;code&gt;deny&lt;/code&gt; lança &lt;code&gt;IllegalAccessException&lt;/code&gt; direto. Esse será o comportamento padrão em uma versão futura do JDK.&lt;/p&gt;

&lt;p&gt;Se você quer se antecipar de verdade, roda seus testes assim:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;java &lt;span class="nt"&gt;--illegal-final-field-mutation&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;deny &lt;span class="nt"&gt;-jar&lt;/span&gt; minha-app.jar
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Se quebrar, você acaba de encontrar exatamente o que precisa corrigir.&lt;/p&gt;

&lt;h2&gt;
  
  
  Como permitir mutação de campos final em módulos específicos?
&lt;/h2&gt;

&lt;p&gt;Nem toda dependência pode ser atualizada amanhã. O JEP 500 prevê isso e oferece um escape cirúrgico por módulo com a flag &lt;code&gt;--enable-final-field-mutation&lt;/code&gt;:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;java &lt;span class="nt"&gt;--enable-final-field-mutation&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;com.minha.lib.legada &lt;span class="nt"&gt;-jar&lt;/span&gt; minha-app.jar
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Isso permite rodar com &lt;code&gt;deny&lt;/code&gt; no geral e abrir exceção só para os módulos que realmente precisam. Para código em classpath, o famoso &lt;code&gt;ALL-UNNAMED&lt;/code&gt;:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;java &lt;span class="nt"&gt;--enable-final-field-mutation&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;ALL-UNNAMED &lt;span class="nt"&gt;-jar&lt;/span&gt; minha-app.jar
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Não é um "libera tudo". É um "eu sei o que estou fazendo aqui, e documentei o motivo".&lt;/p&gt;

&lt;h2&gt;
  
  
  Como auditar mutações de campos final com JDK Flight Recorder?
&lt;/h2&gt;

&lt;p&gt;Se você quer uma visão mais ampla do que está acontecendo em produção ou staging, o JEP 500 integra com o JDK Flight Recorder (JFR) através do evento &lt;code&gt;jdk.FinalFieldMutation&lt;/code&gt;:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;java &lt;span class="nt"&gt;-XX&lt;/span&gt;:StartFlightRecording:filename&lt;span class="o"&gt;=&lt;/span&gt;recording.jfr &lt;span class="nt"&gt;-jar&lt;/span&gt; minha-app.jar
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Depois:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;jfr print &lt;span class="nt"&gt;--events&lt;/span&gt; jdk.FinalFieldMutation recording.jfr
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Isso mostra cada campo &lt;code&gt;final&lt;/code&gt; que foi mutado, por qual classe, em qual módulo. Em um sistema com muitas dependências, essa é a forma mais honesta de fazer o levantamento sem ficar adivinhando.&lt;/p&gt;

&lt;h2&gt;
  
  
  Quais frameworks e bibliotecas Java são afetados pelo JEP 500?
&lt;/h2&gt;

&lt;p&gt;A mutação de campos &lt;code&gt;final&lt;/code&gt; via reflection não é exclusiva de testes. Diversos tipos de bibliotecas e frameworks Java usam essa técnica: frameworks de ORM como Hibernate, bibliotecas de serialização como Jackson em certos cenários, ferramentas de mocking como Mockito e frameworks de injeção de dependência.&lt;/p&gt;

&lt;p&gt;O escopo costuma ser maior do que a gente imagina. A recomendação é rodar os testes com &lt;code&gt;--illegal-final-field-mutation=debug&lt;/code&gt; para descobrir todas as ocorrências com stack traces completas.&lt;/p&gt;

&lt;h2&gt;
  
  
  Qual é a melhor estratégia para se preparar para o JEP 500?
&lt;/h2&gt;

&lt;p&gt;Ignorar os warnings porque "ainda funciona" não é estratégia. O Java segue sempre o mesmo caminho: warning primeiro, exception depois. Foi assim com &lt;code&gt;--add-opens&lt;/code&gt;, foi assim com acesso a internals. A janela de preparação é agora.&lt;/p&gt;

&lt;p&gt;Mas também não faz sentido ligar &lt;code&gt;deny&lt;/code&gt; em produção amanhã cedo. Começa pelo CI. Roda a suite de testes com &lt;code&gt;--illegal-final-field-mutation=debug&lt;/code&gt;, olha as stack traces, classifica o que é código seu e o que é dependência. Atualiza o que dá pra atualizar. Documenta o que precisa do escape. Depois avança para staging, e só então para produção.&lt;/p&gt;

&lt;p&gt;Grava uma sessão com JFR em staging para pegar mutações que só aparecem em fluxos reais de aplicação, não cobertos por testes unitários. Depois sobe o CI com &lt;code&gt;deny&lt;/code&gt; ativado para garantir que nenhuma regressão passe despercebida.&lt;/p&gt;

&lt;h2&gt;
  
  
  Por que isso importa agora
&lt;/h2&gt;

&lt;p&gt;Esse é o tipo de mudança que não aparece no radar de quem olha só release notes por cima. Mas pra quem mantém sistemas em produção, é uma das mais relevantes do Java 26.&lt;/p&gt;

&lt;p&gt;Inclusive, é exatamente esse tipo de conversa que queremos trazer no [DevConverge Buenos Aires], dia 11 de abril. A proposta é conectar devs de toda a América Latina pra falar sobre o que realmente muda no dia a dia: Java, IA, DevOps, automação. Se você constrói software e está por Buenos Aires, chega junto.&lt;/p&gt;

&lt;p&gt;Voltando ao JEP 500: o valor real não está no warning. Está em usar essa janela de preparação para auditar o que roda no seu projeto antes que o comportamento padrão mude.&lt;/p&gt;

&lt;p&gt;Em um sistema como gateway de pagamento, plataforma de e-commerce, serviço financeiro ou qualquer backend onde integridade de configuração importa, essa mudança é relevante. Não quando o &lt;code&gt;deny&lt;/code&gt; virar padrão. Agora.&lt;/p&gt;

&lt;h2&gt;
  
  
  Perguntas frequentes sobre o JEP 500 e campos final no Java 26
&lt;/h2&gt;

&lt;p&gt;&lt;strong&gt;O JEP 500 já bloqueia a mutação de campos final no Java 26?&lt;/strong&gt;&lt;br&gt;
Não. No Java 26, o comportamento padrão é apenas emitir um warning. O bloqueio com &lt;code&gt;IllegalAccessException&lt;/code&gt; será o padrão em uma versão futura do JDK.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Qual a diferença entre &lt;code&gt;--illegal-final-field-mutation&lt;/code&gt; e &lt;code&gt;--enable-final-field-mutation&lt;/code&gt;?&lt;/strong&gt;&lt;br&gt;
A flag &lt;code&gt;--illegal-final-field-mutation&lt;/code&gt; controla o comportamento global (warn, debug ou deny). A flag &lt;code&gt;--enable-final-field-mutation&lt;/code&gt; permite habilitar a mutação seletivamente para módulos específicos, funcionando como um escape controlado.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Records são afetados pelo JEP 500?&lt;/strong&gt;&lt;br&gt;
Não. Os campos implicitamente declarados em records já não permitiam mutação via deep reflection antes do Java 26. O JEP 500 alinha o comportamento de classes normais com o que records já faziam.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Como saber se minhas dependências mutam campos final?&lt;/strong&gt;&lt;br&gt;
Rode sua aplicação ou testes com &lt;code&gt;--illegal-final-field-mutation=debug&lt;/code&gt; para ver warnings com stack trace completa. Para produção, use o JDK Flight Recorder com o evento &lt;code&gt;jdk.FinalFieldMutation&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Preciso atualizar meu código agora?&lt;/strong&gt;&lt;br&gt;
Sim, é recomendável começar a auditoria agora. A transição de warning para exception seguirá o mesmo padrão de outras mudanças de integridade do JDK. Quanto antes você identificar as ocorrências, mais tranquila será a migração.&lt;/p&gt;

&lt;p&gt;Eu sou o Luis De Llamas, Developer Advocate na act digital, Oracle ACE e IBM Champion. Se quiser acompanhar mais conteúdo sobre Quarkus, Java e o que rola no ecossistema, me encontra aqui:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;a href="https://www.linkedin.com/in/luisfabriciodellamas/" rel="noopener noreferrer"&gt;LinkedIn&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://github.com/dellamas" rel="noopener noreferrer"&gt;GitHub&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Nos vemos!&lt;/p&gt;

</description>
      <category>java</category>
      <category>backeend</category>
      <category>security</category>
      <category>reflection</category>
    </item>
    <item>
      <title>Testei o HttpClient do Java 26 com HTTP/3 em um agregador de viagens. E isso é o que realmente importa</title>
      <dc:creator>Luis Fabrício De Llamas</dc:creator>
      <pubDate>Mon, 23 Mar 2026 00:57:19 +0000</pubDate>
      <link>https://forem.com/dellamas/testei-o-httpclient-do-java-26-com-http3-em-um-agregador-de-viagens-e-isso-e-o-que-realmente-i60</link>
      <guid>https://forem.com/dellamas/testei-o-httpclient-do-java-26-com-http3-em-um-agregador-de-viagens-e-isso-e-o-que-realmente-i60</guid>
      <description>&lt;h1&gt;
  
  
  Testei o HttpClient do Java 26 com HTTP/3 em um agregador de viagens. E isso é o que realmente importa
&lt;/h1&gt;

&lt;p&gt;Se você trabalha com sistemas backend que dependem de APIs externas, já sabe que o problema nem sempre está no seu código.&lt;/p&gt;

&lt;p&gt;Às vezes, o gargalo real está no caminho entre o seu serviço e os sistemas de terceiros.&lt;/p&gt;

&lt;p&gt;É por isso que o suporte a HTTP/3 no &lt;code&gt;HttpClient&lt;/code&gt; do Java 26 é realmente interessante. Não porque “suporte a novo protocolo” fica bonito em release note, mas porque isso pode mudar o comportamento de aplicações Java que dependem de múltiplos serviços remotos sob pressão de latência.&lt;/p&gt;

&lt;p&gt;Para não ficar só na teoria, eu montei uma aplicação demo com um cenário de agregador de viagens. O projeto está aqui:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://github.com/dellamas/java26-http3-travel-aggregator-demo" rel="noopener noreferrer"&gt;https://github.com/dellamas/java26-http3-travel-aggregator-demo&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;A ideia foi simular um backend que consulta múltiplos fornecedores em paralelo para consolidar opções de hospedagem, algo bem mais próximo do mundo real do que um exemplo genérico de chamada HTTP isolada.&lt;/p&gt;

&lt;p&gt;Depois de analisar as mudanças do &lt;code&gt;HttpClient&lt;/code&gt; no Java 26, o suporte a HTTP/3 e montar esse exemplo, a conclusão mais importante foi simples:&lt;/p&gt;

&lt;p&gt;HTTP/3 importa, mas o protocolo em si não é a história completa. O que realmente importa é como você decide usar isso.&lt;/p&gt;

&lt;h2&gt;
  
  
  Um contexto mais realista
&lt;/h2&gt;

&lt;p&gt;Imagine uma API de agregação de viagens. O cliente faz uma busca por hotéis em Gramado ( saudades, por sinal!), e o seu serviço precisa consultar múltiplos provedores antes de devolver a resposta final.&lt;/p&gt;

&lt;p&gt;Uma única requisição pode disparar chamadas para:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;uma API de fornecedores de hospedagem&lt;/li&gt;
&lt;li&gt;um serviço de precificação&lt;/li&gt;
&lt;li&gt;uma API de avaliações&lt;/li&gt;
&lt;li&gt;um serviço de cupons ou fidelidade&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Esse tipo de fluxo é comum em marketplaces, plataformas de reserva, integrações financeiras e sistemas logísticos.&lt;/p&gt;

&lt;p&gt;Nesse cenário, pequenos atrasos se acumulam rápido. Uma única chamada externa mais lenta pode puxar para baixo o tempo total de resposta. E quando a rede está instável, comportamento de fallback e recuperação passam a importar ainda mais.&lt;/p&gt;

&lt;p&gt;É aqui que HTTP/3 começa a ficar interessante.&lt;/p&gt;

&lt;h2&gt;
  
  
  O que mudou no Java 26
&lt;/h2&gt;

&lt;p&gt;O Java 26 adicionou suporte a HTTP/3 no &lt;code&gt;java.net.http.HttpClient&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;Isso significa que agora você pode preferir explicitamente &lt;code&gt;HTTP_3&lt;/code&gt; ao construir um client ou uma request.&lt;/p&gt;

&lt;p&gt;Um exemplo simples fica assim:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight java"&gt;&lt;code&gt;&lt;span class="nc"&gt;HttpClient&lt;/span&gt; &lt;span class="n"&gt;client&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nc"&gt;HttpClient&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;newBuilder&lt;/span&gt;&lt;span class="o"&gt;()&lt;/span&gt;
        &lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;version&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="nc"&gt;HttpClient&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;Version&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;HTTP_3&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt;
        &lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;build&lt;/span&gt;&lt;span class="o"&gt;();&lt;/span&gt;

&lt;span class="nc"&gt;HttpRequest&lt;/span&gt; &lt;span class="n"&gt;request&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nc"&gt;HttpRequest&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;newBuilder&lt;/span&gt;&lt;span class="o"&gt;()&lt;/span&gt;
        &lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;uri&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="no"&gt;URI&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;create&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"https://api.parceiro-viagens.com/hoteis/busca"&lt;/span&gt;&lt;span class="o"&gt;))&lt;/span&gt;
        &lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;header&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"Accept"&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="s"&gt;"application/json"&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt;
        &lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;POST&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="nc"&gt;HttpRequest&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;BodyPublishers&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;ofString&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;"""
                {
                  \"destino\": \"Gramado\",
                  \"checkIn\": \"2026-04-10\",
                  \"checkOut\": \"2026-04-13\",
                  \"hospedes\": 2
                }
                """&lt;/span&gt;&lt;span class="o"&gt;))&lt;/span&gt;
        &lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;build&lt;/span&gt;&lt;span class="o"&gt;();&lt;/span&gt;

&lt;span class="nc"&gt;HttpResponse&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nc"&gt;String&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;response&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt;
        &lt;span class="n"&gt;client&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;send&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;request&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="nc"&gt;HttpResponse&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;BodyHandlers&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;ofString&lt;/span&gt;&lt;span class="o"&gt;());&lt;/span&gt;

&lt;span class="nc"&gt;System&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;out&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;println&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;response&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;statusCode&lt;/span&gt;&lt;span class="o"&gt;());&lt;/span&gt;
&lt;span class="nc"&gt;System&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;out&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;println&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;response&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;version&lt;/span&gt;&lt;span class="o"&gt;());&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Essa é a parte fácil.&lt;/p&gt;

&lt;p&gt;A parte mais importante é decidir como sua aplicação deve se comportar quando o serviço remoto não suporta HTTP/3, ou quando suporta, mas nem sempre essa é a melhor escolha.&lt;/p&gt;

&lt;h2&gt;
  
  
  Um exemplo com código mais próximo de aplicação real
&lt;/h2&gt;

&lt;p&gt;Na demo que eu subi no GitHub, a aplicação usa &lt;code&gt;HttpClient&lt;/code&gt;, virtual threads, timeouts explícitos e um fan out simples para múltiplos fornecedores.&lt;/p&gt;

&lt;p&gt;O coração do exemplo é este:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight java"&gt;&lt;code&gt;&lt;span class="nc"&gt;HttpClient&lt;/span&gt; &lt;span class="n"&gt;client&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nc"&gt;HttpClient&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;newBuilder&lt;/span&gt;&lt;span class="o"&gt;()&lt;/span&gt;
        &lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;version&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="nc"&gt;HttpClient&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;Version&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;HTTP_2&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt;
        &lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;connectTimeout&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="nc"&gt;Duration&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;ofSeconds&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;2&lt;/span&gt;&lt;span class="o"&gt;))&lt;/span&gt;
        &lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;build&lt;/span&gt;&lt;span class="o"&gt;();&lt;/span&gt;

&lt;span class="nc"&gt;List&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="no"&gt;URI&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;fornecedores&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nc"&gt;List&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;of&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;
        &lt;span class="no"&gt;URI&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;create&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"https://api.fornecedor-a.com/hoteis/busca"&lt;/span&gt;&lt;span class="o"&gt;),&lt;/span&gt;
        &lt;span class="no"&gt;URI&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;create&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"https://api.fornecedor-b.com/hoteis/busca"&lt;/span&gt;&lt;span class="o"&gt;),&lt;/span&gt;
        &lt;span class="no"&gt;URI&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;create&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"https://api.fornecedor-c.com/hoteis/busca"&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt;
&lt;span class="o"&gt;);&lt;/span&gt;

&lt;span class="k"&gt;try&lt;/span&gt; &lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="kt"&gt;var&lt;/span&gt; &lt;span class="n"&gt;executor&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nc"&gt;Executors&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;newVirtualThreadPerTaskExecutor&lt;/span&gt;&lt;span class="o"&gt;())&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
    &lt;span class="nc"&gt;List&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nc"&gt;Future&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nc"&gt;String&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;futures&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;fornecedores&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;stream&lt;/span&gt;&lt;span class="o"&gt;()&lt;/span&gt;
            &lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;map&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;uri&lt;/span&gt; &lt;span class="o"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;executor&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;submit&lt;/span&gt;&lt;span class="o"&gt;(()&lt;/span&gt; &lt;span class="o"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
                &lt;span class="nc"&gt;HttpRequest&lt;/span&gt; &lt;span class="n"&gt;request&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nc"&gt;HttpRequest&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;newBuilder&lt;/span&gt;&lt;span class="o"&gt;()&lt;/span&gt;
                        &lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;uri&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;uri&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt;
                        &lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;timeout&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="nc"&gt;Duration&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;ofSeconds&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;3&lt;/span&gt;&lt;span class="o"&gt;))&lt;/span&gt;
                        &lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;header&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"Content-Type"&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="s"&gt;"application/json"&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt;
                        &lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;POST&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="nc"&gt;HttpRequest&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;BodyPublishers&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;ofString&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;payload&lt;/span&gt;&lt;span class="o"&gt;))&lt;/span&gt;
                        &lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;build&lt;/span&gt;&lt;span class="o"&gt;();&lt;/span&gt;

                &lt;span class="nc"&gt;HttpResponse&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nc"&gt;String&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;response&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt;
                        &lt;span class="n"&gt;client&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;send&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;request&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="nc"&gt;HttpResponse&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;BodyHandlers&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;ofString&lt;/span&gt;&lt;span class="o"&gt;());&lt;/span&gt;

                &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;response&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;statusCode&lt;/span&gt;&lt;span class="o"&gt;()&lt;/span&gt; &lt;span class="o"&gt;&amp;gt;=&lt;/span&gt; &lt;span class="mi"&gt;400&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
                    &lt;span class="k"&gt;throw&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nf"&gt;IllegalStateException&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"Fornecedor falhou: "&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="n"&gt;uri&lt;/span&gt;&lt;span class="o"&gt;);&lt;/span&gt;
                &lt;span class="o"&gt;}&lt;/span&gt;

                &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;response&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;body&lt;/span&gt;&lt;span class="o"&gt;();&lt;/span&gt;
            &lt;span class="o"&gt;}))&lt;/span&gt;
            &lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;toList&lt;/span&gt;&lt;span class="o"&gt;();&lt;/span&gt;

    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;futures&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;stream&lt;/span&gt;&lt;span class="o"&gt;().&lt;/span&gt;&lt;span class="na"&gt;map&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="nl"&gt;Future:&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt;&lt;span class="n"&gt;get&lt;/span&gt;&lt;span class="o"&gt;).&lt;/span&gt;&lt;span class="na"&gt;toList&lt;/span&gt;&lt;span class="o"&gt;();&lt;/span&gt;
&lt;span class="o"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Na demo, eu deixei &lt;code&gt;HTTP_2&lt;/code&gt; por padrão para manter o projeto estável e executável em ambiente comum. Mas o ponto do artigo continua valendo: quando você estiver em Java 26 com suporte a HTTP/3 disponível, a decisão relevante não é só trocar a versão do protocolo. É medir o impacto em um cenário real.&lt;/p&gt;

&lt;h2&gt;
  
  
  Por que HTTP/3 interessa para backend
&lt;/h2&gt;

&lt;p&gt;Do ponto de vista de funcionalidade, HTTP/3 não parece revolucionário quando comparado com HTTP/2.&lt;/p&gt;

&lt;p&gt;A grande diferença está por baixo.&lt;/p&gt;

&lt;p&gt;HTTP/2 roda sobre TCP.&lt;br&gt;
HTTP/3 roda sobre QUIC, que usa UDP.&lt;/p&gt;

&lt;p&gt;Essa mudança afeta comportamento de conexão, recuperação e performance, principalmente em cenários com perda de pacote, instabilidade de rede ou reconexões frequentes.&lt;/p&gt;

&lt;p&gt;Na prática, isso torna HTTP/3 especialmente interessante para sistemas que:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;dependem de várias APIs externas&lt;/li&gt;
&lt;li&gt;se preocupam com latência de cauda&lt;/li&gt;
&lt;li&gt;rodam em ambientes distribuídos&lt;/li&gt;
&lt;li&gt;precisam lidar bem com redes imperfeitas&lt;/li&gt;
&lt;li&gt;fazem fan out para múltiplos parceiros&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Toda aplicação Java vai ficar mais rápida só porque você definiu &lt;code&gt;HTTP_3&lt;/code&gt;?&lt;/p&gt;

&lt;p&gt;Não.&lt;/p&gt;

&lt;p&gt;E é justamente por isso que esse tema merece uma conversa mais honesta.&lt;/p&gt;
&lt;h2&gt;
  
  
  A decisão real não é “usar HTTP/3 ou não”
&lt;/h2&gt;

&lt;p&gt;A decisão real é sobre estratégia.&lt;/p&gt;
&lt;h2&gt;
  
  
  Estratégia 1: preferir HTTP/3 primeiro
&lt;/h2&gt;

&lt;p&gt;Se você acredita que o serviço remoto já suporta HTTP/3 e quer aproveitar isso quando estiver disponível, esse é o caminho mais direto.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight java"&gt;&lt;code&gt;&lt;span class="nc"&gt;HttpClient&lt;/span&gt; &lt;span class="n"&gt;client&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nc"&gt;HttpClient&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;newBuilder&lt;/span&gt;&lt;span class="o"&gt;()&lt;/span&gt;
        &lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;version&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="nc"&gt;HttpClient&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;Version&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;HTTP_3&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt;
        &lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;build&lt;/span&gt;&lt;span class="o"&gt;();&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Isso faz sentido quando existe confiança no ecossistema do parceiro e você quer testar um caminho mais moderno logo de saída.&lt;/p&gt;

&lt;h2&gt;
  
  
  Estratégia 2: usar HTTP/3 só em requisições específicas
&lt;/h2&gt;

&lt;p&gt;Nem toda integração merece o mesmo tratamento.&lt;/p&gt;

&lt;p&gt;Talvez a API de preços seja uma boa candidata para teste com HTTP/3, enquanto um provedor legado de reservas ainda se comporta melhor com uma negociação mais conservadora.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight java"&gt;&lt;code&gt;&lt;span class="nc"&gt;HttpClient&lt;/span&gt; &lt;span class="n"&gt;client&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nc"&gt;HttpClient&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;newBuilder&lt;/span&gt;&lt;span class="o"&gt;().&lt;/span&gt;&lt;span class="na"&gt;build&lt;/span&gt;&lt;span class="o"&gt;();&lt;/span&gt;

&lt;span class="nc"&gt;HttpRequest&lt;/span&gt; &lt;span class="n"&gt;requestBusca&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nc"&gt;HttpRequest&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;newBuilder&lt;/span&gt;&lt;span class="o"&gt;()&lt;/span&gt;
        &lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;uri&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="no"&gt;URI&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;create&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"https://api.parceiro-viagens.com/hoteis/busca"&lt;/span&gt;&lt;span class="o"&gt;))&lt;/span&gt;
        &lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;version&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="nc"&gt;HttpClient&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;Version&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;HTTP_3&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt;
        &lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;GET&lt;/span&gt;&lt;span class="o"&gt;()&lt;/span&gt;
        &lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;build&lt;/span&gt;&lt;span class="o"&gt;();&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Essa é a abordagem que eu mais gosto para produção, porque é incremental e mais fácil de observar.&lt;/p&gt;

&lt;h2&gt;
  
  
  Estratégia 3: tratar fallback como parte do desenho
&lt;/h2&gt;

&lt;p&gt;Só porque Java 26 suporta HTTP/3 não significa que seu modelo mental deva ser “agora tudo é HTTP/3”.&lt;/p&gt;

&lt;p&gt;Em um agregador de viagens, fallback elegante importa mais do que entusiasmo com protocolo.&lt;/p&gt;

&lt;p&gt;Seu trabalho não é defender uma posição ideológica sobre transporte.&lt;br&gt;
Seu trabalho é devolver uma boa resposta de forma consistente.&lt;/p&gt;

&lt;p&gt;Se um fornecedor não suporta bem HTTP/3, ou se a negociação cair para HTTP/2, isso não é fracasso. Isso é comportamento normal.&lt;/p&gt;

&lt;p&gt;A pergunta útil é esta:&lt;/p&gt;

&lt;p&gt;essa estratégia de client reduz latência e mantém previsibilidade sob tráfego real?&lt;/p&gt;

&lt;p&gt;É isso que interessa.&lt;/p&gt;
&lt;h2&gt;
  
  
  O que eu não faria
&lt;/h2&gt;
&lt;h3&gt;
  
  
  “HTTP/3 é automaticamente mais rápido”
&lt;/h3&gt;

&lt;p&gt;Não necessariamente.&lt;/p&gt;

&lt;p&gt;Se o seu parceiro está lento por causa de contenção de banco, HTTP/3 não vai te salvar.&lt;/p&gt;
&lt;h3&gt;
  
  
  “Agora eu devo forçar HTTP/3 em tudo”
&lt;/h3&gt;

&lt;p&gt;Também não.&lt;/p&gt;

&lt;p&gt;Um backend com várias integrações quase sempre vive num ecossistema heterogêneo.&lt;br&gt;
Forçar escolha de protocolo sem medir antes costuma ser pior do que adotar com critério.&lt;/p&gt;
&lt;h3&gt;
  
  
  “Isso é só detalhe de client”
&lt;/h3&gt;

&lt;p&gt;Não é.&lt;/p&gt;

&lt;p&gt;Em sistemas distribuídos, comportamento de transporte também é comportamento da aplicação.&lt;/p&gt;
&lt;h2&gt;
  
  
  O que eu testaria de verdade
&lt;/h2&gt;

&lt;p&gt;Se eu estivesse avaliando adoção de HTTP/3 em backend Java, eu testaria assim:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;escolher uma integração com sensibilidade real a latência&lt;/li&gt;
&lt;li&gt;comparar percentis de resposta, não só média&lt;/li&gt;
&lt;li&gt;observar o comportamento de fallback&lt;/li&gt;
&lt;li&gt;monitorar handshake e reaproveitamento de conexão&lt;/li&gt;
&lt;li&gt;comparar taxa de erro em condição degradada&lt;/li&gt;
&lt;li&gt;evitar tirar conclusão com benchmark local&lt;/li&gt;
&lt;/ul&gt;
&lt;h2&gt;
  
  
  Minha conclusão
&lt;/h2&gt;

&lt;p&gt;O suporte a HTTP/3 no &lt;code&gt;HttpClient&lt;/code&gt; do Java 26 não é só uma feature para preencher release note.&lt;/p&gt;

&lt;p&gt;Ele é útil porque dá aos desenvolvedores Java uma forma melhor de lidar com a web moderna usando a biblioteca padrão.&lt;/p&gt;

&lt;p&gt;Mas o valor real não está em escrever isto:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight java"&gt;&lt;code&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;version&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="nc"&gt;HttpClient&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;Version&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;HTTP_3&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;O valor real está em saber onde essa decisão ajuda, onde fallback precisa continuar fazendo parte do desenho, e como a escolha do protocolo afeta o comportamento da aplicação em sistemas distribuídos.&lt;/p&gt;

&lt;p&gt;Em um sistema como agregador de viagens, plataforma de reservas, hub logístico ou camada de integração financeira, é aí que essa feature começa a fazer sentido.&lt;/p&gt;

&lt;p&gt;Não no anúncio.&lt;br&gt;
Na arquitetura.&lt;/p&gt;

&lt;p&gt;Eu sou o Luis De Llamas, Developer Advocate na act digital, Oracle ACE e IBM Champion. Se quiser acompanhar mais conteúdo sobre Quarkus, Java e o que rola no ecossistema, me encontra aqui:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;a href="https://www.linkedin.com/in/luisfabriciodellamas/" rel="noopener noreferrer"&gt;LinkedIn&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://github.com/dellamas" rel="noopener noreferrer"&gt;GitHub&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Nos vemos!&lt;/p&gt;

</description>
      <category>java</category>
      <category>http3</category>
      <category>backend</category>
      <category>performance</category>
    </item>
    <item>
      <title>Quarkus Reactive Routes na prática: triagem de incidentes com fluxo reativo de verdade</title>
      <dc:creator>Luis Fabrício De Llamas</dc:creator>
      <pubDate>Sat, 21 Mar 2026 01:13:27 +0000</pubDate>
      <link>https://forem.com/dellamas/quarkus-reactive-routes-na-pratica-triagem-de-incidentes-com-fluxo-reativo-de-verdade-2emd</link>
      <guid>https://forem.com/dellamas/quarkus-reactive-routes-na-pratica-triagem-de-incidentes-com-fluxo-reativo-de-verdade-2emd</guid>
      <description>&lt;h1&gt;
  
  
  Quarkus Reactive Routes na prática: triagem de incidentes com fluxo reativo de verdade
&lt;/h1&gt;

&lt;p&gt;Se você já trabalhou com observabilidade, suporte ou operação, sabe que incidente costuma começar com pressão, sinais espalhados e pouca clareza sobre o que precisa entrar primeiro na fila. Nesse tipo de cenário, não basta expor um endpoint. O desafio é organizar o fluxo de forma simples, legível e compatível com uma aplicação que precisa reagir rápido.&lt;/p&gt;

&lt;p&gt;Neste artigo eu vou mostrar um exemplo de triagem de incidentes com Quarkus Reactive Routes em um contexto mais próximo de uma operação real. A proposta é montar uma API pequena, com fila priorizada, resumo operacional e stream SSE para acompanhamento ao vivo.&lt;/p&gt;

&lt;p&gt;Vale registrar um detalhe histórico. A base dessa linha de funcionalidade entrou no Quarkus no trabalho do Martin Kouba, no commit "Add Vertx web extension" do repositório quarkusio/quarkus. Isso ajuda a entender por que o recurso tem uma integração tão direta com o ecossistema do Vert.x.&lt;/p&gt;

&lt;h2&gt;
  
  
  O que vamos construir
&lt;/h2&gt;

&lt;p&gt;Uma API de triagem operacional com quatro rotas principais:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;POST /incidents para registrar um incidente&lt;/li&gt;
&lt;li&gt;GET /incidents/priority-board para listar a fila priorizada&lt;/li&gt;
&lt;li&gt;GET /incidents/summary para consolidar o estado operacional&lt;/li&gt;
&lt;li&gt;GET /incidents/live para acompanhar snapshots em SSE&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Estrutura do projeto:&lt;/p&gt;

&lt;p&gt;src/main/java/br/com/luisf/fabricio/demos/reactive/routes/incident/&lt;br&gt;
├── api/&lt;br&gt;
│ ├── CreateIncidentRequest.java&lt;br&gt;
│ ├── CreatedIncidentEnvelope.java&lt;br&gt;
│ ├── IncidentLiveSignal.java&lt;br&gt;
│ ├── IncidentResponse.java&lt;br&gt;
│ ├── IncidentRoutes.java&lt;br&gt;
│ ├── IncidentSummaryResponse.java&lt;br&gt;
│ └── PriorityBoardResponse.java&lt;br&gt;
├── domain/&lt;br&gt;
│ ├── Incident.java&lt;br&gt;
│ ├── IncidentStatus.java&lt;br&gt;
│ └── Severity.java&lt;br&gt;
├── health/&lt;br&gt;
│ └── IncidentDispatchHealthCheck.java&lt;br&gt;
└── service/&lt;br&gt;
  ├── IncidentDispatchService.java&lt;br&gt;
  └── IncidentMapper.java&lt;/p&gt;
&lt;h2&gt;
  
  
  Criando a base do projeto
&lt;/h2&gt;

&lt;p&gt;A stack ficou enxuta para destacar o Reactive Routes sem espalhar a atenção em infraestrutura paralela:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;quarkus-reactive-routes&lt;/li&gt;
&lt;li&gt;quarkus-rest-jackson&lt;/li&gt;
&lt;li&gt;quarkus-smallrye-openapi&lt;/li&gt;
&lt;li&gt;quarkus-swagger-ui&lt;/li&gt;
&lt;li&gt;quarkus-smallrye-health&lt;/li&gt;
&lt;li&gt;quarkus-hibernate-validator&lt;/li&gt;
&lt;/ul&gt;
&lt;h2&gt;
  
  
  O domínio e os contratos
&lt;/h2&gt;

&lt;p&gt;O domínio foi mantido simples. &lt;code&gt;Incident.java&lt;/code&gt; representa o incidente, &lt;code&gt;Severity.java&lt;/code&gt; define a prioridade operacional e &lt;code&gt;IncidentStatus.java&lt;/code&gt; mantém o estado mínimo do fluxo.&lt;/p&gt;

&lt;p&gt;&lt;code&gt;Severity.java&lt;/code&gt; ficou assim:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight java"&gt;&lt;code&gt;&lt;span class="kd"&gt;public&lt;/span&gt; &lt;span class="kd"&gt;enum&lt;/span&gt; &lt;span class="nc"&gt;Severity&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
    &lt;span class="no"&gt;LOW&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="o"&gt;),&lt;/span&gt;
    &lt;span class="no"&gt;MEDIUM&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;2&lt;/span&gt;&lt;span class="o"&gt;),&lt;/span&gt;
    &lt;span class="no"&gt;HIGH&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;3&lt;/span&gt;&lt;span class="o"&gt;),&lt;/span&gt;
    &lt;span class="no"&gt;CRITICAL&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;4&lt;/span&gt;&lt;span class="o"&gt;);&lt;/span&gt;

    &lt;span class="kd"&gt;private&lt;/span&gt; &lt;span class="kd"&gt;final&lt;/span&gt; &lt;span class="kt"&gt;int&lt;/span&gt; &lt;span class="n"&gt;priority&lt;/span&gt;&lt;span class="o"&gt;;&lt;/span&gt;

    &lt;span class="nc"&gt;Severity&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="kt"&gt;int&lt;/span&gt; &lt;span class="n"&gt;priority&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
        &lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;priority&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;priority&lt;/span&gt;&lt;span class="o"&gt;;&lt;/span&gt;
    &lt;span class="o"&gt;}&lt;/span&gt;

    &lt;span class="kd"&gt;public&lt;/span&gt; &lt;span class="kt"&gt;int&lt;/span&gt; &lt;span class="nf"&gt;priority&lt;/span&gt;&lt;span class="o"&gt;()&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
        &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;priority&lt;/span&gt;&lt;span class="o"&gt;;&lt;/span&gt;
    &lt;span class="o"&gt;}&lt;/span&gt;
&lt;span class="o"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;No pacote &lt;code&gt;api/&lt;/code&gt;, cada classe cumpre um papel claro:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;code&gt;CreateIncidentRequest.java&lt;/code&gt; define o payload de entrada&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;IncidentResponse.java&lt;/code&gt; representa o incidente devolvido ao cliente&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;CreatedIncidentEnvelope.java&lt;/code&gt; adiciona a mensagem de confirmação&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;PriorityBoardResponse.java&lt;/code&gt; devolve a fila ordenada&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;IncidentSummaryResponse.java&lt;/code&gt; consolida o resumo operacional&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;IncidentLiveSignal.java&lt;/code&gt; modela cada snapshot emitido pelo SSE&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Essa separação ajuda bastante porque o contrato da API fica explícito logo na leitura inicial do projeto.&lt;/p&gt;

&lt;h2&gt;
  
  
  O coração da lógica: IncidentDispatchService.java
&lt;/h2&gt;

&lt;p&gt;Esse é o arquivo principal do projeto. É nele que entram armazenamento em memória, ordenação da fila, criação de incidentes, geração do resumo e emissão dos snapshots ao vivo.&lt;/p&gt;

&lt;p&gt;A regra de priorização ficou assim:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight java"&gt;&lt;code&gt;&lt;span class="kd"&gt;private&lt;/span&gt; &lt;span class="kd"&gt;static&lt;/span&gt; &lt;span class="kd"&gt;final&lt;/span&gt; &lt;span class="nc"&gt;Comparator&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nc"&gt;Incident&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="no"&gt;INCIDENT_PRIORITY&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nc"&gt;Comparator&lt;/span&gt;
        &lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;comparingInt&lt;/span&gt;&lt;span class="o"&gt;((&lt;/span&gt;&lt;span class="nc"&gt;Incident&lt;/span&gt; &lt;span class="n"&gt;incident&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt; &lt;span class="o"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;incident&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;severity&lt;/span&gt;&lt;span class="o"&gt;().&lt;/span&gt;&lt;span class="na"&gt;priority&lt;/span&gt;&lt;span class="o"&gt;())&lt;/span&gt;
        &lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;reversed&lt;/span&gt;&lt;span class="o"&gt;()&lt;/span&gt;
        &lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;thenComparing&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="nl"&gt;Incident:&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt;&lt;span class="n"&gt;openedAt&lt;/span&gt;&lt;span class="o"&gt;);&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Severidade mais alta sobe na fila e, entre incidentes do mesmo nível, o mais antigo vem primeiro.&lt;/p&gt;

&lt;p&gt;A criação do incidente também ficou toda visível no serviço:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight java"&gt;&lt;code&gt;&lt;span class="kd"&gt;public&lt;/span&gt; &lt;span class="nc"&gt;Uni&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nc"&gt;IncidentResponse&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="nf"&gt;create&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="nc"&gt;CreateIncidentRequest&lt;/span&gt; &lt;span class="n"&gt;request&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
    &lt;span class="nc"&gt;OffsetDateTime&lt;/span&gt; &lt;span class="n"&gt;now&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nc"&gt;OffsetDateTime&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;now&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="nc"&gt;ZoneOffset&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;UTC&lt;/span&gt;&lt;span class="o"&gt;);&lt;/span&gt;
    &lt;span class="nc"&gt;Incident&lt;/span&gt; &lt;span class="n"&gt;incident&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nc"&gt;Incident&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;
            &lt;span class="s"&gt;"INC-"&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="n"&gt;sequence&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;incrementAndGet&lt;/span&gt;&lt;span class="o"&gt;(),&lt;/span&gt;
            &lt;span class="n"&gt;request&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;severity&lt;/span&gt;&lt;span class="o"&gt;(),&lt;/span&gt;
            &lt;span class="n"&gt;request&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;affectedService&lt;/span&gt;&lt;span class="o"&gt;().&lt;/span&gt;&lt;span class="na"&gt;trim&lt;/span&gt;&lt;span class="o"&gt;(),&lt;/span&gt;
            &lt;span class="n"&gt;request&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;summary&lt;/span&gt;&lt;span class="o"&gt;().&lt;/span&gt;&lt;span class="na"&gt;trim&lt;/span&gt;&lt;span class="o"&gt;(),&lt;/span&gt;
            &lt;span class="n"&gt;request&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;owner&lt;/span&gt;&lt;span class="o"&gt;().&lt;/span&gt;&lt;span class="na"&gt;trim&lt;/span&gt;&lt;span class="o"&gt;(),&lt;/span&gt;
            &lt;span class="nc"&gt;IncidentStatus&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;OPEN&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt;
            &lt;span class="n"&gt;now&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt;
            &lt;span class="n"&gt;now&lt;/span&gt;&lt;span class="o"&gt;);&lt;/span&gt;
    &lt;span class="n"&gt;incidents&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;add&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;incident&lt;/span&gt;&lt;span class="o"&gt;);&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nc"&gt;Uni&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;createFrom&lt;/span&gt;&lt;span class="o"&gt;().&lt;/span&gt;&lt;span class="na"&gt;item&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;mapper&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;toResponse&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;incident&lt;/span&gt;&lt;span class="o"&gt;));&lt;/span&gt;
&lt;span class="o"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;E o stream SSE sai do mesmo serviço:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight java"&gt;&lt;code&gt;&lt;span class="kd"&gt;public&lt;/span&gt; &lt;span class="nc"&gt;Multi&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nc"&gt;IncidentLiveSignal&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="nf"&gt;liveSignals&lt;/span&gt;&lt;span class="o"&gt;()&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nc"&gt;Multi&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;createFrom&lt;/span&gt;&lt;span class="o"&gt;().&lt;/span&gt;&lt;span class="na"&gt;ticks&lt;/span&gt;&lt;span class="o"&gt;().&lt;/span&gt;&lt;span class="na"&gt;every&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="nc"&gt;Duration&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;ofSeconds&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="o"&gt;))&lt;/span&gt;
            &lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;onItem&lt;/span&gt;&lt;span class="o"&gt;().&lt;/span&gt;&lt;span class="na"&gt;transform&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;index&lt;/span&gt; &lt;span class="o"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nc"&gt;IncidentLiveSignal&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;
                    &lt;span class="nc"&gt;Math&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;toIntExact&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;index&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt;
                    &lt;span class="s"&gt;"incident-dispatch"&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt;
                    &lt;span class="nc"&gt;OffsetDateTime&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;now&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="nc"&gt;ZoneOffset&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;UTC&lt;/span&gt;&lt;span class="o"&gt;),&lt;/span&gt;
                    &lt;span class="n"&gt;summarySnapshot&lt;/span&gt;&lt;span class="o"&gt;(),&lt;/span&gt;
                    &lt;span class="n"&gt;priorityBoardSnapshot&lt;/span&gt;&lt;span class="o"&gt;().&lt;/span&gt;&lt;span class="na"&gt;queue&lt;/span&gt;&lt;span class="o"&gt;().&lt;/span&gt;&lt;span class="na"&gt;stream&lt;/span&gt;&lt;span class="o"&gt;().&lt;/span&gt;&lt;span class="na"&gt;findFirst&lt;/span&gt;&lt;span class="o"&gt;().&lt;/span&gt;&lt;span class="na"&gt;orElse&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="kc"&gt;null&lt;/span&gt;&lt;span class="o"&gt;)))&lt;/span&gt;
            &lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;select&lt;/span&gt;&lt;span class="o"&gt;().&lt;/span&gt;&lt;span class="na"&gt;first&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;5&lt;/span&gt;&lt;span class="o"&gt;);&lt;/span&gt;
&lt;span class="o"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Mapeamento e borda HTTP
&lt;/h2&gt;

&lt;p&gt;&lt;code&gt;IncidentMapper.java&lt;/code&gt; faz a conversão entre domínio e resposta HTTP. Pode parecer detalhe, mas essa separação evita misturar regra de negócio com montagem de payload.&lt;/p&gt;

&lt;p&gt;&lt;code&gt;IncidentRoutes.java&lt;/code&gt; concentra as quatro rotas da aplicação. A criação do incidente ficou assim:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight java"&gt;&lt;code&gt;&lt;span class="nd"&gt;@Route&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;path&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s"&gt;""&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="n"&gt;methods&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nc"&gt;Route&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;HttpMethod&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;POST&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="n"&gt;consumes&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s"&gt;"application/json"&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt;
&lt;span class="kd"&gt;public&lt;/span&gt; &lt;span class="nc"&gt;Uni&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nc"&gt;CreatedIncidentEnvelope&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="nf"&gt;create&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="nc"&gt;HttpServerResponse&lt;/span&gt; &lt;span class="n"&gt;response&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="nd"&gt;@Body&lt;/span&gt; &lt;span class="nd"&gt;@Valid&lt;/span&gt; &lt;span class="nc"&gt;CreateIncidentRequest&lt;/span&gt; &lt;span class="n"&gt;request&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
    &lt;span class="n"&gt;response&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;setStatusCode&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;201&lt;/span&gt;&lt;span class="o"&gt;);&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;service&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;create&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;request&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt;
            &lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;onItem&lt;/span&gt;&lt;span class="o"&gt;().&lt;/span&gt;&lt;span class="na"&gt;transform&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;incident&lt;/span&gt; &lt;span class="o"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nc"&gt;CreatedIncidentEnvelope&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;
                    &lt;span class="s"&gt;"Incident registered and queued for reactive triage."&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="n"&gt;incident&lt;/span&gt;&lt;span class="o"&gt;));&lt;/span&gt;
&lt;span class="o"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;A fila priorizada e o resumo retornam &lt;code&gt;Uni&lt;/code&gt;:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight java"&gt;&lt;code&gt;&lt;span class="nd"&gt;@Route&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;path&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s"&gt;"priority-board"&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="n"&gt;methods&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nc"&gt;Route&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;HttpMethod&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;GET&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt;
&lt;span class="kd"&gt;public&lt;/span&gt; &lt;span class="nc"&gt;Uni&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nc"&gt;PriorityBoardResponse&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="nf"&gt;priorityBoard&lt;/span&gt;&lt;span class="o"&gt;()&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;service&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;priorityBoard&lt;/span&gt;&lt;span class="o"&gt;();&lt;/span&gt;
&lt;span class="o"&gt;}&lt;/span&gt;

&lt;span class="nd"&gt;@Route&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;path&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s"&gt;"summary"&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="n"&gt;methods&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nc"&gt;Route&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;HttpMethod&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;GET&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt;
&lt;span class="kd"&gt;public&lt;/span&gt; &lt;span class="nc"&gt;Uni&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nc"&gt;IncidentSummaryResponse&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="nf"&gt;summary&lt;/span&gt;&lt;span class="o"&gt;()&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;service&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;summary&lt;/span&gt;&lt;span class="o"&gt;();&lt;/span&gt;
&lt;span class="o"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;E o acompanhamento ao vivo usa SSE:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight java"&gt;&lt;code&gt;&lt;span class="nd"&gt;@Route&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;path&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s"&gt;"live"&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="n"&gt;methods&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nc"&gt;Route&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;HttpMethod&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;GET&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="n"&gt;produces&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s"&gt;"text/event-stream"&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt;
&lt;span class="kd"&gt;public&lt;/span&gt; &lt;span class="nc"&gt;Multi&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nc"&gt;String&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="nf"&gt;live&lt;/span&gt;&lt;span class="o"&gt;()&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;service&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;liveSignals&lt;/span&gt;&lt;span class="o"&gt;().&lt;/span&gt;&lt;span class="na"&gt;onItem&lt;/span&gt;&lt;span class="o"&gt;().&lt;/span&gt;&lt;span class="na"&gt;transform&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="n"&gt;toSsePayload&lt;/span&gt;&lt;span class="o"&gt;);&lt;/span&gt;
&lt;span class="o"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Health check e configuração
&lt;/h2&gt;

&lt;p&gt;&lt;code&gt;IncidentDispatchHealthCheck.java&lt;/code&gt; responde a uma pergunta simples: o serviço está de pé?&lt;/p&gt;

&lt;p&gt;O &lt;code&gt;application.properties&lt;/code&gt; também ficou enxuto:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight properties"&gt;&lt;code&gt;&lt;span class="py"&gt;quarkus.http.port&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="s"&gt;8080&lt;/span&gt;
&lt;span class="py"&gt;quarkus.swagger-ui.always-include&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="s"&gt;true&lt;/span&gt;
&lt;span class="py"&gt;quarkus.smallrye-openapi.info-title&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="s"&gt;Reactive Incident Dispatch API&lt;/span&gt;
&lt;span class="py"&gt;quarkus.smallrye-openapi.info-version&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="s"&gt;1.0.0&lt;/span&gt;
&lt;span class="py"&gt;quarkus.smallrye-openapi.info-description&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="s"&gt;API reativa para despacho e triagem de incidentes operacionais.&lt;/span&gt;
&lt;span class="py"&gt;quarkus.http.enable-compression&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="s"&gt;true&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Como rodar
&lt;/h2&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;git clone https://github.com/dellamas/quarkus-reactive-routes-incident-dispatch-api
&lt;span class="nb"&gt;cd &lt;/span&gt;quarkus-reactive-routes-incident-dispatch-api
mvn quarkus:dev
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Criando um incidente:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;curl &lt;span class="nt"&gt;-X&lt;/span&gt; POST http://localhost:8080/incidents &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="nt"&gt;-H&lt;/span&gt; &lt;span class="s2"&gt;"Content-Type: application/json"&lt;/span&gt; &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="nt"&gt;-d&lt;/span&gt; &lt;span class="s1"&gt;'{
    "severity": "HIGH",
    "affectedService": "telemetry-gateway",
    "summary": "Atraso na entrega de métricas de disponibilidade",
    "owner": "observability-core"
  }'&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Consultando a fila:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;curl http://localhost:8080/incidents/priority-board
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Consultando o resumo:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;curl http://localhost:8080/incidents/summary
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Abrindo o stream:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;curl http://localhost:8080/incidents/live
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  O que este projeto mostra na prática
&lt;/h2&gt;

&lt;p&gt;O Quarkus Reactive Routes funciona muito bem quando você quer expor rotas curtas, fluxo reativo explícito e um contrato HTTP fácil de acompanhar. Neste exemplo, isso aparece na combinação entre criação de incidente, fila priorizada, resumo consolidado e stream SSE.&lt;/p&gt;

&lt;p&gt;Mostrar as classes do fluxo também ajuda bastante. Você entende onde está o contrato, onde está a regra, onde está o mapeamento e onde está a borda HTTP.&lt;/p&gt;

&lt;p&gt;O código completo está no GitHub:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://github.com/dellamas/quarkus-reactive-routes-incident-dispatch-api" rel="noopener noreferrer"&gt;https://github.com/dellamas/quarkus-reactive-routes-incident-dispatch-api&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Se quiser acompanhar mais conteúdo meu, me segue no LinkedIn:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://www.linkedin.com/in/luisfabriciodellamas/" rel="noopener noreferrer"&gt;https://www.linkedin.com/in/luisfabriciodellamas/&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;E no Insta:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://instagram.com/luisdellamas" rel="noopener noreferrer"&gt;https://instagram.com/luisdellamas&lt;/a&gt;&lt;/p&gt;

</description>
      <category>quarkus</category>
      <category>java</category>
      <category>reactive</category>
      <category>backend</category>
    </item>
    <item>
      <title>SmallRye Fault Tolerance na prática: retry, fallback e circuit breaker em um gateway Pix com Quarkus</title>
      <dc:creator>Luis Fabrício De Llamas</dc:creator>
      <pubDate>Mon, 16 Mar 2026 15:12:40 +0000</pubDate>
      <link>https://forem.com/dellamas/smallrye-fault-tolerance-num-gateway-pix-que-nao-pode-falhar-no-susto-kac</link>
      <guid>https://forem.com/dellamas/smallrye-fault-tolerance-num-gateway-pix-que-nao-pode-falhar-no-susto-kac</guid>
      <description>&lt;p&gt;Neste artigo mostro como usar SmallRye Fault Tolerance com Quarkus para proteger um gateway Pix com @Retry, @Timeout, @CircuitBreaker e @Fallback. O cenário simula uma fintech que precisa de resiliência real quando o provedor de autorização fica instável.&lt;/p&gt;

&lt;h2&gt;
  
  
  O cenário que eu montei
&lt;/h2&gt;

&lt;p&gt;A aplicação simula um gateway Pix de fintech recebendo pedidos de cobrança e chamando um provedor externo de autorização. Quando esse provedor fica instável, a API não pode simplesmente responder erro para tudo e deixar o time operacional apagar incêndio no braço.&lt;/p&gt;

&lt;p&gt;Para esse lab, o fluxo ficou assim:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;cobrança comum tenta novamente e segue o jogo&lt;/li&gt;
&lt;li&gt;cobrança mais alta não insiste para sempre&lt;/li&gt;
&lt;li&gt;quando o risco operacional aumenta, a resposta volta como análise manual&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Foi aí que &lt;code&gt;quarkus-smallrye-fault-tolerance&lt;/code&gt; fez sentido de verdade.&lt;/p&gt;

&lt;h2&gt;
  
  
  Estrutura do projeto
&lt;/h2&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;.
├── README.md
├── ARTICLE.md
├── pom.xml
├── src
│   ├── main
│   │   ├── java
│   │   │   └── dev
│   │   │       └── dailylab
│   │   │           └── payments
│   │   │               ├── PixChargeRequest.java
│   │   │               ├── PixChargeResource.java
│   │   │               ├── PixChargeResult.java
│   │   │               ├── PixChargeService.java
│   │   │               └── PixGatewayClient.java
│   │   └── resources
│   │       └── application.properties
│   └── test
│       └── java
│           └── dev
│               └── dailylab
│                   └── payments
│                       └── PixChargeResourceTest.java
└── mvnw
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Onde a extensão entrou de verdade
&lt;/h2&gt;

&lt;p&gt;O coração do lab está no serviço. A chamada externa foi protegida com retry, timeout, circuit breaker e fallback no mesmo método.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight java"&gt;&lt;code&gt;&lt;span class="nd"&gt;@Retry&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;maxRetries&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;2&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="n"&gt;delay&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;200&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="n"&gt;delayUnit&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nc"&gt;ChronoUnit&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;MILLIS&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt;
&lt;span class="nd"&gt;@Timeout&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;value&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;400&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="n"&gt;unit&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nc"&gt;ChronoUnit&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;MILLIS&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt;
&lt;span class="nd"&gt;@CircuitBreaker&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;requestVolumeThreshold&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;4&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="n"&gt;failureRatio&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mf"&gt;0.75&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="n"&gt;delay&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;2&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="n"&gt;delayUnit&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nc"&gt;ChronoUnit&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;SECONDS&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt;
&lt;span class="nd"&gt;@Fallback&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;fallbackMethod&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s"&gt;"reserveForManualReview"&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt;
&lt;span class="kd"&gt;public&lt;/span&gt; &lt;span class="nc"&gt;PixChargeResult&lt;/span&gt; &lt;span class="nf"&gt;process&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="nc"&gt;PixChargeRequest&lt;/span&gt; &lt;span class="n"&gt;request&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
    &lt;span class="kt"&gt;int&lt;/span&gt; &lt;span class="n"&gt;attempt&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;gatewayClient&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;nextAttempt&lt;/span&gt;&lt;span class="o"&gt;();&lt;/span&gt;
    &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;request&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;amount&lt;/span&gt;&lt;span class="o"&gt;().&lt;/span&gt;&lt;span class="na"&gt;compareTo&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nc"&gt;BigDecimal&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"1500.00"&lt;/span&gt;&lt;span class="o"&gt;))&lt;/span&gt; &lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
        &lt;span class="k"&gt;throw&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nf"&gt;IllegalStateException&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"provider timeout on high-value pix charge"&lt;/span&gt;&lt;span class="o"&gt;);&lt;/span&gt;
    &lt;span class="o"&gt;}&lt;/span&gt;
    &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;attempt&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;&lt;/span&gt; &lt;span class="mi"&gt;3&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
        &lt;span class="k"&gt;throw&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nf"&gt;IllegalStateException&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"temporary provider instability on attempt "&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="n"&gt;attempt&lt;/span&gt;&lt;span class="o"&gt;);&lt;/span&gt;
    &lt;span class="o"&gt;}&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nf"&gt;PixChargeResult&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;
            &lt;span class="s"&gt;"APPROVED"&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt;
            &lt;span class="s"&gt;"primary-pix-provider"&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt;
            &lt;span class="n"&gt;request&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;amount&lt;/span&gt;&lt;span class="o"&gt;(),&lt;/span&gt;
            &lt;span class="s"&gt;"Charge approved after retry strategy stabilized the provider call"&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt;
            &lt;span class="n"&gt;request&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;correlationId&lt;/span&gt;&lt;span class="o"&gt;());&lt;/span&gt;
&lt;span class="o"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;O que eu gosto aqui é que a regra fica visível. Não tem controller fazendo malabarismo, nem exception espalhada em três camadas diferentes. A decisão operacional está no ponto em que a falha realmente importa.&lt;/p&gt;

&lt;p&gt;O endpoint HTTP ficou enxuto:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight java"&gt;&lt;code&gt;&lt;span class="nd"&gt;@Path&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"/pix-charges"&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt;
&lt;span class="nd"&gt;@Consumes&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="nc"&gt;MediaType&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;APPLICATION_JSON&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt;
&lt;span class="nd"&gt;@Produces&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="nc"&gt;MediaType&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;APPLICATION_JSON&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt;
&lt;span class="kd"&gt;public&lt;/span&gt; &lt;span class="kd"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;PixChargeResource&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;

    &lt;span class="kd"&gt;private&lt;/span&gt; &lt;span class="kd"&gt;final&lt;/span&gt; &lt;span class="nc"&gt;PixChargeService&lt;/span&gt; &lt;span class="n"&gt;service&lt;/span&gt;&lt;span class="o"&gt;;&lt;/span&gt;

    &lt;span class="kd"&gt;public&lt;/span&gt; &lt;span class="nf"&gt;PixChargeResource&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="nc"&gt;PixChargeService&lt;/span&gt; &lt;span class="n"&gt;service&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
        &lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;service&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;service&lt;/span&gt;&lt;span class="o"&gt;;&lt;/span&gt;
    &lt;span class="o"&gt;}&lt;/span&gt;

    &lt;span class="nd"&gt;@POST&lt;/span&gt;
    &lt;span class="kd"&gt;public&lt;/span&gt; &lt;span class="nc"&gt;PixChargeResult&lt;/span&gt; &lt;span class="nf"&gt;create&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="nc"&gt;PixChargeRequest&lt;/span&gt; &lt;span class="n"&gt;request&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
        &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;service&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;process&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;request&lt;/span&gt;&lt;span class="o"&gt;);&lt;/span&gt;
    &lt;span class="o"&gt;}&lt;/span&gt;
&lt;span class="o"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Configuração usada
&lt;/h2&gt;

&lt;p&gt;A configuração ficou pequena porque o objetivo era mostrar a extensão resolvendo um caso concreto.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight properties"&gt;&lt;code&gt;&lt;span class="py"&gt;quarkus.swagger-ui.always-include&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="s"&gt;true&lt;/span&gt;
&lt;span class="py"&gt;quarkus.smallrye-openapi.info-title&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="s"&gt;Lab SmallRye Fault Tolerance&lt;/span&gt;
&lt;span class="py"&gt;quarkus.smallrye-openapi.info-version&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="s"&gt;1.0.0&lt;/span&gt;
&lt;span class="py"&gt;quarkus.smallrye-openapi.info-description&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="s"&gt;API de fallback para cobrancas Pix em um contexto de antifraude e estabilidade de gateway.&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Como rodar e testar
&lt;/h2&gt;

&lt;p&gt;Subindo localmente:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;./mvnw quarkus:dev
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Cobrança que passa depois do retry:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;curl &lt;span class="nt"&gt;-X&lt;/span&gt; POST http://localhost:8080/pix-charges &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="nt"&gt;-H&lt;/span&gt; &lt;span class="s1"&gt;'Content-Type: application/json'&lt;/span&gt; &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="nt"&gt;-d&lt;/span&gt; &lt;span class="s1"&gt;'{
    "customerId": "cust-01",
    "amount": 1200.00,
    "correlationId": "pix-001"
  }'&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Cobrança que desvia para análise manual:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;curl &lt;span class="nt"&gt;-X&lt;/span&gt; POST http://localhost:8080/pix-charges &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="nt"&gt;-H&lt;/span&gt; &lt;span class="s1"&gt;'Content-Type: application/json'&lt;/span&gt; &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="nt"&gt;-d&lt;/span&gt; &lt;span class="s1"&gt;'{
    "customerId": "cust-02",
    "amount": 2500.00,
    "correlationId": "pix-002"
  }'&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Swagger:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;code&gt;http://localhost:8080/q/swagger-ui&lt;/code&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  O que eu tirei desse lab
&lt;/h2&gt;

&lt;p&gt;Essa extensão ganha muito quando o exemplo deixa de ser acadêmico. No caso da cobrança Pix, retry e fallback não são enfeite: eles viram uma decisão de operação. Cobrança pequena pode insistir um pouco. Cobrança maior precisa preservar o sistema e cair para outro fluxo.&lt;/p&gt;

&lt;p&gt;Também ficou claro que esse tipo de lab funciona melhor quando o código é curto, o cenário é específico e o teste cobre a resposta final. A leitura fica muito mais honesta.&lt;/p&gt;

&lt;h2&gt;
  
  
  Link pro GitHub
&lt;/h2&gt;

&lt;p&gt;&lt;a href="https://github.com/dellamas/quarkus-smallrye-fault-tolerance" rel="noopener noreferrer"&gt;https://github.com/dellamas/quarkus-smallrye-fault-tolerance&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Gostou e quer ver mais conteúdos como este? Então deixa uma ⭐ no repositório.&lt;/p&gt;

&lt;p&gt;No LinkedIn eu sempre posto sobre eventos, comunidade Java e Quarkus:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://www.linkedin.com/in/luisfabriciodellamas/" rel="noopener noreferrer"&gt;💼 LinkedIn&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;E o artigo deste projeto está no dev.to:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://dev.to/dellamas"&gt;✍️ dev.to&lt;/a&gt;&lt;/p&gt;

</description>
      <category>java</category>
      <category>quarkus</category>
      <category>smallrye</category>
      <category>braziliandevs</category>
    </item>
    <item>
      <title>Quarkus Scheduler na prática</title>
      <dc:creator>Luis Fabrício De Llamas</dc:creator>
      <pubDate>Sun, 15 Mar 2026 17:11:32 +0000</pubDate>
      <link>https://forem.com/dellamas/quarkus-scheduler-na-pratica-agendando-cobrancas-como-um-servico-fintech-33i3</link>
      <guid>https://forem.com/dellamas/quarkus-scheduler-na-pratica-agendando-cobrancas-como-um-servico-fintech-33i3</guid>
      <description>&lt;p&gt;Se você já trabalhou com sistemas financeiros, sabe que uma das tarefas mais comuns é lidar com tarefas agendadas: verificar vencimentos, processar cobranças, gerar relatórios diários. No mundo Spring Boot, muita gente recorre ao &lt;code&gt;@Scheduled&lt;/code&gt;. No Quarkus, temos o &lt;strong&gt;Quarkus Scheduler&lt;/strong&gt; — e ele é bem direto ao ponto.&lt;/p&gt;

&lt;p&gt;Nesse post vou mostrar como usar o Scheduler num contexto real de fintech, sem aquele exemplo de "contador que incrementa a cada 10 segundos" que todo tutorial usa. Bora?&lt;/p&gt;

&lt;h2&gt;
  
  
  O que vamos construir
&lt;/h2&gt;

&lt;p&gt;Uma API de cobranças com três jobs agendados:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;A cada 30 segundos: verifica vencimentos e atualiza status&lt;/li&gt;
&lt;li&gt;Todo dia às 8h: inicia o processamento das cobranças pendentes&lt;/li&gt;
&lt;li&gt;Todo dia às 18h: gera um relatório com totais&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Estrutura do projeto:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;src/main/java/dev/dellamas/fintech/
├── model/
│   └── Cobranca.java
├── service/
│   └── CobrancaService.java
├── scheduler/
│   └── CobrancaScheduler.java
└── resource/
    └── CobrancaResource.java
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Criando o projeto
&lt;/h2&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;mvn io.quarkus.platform:quarkus-maven-plugin:3.18.4:create &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="nt"&gt;-DprojectGroupId&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;dev.dellamas &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="nt"&gt;-DprojectArtifactId&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;quarkus-scheduler-fintech &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="nt"&gt;-Dextensions&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s2"&gt;"rest,scheduler,rest-jackson"&lt;/span&gt; &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="nt"&gt;-DnoCode&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  O modelo: Cobranca.java
&lt;/h2&gt;

&lt;p&gt;Vamos começar pelo modelo. Nada sofisticado aqui — uma cobrança com id, cliente, valor, vencimento e status. Mas já pensou quantas vezes você viu um sistema que não tem nem isso bem definido?&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight java"&gt;&lt;code&gt;&lt;span class="kn"&gt;package&lt;/span&gt; &lt;span class="nn"&gt;dev.dellamas.fintech.model&lt;/span&gt;&lt;span class="o"&gt;;&lt;/span&gt;

&lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="nn"&gt;java.math.BigDecimal&lt;/span&gt;&lt;span class="o"&gt;;&lt;/span&gt;
&lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="nn"&gt;java.time.LocalDate&lt;/span&gt;&lt;span class="o"&gt;;&lt;/span&gt;

&lt;span class="kd"&gt;public&lt;/span&gt; &lt;span class="kd"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;Cobranca&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;

    &lt;span class="kd"&gt;private&lt;/span&gt; &lt;span class="nc"&gt;String&lt;/span&gt; &lt;span class="n"&gt;id&lt;/span&gt;&lt;span class="o"&gt;;&lt;/span&gt;
    &lt;span class="kd"&gt;private&lt;/span&gt; &lt;span class="nc"&gt;String&lt;/span&gt; &lt;span class="n"&gt;cliente&lt;/span&gt;&lt;span class="o"&gt;;&lt;/span&gt;
    &lt;span class="kd"&gt;private&lt;/span&gt; &lt;span class="nc"&gt;BigDecimal&lt;/span&gt; &lt;span class="n"&gt;valor&lt;/span&gt;&lt;span class="o"&gt;;&lt;/span&gt;
    &lt;span class="kd"&gt;private&lt;/span&gt; &lt;span class="nc"&gt;LocalDate&lt;/span&gt; &lt;span class="n"&gt;vencimento&lt;/span&gt;&lt;span class="o"&gt;;&lt;/span&gt;
    &lt;span class="kd"&gt;private&lt;/span&gt; &lt;span class="nc"&gt;StatusCobranca&lt;/span&gt; &lt;span class="n"&gt;status&lt;/span&gt;&lt;span class="o"&gt;;&lt;/span&gt;

    &lt;span class="kd"&gt;public&lt;/span&gt; &lt;span class="kd"&gt;enum&lt;/span&gt; &lt;span class="nc"&gt;StatusCobranca&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
        &lt;span class="no"&gt;PENDENTE&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="no"&gt;PROCESSANDO&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="no"&gt;PAGA&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="no"&gt;VENCIDA&lt;/span&gt;
    &lt;span class="o"&gt;}&lt;/span&gt;

    &lt;span class="kd"&gt;public&lt;/span&gt; &lt;span class="nf"&gt;Cobranca&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="nc"&gt;String&lt;/span&gt; &lt;span class="n"&gt;id&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="nc"&gt;String&lt;/span&gt; &lt;span class="n"&gt;cliente&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="nc"&gt;BigDecimal&lt;/span&gt; &lt;span class="n"&gt;valor&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="nc"&gt;LocalDate&lt;/span&gt; &lt;span class="n"&gt;vencimento&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
        &lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;id&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;id&lt;/span&gt;&lt;span class="o"&gt;;&lt;/span&gt;
        &lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;cliente&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;cliente&lt;/span&gt;&lt;span class="o"&gt;;&lt;/span&gt;
        &lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;valor&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;valor&lt;/span&gt;&lt;span class="o"&gt;;&lt;/span&gt;
        &lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;vencimento&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;vencimento&lt;/span&gt;&lt;span class="o"&gt;;&lt;/span&gt;
        &lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;status&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nc"&gt;StatusCobranca&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;PENDENTE&lt;/span&gt;&lt;span class="o"&gt;;&lt;/span&gt;
    &lt;span class="o"&gt;}&lt;/span&gt;

    &lt;span class="kd"&gt;public&lt;/span&gt; &lt;span class="nc"&gt;String&lt;/span&gt; &lt;span class="nf"&gt;getId&lt;/span&gt;&lt;span class="o"&gt;()&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt; &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;id&lt;/span&gt;&lt;span class="o"&gt;;&lt;/span&gt; &lt;span class="o"&gt;}&lt;/span&gt;
    &lt;span class="kd"&gt;public&lt;/span&gt; &lt;span class="nc"&gt;String&lt;/span&gt; &lt;span class="nf"&gt;getCliente&lt;/span&gt;&lt;span class="o"&gt;()&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt; &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;cliente&lt;/span&gt;&lt;span class="o"&gt;;&lt;/span&gt; &lt;span class="o"&gt;}&lt;/span&gt;
    &lt;span class="kd"&gt;public&lt;/span&gt; &lt;span class="nc"&gt;BigDecimal&lt;/span&gt; &lt;span class="nf"&gt;getValor&lt;/span&gt;&lt;span class="o"&gt;()&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt; &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;valor&lt;/span&gt;&lt;span class="o"&gt;;&lt;/span&gt; &lt;span class="o"&gt;}&lt;/span&gt;
    &lt;span class="kd"&gt;public&lt;/span&gt; &lt;span class="nc"&gt;LocalDate&lt;/span&gt; &lt;span class="nf"&gt;getVencimento&lt;/span&gt;&lt;span class="o"&gt;()&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt; &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;vencimento&lt;/span&gt;&lt;span class="o"&gt;;&lt;/span&gt; &lt;span class="o"&gt;}&lt;/span&gt;
    &lt;span class="kd"&gt;public&lt;/span&gt; &lt;span class="nc"&gt;StatusCobranca&lt;/span&gt; &lt;span class="nf"&gt;getStatus&lt;/span&gt;&lt;span class="o"&gt;()&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt; &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;status&lt;/span&gt;&lt;span class="o"&gt;;&lt;/span&gt; &lt;span class="o"&gt;}&lt;/span&gt;
    &lt;span class="kd"&gt;public&lt;/span&gt; &lt;span class="kt"&gt;void&lt;/span&gt; &lt;span class="nf"&gt;setStatus&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="nc"&gt;StatusCobranca&lt;/span&gt; &lt;span class="n"&gt;status&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt; &lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;status&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;status&lt;/span&gt;&lt;span class="o"&gt;;&lt;/span&gt; &lt;span class="o"&gt;}&lt;/span&gt;
&lt;span class="o"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Sem persistência por enquanto — o foco aqui é no Scheduler. Num projeto real, isso viraria uma entidade Panache sem dor.&lt;/p&gt;

&lt;h2&gt;
  
  
  O serviço: CobrancaService.java
&lt;/h2&gt;

&lt;p&gt;Esse é o coração da lógica. Ele mantém as cobranças em memória e expõe os métodos que os jobs vão chamar. Perceba o &lt;code&gt;ConcurrentHashMap&lt;/code&gt; — os jobs rodam em threads separadas, então se você não pensar em concorrência aqui, vai ter problema cedo ou tarde.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight java"&gt;&lt;code&gt;&lt;span class="kn"&gt;package&lt;/span&gt; &lt;span class="nn"&gt;dev.dellamas.fintech.service&lt;/span&gt;&lt;span class="o"&gt;;&lt;/span&gt;

&lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="nn"&gt;dev.dellamas.fintech.model.Cobranca&lt;/span&gt;&lt;span class="o"&gt;;&lt;/span&gt;
&lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="nn"&gt;dev.dellamas.fintech.model.Cobranca.StatusCobranca&lt;/span&gt;&lt;span class="o"&gt;;&lt;/span&gt;
&lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="nn"&gt;jakarta.enterprise.context.ApplicationScoped&lt;/span&gt;&lt;span class="o"&gt;;&lt;/span&gt;

&lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="nn"&gt;java.math.BigDecimal&lt;/span&gt;&lt;span class="o"&gt;;&lt;/span&gt;
&lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="nn"&gt;java.time.LocalDate&lt;/span&gt;&lt;span class="o"&gt;;&lt;/span&gt;
&lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="nn"&gt;java.util.ArrayList&lt;/span&gt;&lt;span class="o"&gt;;&lt;/span&gt;
&lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="nn"&gt;java.util.List&lt;/span&gt;&lt;span class="o"&gt;;&lt;/span&gt;
&lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="nn"&gt;java.util.Map&lt;/span&gt;&lt;span class="o"&gt;;&lt;/span&gt;
&lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="nn"&gt;java.util.concurrent.ConcurrentHashMap&lt;/span&gt;&lt;span class="o"&gt;;&lt;/span&gt;
&lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="nn"&gt;java.util.stream.Collectors&lt;/span&gt;&lt;span class="o"&gt;;&lt;/span&gt;

&lt;span class="nd"&gt;@ApplicationScoped&lt;/span&gt;
&lt;span class="kd"&gt;public&lt;/span&gt; &lt;span class="kd"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;CobrancaService&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;

    &lt;span class="kd"&gt;private&lt;/span&gt; &lt;span class="kd"&gt;final&lt;/span&gt; &lt;span class="nc"&gt;Map&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nc"&gt;String&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="nc"&gt;Cobranca&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;cobrancas&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nc"&gt;ConcurrentHashMap&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&amp;gt;();&lt;/span&gt;

    &lt;span class="kd"&gt;public&lt;/span&gt; &lt;span class="nf"&gt;CobrancaService&lt;/span&gt;&lt;span class="o"&gt;()&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
        &lt;span class="n"&gt;cobrancas&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;put&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"C001"&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nc"&gt;Cobranca&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"C001"&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="s"&gt;"Empresa Alpha"&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt;
                &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nf"&gt;BigDecimal&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"1500.00"&lt;/span&gt;&lt;span class="o"&gt;),&lt;/span&gt; &lt;span class="nc"&gt;LocalDate&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;now&lt;/span&gt;&lt;span class="o"&gt;().&lt;/span&gt;&lt;span class="na"&gt;minusDays&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="o"&gt;)));&lt;/span&gt;
        &lt;span class="n"&gt;cobrancas&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;put&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"C002"&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nc"&gt;Cobranca&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"C002"&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="s"&gt;"Startup Beta"&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt;
                &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nf"&gt;BigDecimal&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"890.50"&lt;/span&gt;&lt;span class="o"&gt;),&lt;/span&gt; &lt;span class="nc"&gt;LocalDate&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;now&lt;/span&gt;&lt;span class="o"&gt;()));&lt;/span&gt;
        &lt;span class="n"&gt;cobrancas&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;put&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"C003"&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nc"&gt;Cobranca&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"C003"&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="s"&gt;"Loja Gamma"&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt;
                &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nf"&gt;BigDecimal&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"3200.00"&lt;/span&gt;&lt;span class="o"&gt;),&lt;/span&gt; &lt;span class="nc"&gt;LocalDate&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;now&lt;/span&gt;&lt;span class="o"&gt;().&lt;/span&gt;&lt;span class="na"&gt;plusDays&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;5&lt;/span&gt;&lt;span class="o"&gt;)));&lt;/span&gt;
        &lt;span class="n"&gt;cobrancas&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;put&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"C004"&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nc"&gt;Cobranca&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"C004"&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="s"&gt;"Consultoria Delta"&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt;
                &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nf"&gt;BigDecimal&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"650.00"&lt;/span&gt;&lt;span class="o"&gt;),&lt;/span&gt; &lt;span class="nc"&gt;LocalDate&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;now&lt;/span&gt;&lt;span class="o"&gt;().&lt;/span&gt;&lt;span class="na"&gt;minusDays&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;3&lt;/span&gt;&lt;span class="o"&gt;)));&lt;/span&gt;
    &lt;span class="o"&gt;}&lt;/span&gt;

    &lt;span class="kd"&gt;public&lt;/span&gt; &lt;span class="nc"&gt;List&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nc"&gt;Cobranca&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="nf"&gt;listarTodas&lt;/span&gt;&lt;span class="o"&gt;()&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
        &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nc"&gt;ArrayList&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&amp;gt;(&lt;/span&gt;&lt;span class="n"&gt;cobrancas&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;values&lt;/span&gt;&lt;span class="o"&gt;());&lt;/span&gt;
    &lt;span class="o"&gt;}&lt;/span&gt;

    &lt;span class="kd"&gt;public&lt;/span&gt; &lt;span class="nc"&gt;List&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nc"&gt;Cobranca&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="nf"&gt;listarVencidas&lt;/span&gt;&lt;span class="o"&gt;()&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
        &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;cobrancas&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;values&lt;/span&gt;&lt;span class="o"&gt;().&lt;/span&gt;&lt;span class="na"&gt;stream&lt;/span&gt;&lt;span class="o"&gt;()&lt;/span&gt;
                &lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;filter&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;c&lt;/span&gt; &lt;span class="o"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;c&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;getVencimento&lt;/span&gt;&lt;span class="o"&gt;().&lt;/span&gt;&lt;span class="na"&gt;isBefore&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="nc"&gt;LocalDate&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;now&lt;/span&gt;&lt;span class="o"&gt;())&lt;/span&gt;
                        &lt;span class="o"&gt;&amp;amp;&amp;amp;&lt;/span&gt; &lt;span class="n"&gt;c&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;getStatus&lt;/span&gt;&lt;span class="o"&gt;()&lt;/span&gt; &lt;span class="o"&gt;==&lt;/span&gt; &lt;span class="nc"&gt;StatusCobranca&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;PENDENTE&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt;
                &lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;collect&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="nc"&gt;Collectors&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;toList&lt;/span&gt;&lt;span class="o"&gt;());&lt;/span&gt;
    &lt;span class="o"&gt;}&lt;/span&gt;

    &lt;span class="kd"&gt;public&lt;/span&gt; &lt;span class="nc"&gt;List&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nc"&gt;Cobranca&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="nf"&gt;listarPendentes&lt;/span&gt;&lt;span class="o"&gt;()&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
        &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;cobrancas&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;values&lt;/span&gt;&lt;span class="o"&gt;().&lt;/span&gt;&lt;span class="na"&gt;stream&lt;/span&gt;&lt;span class="o"&gt;()&lt;/span&gt;
                &lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;filter&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;c&lt;/span&gt; &lt;span class="o"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;c&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;getStatus&lt;/span&gt;&lt;span class="o"&gt;()&lt;/span&gt; &lt;span class="o"&gt;==&lt;/span&gt; &lt;span class="nc"&gt;StatusCobranca&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;PENDENTE&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt;
                &lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;collect&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="nc"&gt;Collectors&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;toList&lt;/span&gt;&lt;span class="o"&gt;());&lt;/span&gt;
    &lt;span class="o"&gt;}&lt;/span&gt;

    &lt;span class="kd"&gt;public&lt;/span&gt; &lt;span class="kt"&gt;int&lt;/span&gt; &lt;span class="nf"&gt;marcarVencidasComoVencidas&lt;/span&gt;&lt;span class="o"&gt;()&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
        &lt;span class="nc"&gt;List&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nc"&gt;Cobranca&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;vencidas&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;listarVencidas&lt;/span&gt;&lt;span class="o"&gt;();&lt;/span&gt;
        &lt;span class="n"&gt;vencidas&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;forEach&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;c&lt;/span&gt; &lt;span class="o"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;c&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;setStatus&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="nc"&gt;StatusCobranca&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;VENCIDA&lt;/span&gt;&lt;span class="o"&gt;));&lt;/span&gt;
        &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;vencidas&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;size&lt;/span&gt;&lt;span class="o"&gt;();&lt;/span&gt;
    &lt;span class="o"&gt;}&lt;/span&gt;

    &lt;span class="kd"&gt;public&lt;/span&gt; &lt;span class="kt"&gt;int&lt;/span&gt; &lt;span class="nf"&gt;processarPendentes&lt;/span&gt;&lt;span class="o"&gt;()&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
        &lt;span class="nc"&gt;List&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nc"&gt;Cobranca&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;pendentes&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;listarPendentes&lt;/span&gt;&lt;span class="o"&gt;();&lt;/span&gt;
        &lt;span class="n"&gt;pendentes&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;forEach&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;c&lt;/span&gt; &lt;span class="o"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;c&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;setStatus&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="nc"&gt;StatusCobranca&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;PROCESSANDO&lt;/span&gt;&lt;span class="o"&gt;));&lt;/span&gt;
        &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;pendentes&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;size&lt;/span&gt;&lt;span class="o"&gt;();&lt;/span&gt;
    &lt;span class="o"&gt;}&lt;/span&gt;

    &lt;span class="kd"&gt;public&lt;/span&gt; &lt;span class="nc"&gt;BigDecimal&lt;/span&gt; &lt;span class="nf"&gt;totalVencido&lt;/span&gt;&lt;span class="o"&gt;()&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
        &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;cobrancas&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;values&lt;/span&gt;&lt;span class="o"&gt;().&lt;/span&gt;&lt;span class="na"&gt;stream&lt;/span&gt;&lt;span class="o"&gt;()&lt;/span&gt;
                &lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;filter&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;c&lt;/span&gt; &lt;span class="o"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;c&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;getStatus&lt;/span&gt;&lt;span class="o"&gt;()&lt;/span&gt; &lt;span class="o"&gt;==&lt;/span&gt; &lt;span class="nc"&gt;StatusCobranca&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;VENCIDA&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt;
                &lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;map&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="nl"&gt;Cobranca:&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt;&lt;span class="n"&gt;getValor&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt;
                &lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;reduce&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="nc"&gt;BigDecimal&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;ZERO&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="nl"&gt;BigDecimal:&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt;&lt;span class="n"&gt;add&lt;/span&gt;&lt;span class="o"&gt;);&lt;/span&gt;
    &lt;span class="o"&gt;}&lt;/span&gt;
&lt;span class="o"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Os jobs agendados: CobrancaScheduler.java
&lt;/h2&gt;

&lt;p&gt;Aqui é onde o Quarkus Scheduler entra. A anotação &lt;code&gt;@Scheduled&lt;/code&gt; aceita dois formatos: intervalo fixo com &lt;code&gt;every&lt;/code&gt; e expressão cron com &lt;code&gt;cron&lt;/code&gt;. Qual usar? Depende. Pra verificações frequentes, &lt;code&gt;every&lt;/code&gt; resolve. Pra tarefas que precisam rodar em horário específico, cron é o caminho.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight java"&gt;&lt;code&gt;&lt;span class="kn"&gt;package&lt;/span&gt; &lt;span class="nn"&gt;dev.dellamas.fintech.scheduler&lt;/span&gt;&lt;span class="o"&gt;;&lt;/span&gt;

&lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="nn"&gt;dev.dellamas.fintech.service.CobrancaService&lt;/span&gt;&lt;span class="o"&gt;;&lt;/span&gt;
&lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="nn"&gt;io.quarkus.scheduler.Scheduled&lt;/span&gt;&lt;span class="o"&gt;;&lt;/span&gt;
&lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="nn"&gt;jakarta.enterprise.context.ApplicationScoped&lt;/span&gt;&lt;span class="o"&gt;;&lt;/span&gt;
&lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="nn"&gt;jakarta.inject.Inject&lt;/span&gt;&lt;span class="o"&gt;;&lt;/span&gt;
&lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="nn"&gt;org.jboss.logging.Logger&lt;/span&gt;&lt;span class="o"&gt;;&lt;/span&gt;

&lt;span class="nd"&gt;@ApplicationScoped&lt;/span&gt;
&lt;span class="kd"&gt;public&lt;/span&gt; &lt;span class="kd"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;CobrancaScheduler&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;

    &lt;span class="kd"&gt;private&lt;/span&gt; &lt;span class="kd"&gt;static&lt;/span&gt; &lt;span class="kd"&gt;final&lt;/span&gt; &lt;span class="nc"&gt;Logger&lt;/span&gt; &lt;span class="no"&gt;LOG&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nc"&gt;Logger&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;getLogger&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="nc"&gt;CobrancaScheduler&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;class&lt;/span&gt;&lt;span class="o"&gt;);&lt;/span&gt;

    &lt;span class="nd"&gt;@Inject&lt;/span&gt;
    &lt;span class="nc"&gt;CobrancaService&lt;/span&gt; &lt;span class="n"&gt;cobrancaService&lt;/span&gt;&lt;span class="o"&gt;;&lt;/span&gt;

    &lt;span class="nd"&gt;@Scheduled&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;every&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s"&gt;"30s"&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt;
    &lt;span class="kt"&gt;void&lt;/span&gt; &lt;span class="nf"&gt;verificarVencimentos&lt;/span&gt;&lt;span class="o"&gt;()&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
        &lt;span class="kt"&gt;int&lt;/span&gt; &lt;span class="n"&gt;total&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;cobrancaService&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;marcarVencidasComoVencidas&lt;/span&gt;&lt;span class="o"&gt;();&lt;/span&gt;
        &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;total&lt;/span&gt; &lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
            &lt;span class="no"&gt;LOG&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;infof&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"Vencimentos processados: %d cobrança(s) marcadas como vencidas"&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="n"&gt;total&lt;/span&gt;&lt;span class="o"&gt;);&lt;/span&gt;
        &lt;span class="o"&gt;}&lt;/span&gt;
    &lt;span class="o"&gt;}&lt;/span&gt;

    &lt;span class="nd"&gt;@Scheduled&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;cron&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s"&gt;"0 0 8 * * ?"&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt;
    &lt;span class="kt"&gt;void&lt;/span&gt; &lt;span class="nf"&gt;processarCobrancasDiarias&lt;/span&gt;&lt;span class="o"&gt;()&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
        &lt;span class="kt"&gt;int&lt;/span&gt; &lt;span class="n"&gt;total&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;cobrancaService&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;processarPendentes&lt;/span&gt;&lt;span class="o"&gt;();&lt;/span&gt;
        &lt;span class="no"&gt;LOG&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;infof&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"Processamento diário iniciado: %d cobrança(s) em processamento"&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="n"&gt;total&lt;/span&gt;&lt;span class="o"&gt;);&lt;/span&gt;
    &lt;span class="o"&gt;}&lt;/span&gt;

    &lt;span class="nd"&gt;@Scheduled&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;cron&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s"&gt;"0 0 18 * * ?"&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt;
    &lt;span class="kt"&gt;void&lt;/span&gt; &lt;span class="nf"&gt;gerarRelatorioDiario&lt;/span&gt;&lt;span class="o"&gt;()&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
        &lt;span class="kt"&gt;var&lt;/span&gt; &lt;span class="n"&gt;vencidas&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;cobrancaService&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;listarVencidas&lt;/span&gt;&lt;span class="o"&gt;().&lt;/span&gt;&lt;span class="na"&gt;size&lt;/span&gt;&lt;span class="o"&gt;();&lt;/span&gt;
        &lt;span class="kt"&gt;var&lt;/span&gt; &lt;span class="n"&gt;totalVencido&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;cobrancaService&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;totalVencido&lt;/span&gt;&lt;span class="o"&gt;();&lt;/span&gt;
        &lt;span class="no"&gt;LOG&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;infof&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"Relatório diário — Cobranças vencidas: %d | Total em aberto: R$ %s"&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt;
                &lt;span class="n"&gt;vencidas&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="n"&gt;totalVencido&lt;/span&gt;&lt;span class="o"&gt;);&lt;/span&gt;
    &lt;span class="o"&gt;}&lt;/span&gt;
&lt;span class="o"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;O formato de cron padrão no Quarkus é o do Quartz (6 campos, com segundos). Se você prefere o formato Unix de 5 campos, troca no &lt;code&gt;application.properties&lt;/code&gt;:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight properties"&gt;&lt;code&gt;&lt;span class="py"&gt;quarkus.scheduler.cron-type&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="s"&gt;unix&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  O endpoint REST: CobrancaResource.java
&lt;/h2&gt;

&lt;p&gt;Pra fechar, precisamos expor o estado das cobranças. Afinal, de que adianta processar tudo em background se ninguém consegue consultar?&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight java"&gt;&lt;code&gt;&lt;span class="kn"&gt;package&lt;/span&gt; &lt;span class="nn"&gt;dev.dellamas.fintech.resource&lt;/span&gt;&lt;span class="o"&gt;;&lt;/span&gt;

&lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="nn"&gt;dev.dellamas.fintech.model.Cobranca&lt;/span&gt;&lt;span class="o"&gt;;&lt;/span&gt;
&lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="nn"&gt;dev.dellamas.fintech.service.CobrancaService&lt;/span&gt;&lt;span class="o"&gt;;&lt;/span&gt;
&lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="nn"&gt;jakarta.inject.Inject&lt;/span&gt;&lt;span class="o"&gt;;&lt;/span&gt;
&lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="nn"&gt;jakarta.ws.rs.GET&lt;/span&gt;&lt;span class="o"&gt;;&lt;/span&gt;
&lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="nn"&gt;jakarta.ws.rs.Path&lt;/span&gt;&lt;span class="o"&gt;;&lt;/span&gt;
&lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="nn"&gt;jakarta.ws.rs.Produces&lt;/span&gt;&lt;span class="o"&gt;;&lt;/span&gt;
&lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="nn"&gt;jakarta.ws.rs.core.MediaType&lt;/span&gt;&lt;span class="o"&gt;;&lt;/span&gt;

&lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="nn"&gt;java.util.List&lt;/span&gt;&lt;span class="o"&gt;;&lt;/span&gt;

&lt;span class="nd"&gt;@Path&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"/cobrancas"&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt;
&lt;span class="nd"&gt;@Produces&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="nc"&gt;MediaType&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;APPLICATION_JSON&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt;
&lt;span class="kd"&gt;public&lt;/span&gt; &lt;span class="kd"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;CobrancaResource&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;

    &lt;span class="nd"&gt;@Inject&lt;/span&gt;
    &lt;span class="nc"&gt;CobrancaService&lt;/span&gt; &lt;span class="n"&gt;cobrancaService&lt;/span&gt;&lt;span class="o"&gt;;&lt;/span&gt;

    &lt;span class="nd"&gt;@GET&lt;/span&gt;
    &lt;span class="kd"&gt;public&lt;/span&gt; &lt;span class="nc"&gt;List&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nc"&gt;Cobranca&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="nf"&gt;listarTodas&lt;/span&gt;&lt;span class="o"&gt;()&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
        &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;cobrancaService&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;listarTodas&lt;/span&gt;&lt;span class="o"&gt;();&lt;/span&gt;
    &lt;span class="o"&gt;}&lt;/span&gt;

    &lt;span class="nd"&gt;@GET&lt;/span&gt;
    &lt;span class="nd"&gt;@Path&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"/vencidas"&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt;
    &lt;span class="kd"&gt;public&lt;/span&gt; &lt;span class="nc"&gt;List&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nc"&gt;Cobranca&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="nf"&gt;listarVencidas&lt;/span&gt;&lt;span class="o"&gt;()&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
        &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;cobrancaService&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;listarVencidas&lt;/span&gt;&lt;span class="o"&gt;();&lt;/span&gt;
    &lt;span class="o"&gt;}&lt;/span&gt;

    &lt;span class="nd"&gt;@GET&lt;/span&gt;
    &lt;span class="nd"&gt;@Path&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"/pendentes"&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt;
    &lt;span class="kd"&gt;public&lt;/span&gt; &lt;span class="nc"&gt;List&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nc"&gt;Cobranca&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="nf"&gt;listarPendentes&lt;/span&gt;&lt;span class="o"&gt;()&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
        &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;cobrancaService&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;listarPendentes&lt;/span&gt;&lt;span class="o"&gt;();&lt;/span&gt;
    &lt;span class="o"&gt;}&lt;/span&gt;

    &lt;span class="nd"&gt;@GET&lt;/span&gt;
    &lt;span class="nd"&gt;@Path&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"/resumo"&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt;
    &lt;span class="nd"&gt;@Produces&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="nc"&gt;MediaType&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;TEXT_PLAIN&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt;
    &lt;span class="kd"&gt;public&lt;/span&gt; &lt;span class="nc"&gt;String&lt;/span&gt; &lt;span class="nf"&gt;resumo&lt;/span&gt;&lt;span class="o"&gt;()&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
        &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nc"&gt;String&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;format&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"Total vencido: R$ %s | Vencidas: %d | Pendentes: %d"&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt;
                &lt;span class="n"&gt;cobrancaService&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;totalVencido&lt;/span&gt;&lt;span class="o"&gt;(),&lt;/span&gt;
                &lt;span class="n"&gt;cobrancaService&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;listarVencidas&lt;/span&gt;&lt;span class="o"&gt;().&lt;/span&gt;&lt;span class="na"&gt;size&lt;/span&gt;&lt;span class="o"&gt;(),&lt;/span&gt;
                &lt;span class="n"&gt;cobrancaService&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;listarPendentes&lt;/span&gt;&lt;span class="o"&gt;().&lt;/span&gt;&lt;span class="na"&gt;size&lt;/span&gt;&lt;span class="o"&gt;());&lt;/span&gt;
    &lt;span class="o"&gt;}&lt;/span&gt;
&lt;span class="o"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Configuração
&lt;/h2&gt;

&lt;p&gt;&lt;code&gt;application.properties&lt;/code&gt;:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight properties"&gt;&lt;code&gt;&lt;span class="py"&gt;quarkus.application.name&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="s"&gt;quarkus-scheduler-fintech&lt;/span&gt;
&lt;span class="py"&gt;quarkus.scheduler.cron-type&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="s"&gt;quartz&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Rodando
&lt;/h2&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;git clone https://github.com/dellamas/quarkus-scheduler-fintech
&lt;span class="nb"&gt;cd &lt;/span&gt;quarkus-scheduler-fintech
./mvnw quarkus:dev
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Assim que subir, o job de verificação de vencimentos já começa a rodar a cada 30 segundos. Acompanhe no terminal e, em paralelo, teste:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;curl http://localhost:8080/cobrancas
curl http://localhost:8080/cobrancas/vencidas
curl http://localhost:8080/cobrancas/resumo
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Por que o Scheduler e não o Quartz?
&lt;/h2&gt;

&lt;p&gt;O &lt;code&gt;quarkus-scheduler&lt;/code&gt; é a opção leve — resolve bem pra aplicações de instância única. Precisa de clustering, com múltiplas instâncias disputando o mesmo job? Aí o &lt;code&gt;quarkus-quartz&lt;/code&gt; faz mais sentido. Mas pra maioria dos cenários do dia a dia, o Scheduler padrão dá conta.&lt;/p&gt;




&lt;p&gt;O código completo está no &lt;a href="https://github.com/dellamas/quarkus-scheduler-fintech" rel="noopener noreferrer"&gt;GitHub&lt;/a&gt;. Se fez sentido pra você, deixa uma estrela no repositório — ajuda mais do que parece.&lt;/p&gt;

&lt;p&gt;Eu sou o Luis De Llamas, Developer Advocate na act digital, Oracle ACE e IBM Champion. Se quiser acompanhar mais conteúdo sobre Quarkus, Java e o que rola no ecossistema, me encontra aqui:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;a href="https://www.linkedin.com/in/luisfabriciodellamas/" rel="noopener noreferrer"&gt;LinkedIn&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://github.com/dellamas" rel="noopener noreferrer"&gt;GitHub&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Nos vemos no próximo.&lt;/p&gt;

</description>
      <category>quarkus</category>
      <category>java</category>
      <category>braziliandevs</category>
    </item>
    <item>
      <title>Bob - how much is your time worth?</title>
      <dc:creator>Luis Fabrício De Llamas</dc:creator>
      <pubDate>Sun, 16 Nov 2025 14:30:33 +0000</pubDate>
      <link>https://forem.com/dellamas/bob-how-much-is-your-time-worth-3hc3</link>
      <guid>https://forem.com/dellamas/bob-how-much-is-your-time-worth-3hc3</guid>
      <description>&lt;p&gt;Bob continues to surprise me.&lt;/p&gt;

&lt;p&gt;Recently, I took a moment to observe how the developers I know are using AI in their daily work. It’s not that AI isn’t present. It is. But the way it’s used still feels far from being truly integrated into the development process. And this varies a lot depending on the developer’s seniority. In some cases, this difference can even affect the process of building long-term knowledge, which is a topic worthy of its own post.  But the question that stayed in my mind was another one: why aren’t we using AI in a more fluid, natural way, as part of our workflow?&lt;/p&gt;

&lt;p&gt;Are we lacking clarity about what should be delegated? Are we lacking trust? &lt;/p&gt;

&lt;p&gt;With that in mind, I decided to take advantage of my early access to Project Bob ( IBM ) and run a more realistic test. I listed a few tasks that I see happening all the time in daily development work, tasks that no one finds particularly difficult, but everyone knows are… exhausting. Lots of small steps, legacy dependencies, old codebases, short but vague specs, branch creation, tiny adjustments, tests, validations… that classic mix of little things that end up consuming a huge amount of time. &lt;/p&gt;

&lt;p&gt;I picked a very concrete task: modernizing a #Java 8 application to Java 21 and replacing RestTemplate with RestClient. Nothing epic, nothing extremely complex, just something extremely common in the life of a backend Java developer. And then another question came to mind: why do tasks we understand so well still take so long? &lt;/p&gt;

&lt;p&gt;When you look at the modernization, the value is obvious. Java 21 brings better performance, improved security, new language features, and virtual threads. The modern Spring Boot ecosystem requires Jakarta. And RestTemplate, even though it has been our companion for so many years, no longer receives improvements, while RestClient provides a much more intuitive, modern, and fluent API. It’s hard not to want something better.&lt;/p&gt;

&lt;p&gt;The example application had the same foundation many systems still have today: Java 8, Spring Boot 2.x, RestTemplate, and javax.validation. After the modernization, it became a current and fully updated application using Java 21, Spring Boot 3.x, RestClient, Jakarta Validation, and virtual threads. &lt;/p&gt;

&lt;p&gt;The prompt I used was:&lt;/p&gt;

&lt;p&gt;“Update this project from Java 8 to Java 21 and replace all usages of RestTemplate with the new Spring RestClient API. Modernize the code where needed, adjust dependencies, update configuration, and ensure compatibility with Spring Boot’s latest recommended patterns. Provide the updated code examples and explain any breaking changes or required refactoring.” &lt;/p&gt;

&lt;p&gt;And here comes the interesting part. This entire task, which normally involves understanding the context, reviewing code, updating dependencies, replacing HTTP calls, testing functionality, reviewing behaviors, fixing warnings, validating the flow, and ensuring compatibility, would easily be estimated at two days of work. I did the whole thing with Bob and, in a demo extremely similar to a real-world scenario, everything was completed in just over four minutes, as you can see in the video. &lt;/p&gt;

&lt;p&gt;It’s hard not to stop and think: Does Bob really understand the project?&lt;/p&gt;

&lt;p&gt;Based on what I saw, the answer is yes. He understands the context, the application’s style, the dependencies, the patterns used, and the adjustments required. And he does this in a way that doesn’t disrupt the developer, doesn’t break the flow, and doesn’t require you to adapt too much. He simply works with you. &lt;/p&gt;

&lt;p&gt;And there’s more. IBM has already reported real productivity gains close to forty-five percent in teams that tested Bob. It helps understand legacy code, accelerates onboarding for new developers, reduces migration effort, supports complex modernization tasks, and removes a huge amount of repetitive work from developers’ shoulders. &lt;/p&gt;

&lt;p&gt;So the big question is: why are we still doing all of this manually? How many tasks like this are sitting in your backlog right now? What could you be delivering or learning if part of this work were delegated? &lt;/p&gt;

&lt;p&gt;Tools like Bob weren’t created just to speed up delivery. They were created to transform the way we work, freeing time and energy for what actually helps developers evolve: creating, thinking, deciding, exploring, connecting ideas, and delivering real value. &lt;/p&gt;

&lt;p&gt;And here’s a fun note: as I’m writing this post, Bob is currently migrating this same application to #Quarkus. So let me ask you this… how much is your time worth? &lt;/p&gt;

&lt;p&gt;Oh, and if you enjoyed this content and want to learn more about emerging technologies, here’s an invitation!&lt;br&gt;&lt;br&gt;
We have a very active community where we share knowledge, answer questions, and network.  &lt;/p&gt;

&lt;h3&gt;
  
  
  Join the Quarkus Club:
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Discord:&lt;/strong&gt; &lt;a href="https://discord.gg/nMeSs2u4ZJ" rel="noopener noreferrer"&gt;https://discord.gg/nMeSs2u4ZJ&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;YouTube:&lt;/strong&gt; &lt;a href="https://www.youtube.com/@QuarkusClub" rel="noopener noreferrer"&gt;https://www.youtube.com/@QuarkusClub&lt;/a&gt;
&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;And if you’d like to chat about Oracle, AI, or any tech topic in general, feel free to connect with me on LinkedIn:  &lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;LinkedIn:&lt;/strong&gt; &lt;a href="https://www.linkedin.com/in/luisfabriciodellamas/" rel="noopener noreferrer"&gt;https://www.linkedin.com/in/luisfabriciodellamas/&lt;/a&gt;
&lt;/li&gt;
&lt;/ul&gt;

</description>
      <category>ibm</category>
      <category>java</category>
      <category>ai</category>
      <category>spring</category>
    </item>
    <item>
      <title>Instrumentação com OpenTelemetry: Zero-Code, Code-Based ou Bibliotecas Instrumentadas?</title>
      <dc:creator>Luis Fabrício De Llamas</dc:creator>
      <pubDate>Sat, 05 Oct 2024 01:19:40 +0000</pubDate>
      <link>https://forem.com/dellamas/instrumentacao-com-opentelemetry-zero-code-code-based-ou-bibliotecas-instrumentadas-3477</link>
      <guid>https://forem.com/dellamas/instrumentacao-com-opentelemetry-zero-code-code-based-ou-bibliotecas-instrumentadas-3477</guid>
      <description>&lt;p&gt;A instrumentação é o coração da observabilidade em sistemas complexos e distribuídos, e ferramentas como o &lt;strong&gt;OpenTelemetry&lt;/strong&gt; estão transformando a forma como desenvolvedores e arquitetos coletam dados de suas aplicações. Neste artigo, vamos explorar as três abordagens principais de instrumentação oferecidas pelo OpenTelemetry: &lt;strong&gt;instrumentação zero-code&lt;/strong&gt;, &lt;strong&gt;instrumentação code-based&lt;/strong&gt; e &lt;strong&gt;bibliotecas instrumentadas&lt;/strong&gt;. Cada uma delas possui suas vantagens e desvantagens, e entender qual delas utilizar pode ser determinante para o sucesso do monitoramento do seu sistema.&lt;/p&gt;

&lt;h2&gt;
  
  
  Instrumentação Zero-Code: Simplicidade ou Limitação?
&lt;/h2&gt;

&lt;p&gt;A &lt;strong&gt;instrumentação zero-code&lt;/strong&gt; é uma proposta intrigante. O conceito é simples: sem precisar modificar o código da aplicação, você consegue coletar métricas e traços diretamente. Isso se torna possível através de agentes ou ferramentas que fazem o trabalho pesado nos bastidores, interceptando chamadas e gerando os dados de observabilidade.&lt;/p&gt;

&lt;p&gt;Imagine que você tem um sistema legado, ou até mesmo uma aplicação moderna, e precisa urgentemente começar a monitorar seu desempenho. A zero-code permite que você faça isso rapidamente. No entanto, há um lado negativo: essa abordagem pode ser limitada em termos de customização e profundidade das informações capturadas. Por exemplo, em uma aplicação complexa, como as utilizadas na série &lt;em&gt;Naruto&lt;/em&gt; (se você fosse monitorar todos os movimentos e interações entre os personagens), a instrumentação zero-code seria suficiente para capturar os detalhes de cada combate? Provavelmente não. Ela oferece uma visão mais superficial e genérica, ideal para situações onde a velocidade é crucial, mas pode deixar a desejar quando se precisa de um nível maior de controle.&lt;/p&gt;

&lt;h2&gt;
  
  
  Instrumentação Code-Based: Controle Total
&lt;/h2&gt;

&lt;p&gt;Se a zero-code se trata de velocidade e simplicidade, a &lt;strong&gt;instrumentação baseada em código&lt;/strong&gt; é o oposto: aqui, o desenvolvedor tem controle total. Ao inserir manualmente as chamadas de instrumentação no código, é possível personalizar completamente o que é rastreado e como esses dados são reportados. Isso significa que se você precisa de visibilidade total sobre uma função específica ou fluxo de trabalho, esta é a abordagem ideal.&lt;/p&gt;

&lt;p&gt;No entanto, essa flexibilidade vem com um preço. Requer tempo e esforço da equipe de desenvolvimento. É uma escolha particularmente vantajosa quando a aplicação exige monitoramento detalhado em áreas específicas que a instrumentação automática não cobre de forma eficiente. Se voltarmos ao exemplo de &lt;em&gt;Naruto&lt;/em&gt;, isso seria como monitorar não só os movimentos de cada personagem, mas também suas intenções, motivações e até o fluxo de chakra. Com a instrumentação baseada em código, você pode capturar tudo isso com precisão, mas precisará trabalhar mais para configurá-la.&lt;/p&gt;

&lt;h2&gt;
  
  
  Bibliotecas Instrumentadas: O Melhor dos Dois Mundos?
&lt;/h2&gt;

&lt;p&gt;Para aqueles que querem o meio-termo entre a simplicidade da instrumentação zero-code e o controle da code-based, as &lt;strong&gt;bibliotecas instrumentadas&lt;/strong&gt; são uma excelente opção. Elas vêm pré-configuradas com pontos de instrumentação e oferecem integração nativa com o OpenTelemetry. Você pode usá-las para monitorar componentes específicos do sistema sem precisar reinventar a roda.&lt;/p&gt;

&lt;p&gt;Bibliotecas populares como frameworks web e sistemas de banco de dados já possuem suporte nativo para OpenTelemetry, o que facilita a adoção e acelera o processo de coleta de dados. Novamente, utilizando o universo de &lt;em&gt;Naruto&lt;/em&gt; como exemplo, seria como pegar uma biblioteca pronta para monitorar os combates de cada ninja sem precisar escrever o código para isso do zero. Prático, não?&lt;/p&gt;

&lt;h2&gt;
  
  
  Conclusão
&lt;/h2&gt;

&lt;p&gt;No final das contas, a escolha entre zero-code, code-based ou bibliotecas instrumentadas vai depender das necessidades do seu projeto e da sua equipe. Se você precisa de uma solução rápida e eficiente, zero-code pode ser a melhor escolha. Mas se o seu foco é controle e precisão, code-based provavelmente será o caminho. Já as bibliotecas instrumentadas oferecem um excelente compromisso entre ambos.&lt;/p&gt;

&lt;p&gt;Luis De Llamas&lt;/p&gt;

</description>
      <category>beginners</category>
      <category>observability</category>
      <category>opentelemetry</category>
      <category>opensource</category>
    </item>
    <item>
      <title>OpenTelemetry: Traces, Métricas, Logs e Baggage</title>
      <dc:creator>Luis Fabrício De Llamas</dc:creator>
      <pubDate>Thu, 03 Oct 2024 22:06:09 +0000</pubDate>
      <link>https://forem.com/dellamas/opentelemetry-traces-metricas-logs-e-baggage-4foo</link>
      <guid>https://forem.com/dellamas/opentelemetry-traces-metricas-logs-e-baggage-4foo</guid>
      <description>&lt;p&gt;Com o avanço das arquiteturas distribuídas e o uso crescente de microserviços, o monitoramento tradicional das aplicações deixou de ser suficiente. Ferramentas que apenas capturam métricas ou logs isoladamente não conseguem fornecer uma visão completa do comportamento de sistemas complexos. É nesse contexto que o OpenTelemetry surge como uma solução robusta, oferecendo uma abordagem unificada para coletar e correlacionar diferentes sinais. Entre esses sinais, estão os &lt;em&gt;traces&lt;/em&gt;, as métricas, os logs e o &lt;em&gt;baggage&lt;/em&gt;, cada um desempenhando um papel fundamental na jornada rumo à observabilidade completa.&lt;/p&gt;

&lt;h2&gt;
  
  
  1. O que são Traces?
&lt;/h2&gt;

&lt;p&gt;Os &lt;em&gt;traces&lt;/em&gt; são essenciais para rastrear o caminho de uma requisição através de vários serviços em um sistema distribuído. Cada requisição pode passar por diversas camadas e serviços, e os &lt;em&gt;traces&lt;/em&gt; registram todas essas interações em detalhes. Isso permite visualizar o fluxo completo de uma transação, desde a entrada no frontend até a interação com o banco de dados, ajudando a identificar onde ocorrem falhas ou lentidões.&lt;/p&gt;

&lt;p&gt;Como descrito na &lt;a href="https://opentelemetry.io/docs/concepts/signals/traces/" rel="noopener noreferrer"&gt;documentação oficial do OpenTelemetry&lt;/a&gt;, os &lt;em&gt;traces&lt;/em&gt; são compostos por &lt;em&gt;spans&lt;/em&gt;, que representam cada etapa individual da requisição. Esses &lt;em&gt;spans&lt;/em&gt; são então agrupados para formar um &lt;em&gt;trace&lt;/em&gt;, que fornece uma visão coesa do fluxo da transação.&lt;/p&gt;

&lt;h2&gt;
  
  
  2. Métricas: Monitoramento da Saúde do Sistema
&lt;/h2&gt;

&lt;p&gt;As métricas são outro sinal importante fornecido pelo OpenTelemetry. Elas são essenciais para monitorar o desempenho geral do sistema, oferecendo insights sobre o uso de recursos, como CPU e memória, e a taxa de erro de serviços. Enquanto os &lt;em&gt;traces&lt;/em&gt; focam na rastreabilidade de uma requisição específica, as &lt;a href="https://opentelemetry.io/docs/concepts/signals/metrics/" rel="noopener noreferrer"&gt;métricas&lt;/a&gt; proporcionam uma visão macro, permitindo que você monitore a "saúde" da aplicação como um todo.&lt;/p&gt;

&lt;p&gt;Por exemplo, métricas como o tempo de resposta médio, o número de requisições por segundo ou a taxa de erros ajudam a identificar padrões e tendências de desempenho, além de alertar sobre possíveis problemas que possam estar afetando o sistema.&lt;/p&gt;

&lt;h2&gt;
  
  
  3. Logs: Capturando Eventos Críticos
&lt;/h2&gt;

&lt;p&gt;Os &lt;a href="https://opentelemetry.io/docs/concepts/signals/logs/" rel="noopener noreferrer"&gt;logs&lt;/a&gt; são usados para registrar eventos significativos no sistema, como erros, transações ou qualquer outro evento relevante. Eles complementam os &lt;em&gt;traces&lt;/em&gt; e as métricas, oferecendo contexto adicional sobre o que aconteceu em determinado ponto do tempo.&lt;/p&gt;

&lt;p&gt;Enquanto um &lt;em&gt;trace&lt;/em&gt; mostra o caminho de uma requisição e uma métrica oferece uma visão numérica sobre o desempenho, os logs trazem detalhes específicos dos eventos que ocorreram. Por exemplo, se uma falha for detectada em um &lt;em&gt;trace&lt;/em&gt;, os logs podem fornecer detalhes sobre o erro que causou a falha, ajudando a solucionar o problema de forma mais eficiente.&lt;/p&gt;

&lt;h2&gt;
  
  
  4. Baggage: Contexto Compartilhado
&lt;/h2&gt;

&lt;p&gt;O &lt;a href="https://opentelemetry.io/docs/concepts/signals/baggage/" rel="noopener noreferrer"&gt;&lt;em&gt;baggage&lt;/em&gt;&lt;/a&gt; é um sinal muitas vezes subestimado, mas que tem um papel crítico no rastreamento de requisições distribuídas. Ele permite que informações contextuais sejam propagadas entre serviços em uma requisição, o que é extremamente útil em sistemas de microserviços. Com o &lt;em&gt;baggage&lt;/em&gt;, é possível compartilhar atributos e dados entre diferentes partes do sistema, garantindo que o contexto de uma requisição seja mantido de ponta a ponta.&lt;/p&gt;

&lt;p&gt;Por exemplo, imagine que uma requisição passe por vários serviços em diferentes partes do sistema. O &lt;em&gt;baggage&lt;/em&gt; garante que atributos como IDs de transações ou dados do usuário sejam transmitidos entre todos os serviços envolvidos, facilitando a correlação de logs, métricas e &lt;em&gt;traces&lt;/em&gt;.&lt;/p&gt;

&lt;h2&gt;
  
  
  A Importância de Combinar Esses Sinais
&lt;/h2&gt;

&lt;p&gt;Cada um desses sinais &lt;em&gt;traces&lt;/em&gt;, métricas, logs e *baggage*tem uma função específica, mas é na combinação deles que o verdadeiro poder do OpenTelemetry se revela. Quando utilizados juntos, eles proporcionam uma visão detalhada e coesa de todos os aspectos do sistema. Por exemplo:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Um &lt;em&gt;trace&lt;/em&gt; pode mostrar o fluxo completo de uma requisição.&lt;/li&gt;
&lt;li&gt;Métricas podem indicar que o tempo de resposta médio aumentou em determinado serviço.&lt;/li&gt;
&lt;li&gt;Logs podem fornecer detalhes sobre erros que ocorreram.&lt;/li&gt;
&lt;li&gt;O &lt;em&gt;baggage&lt;/em&gt; garante que informações críticas estejam disponíveis em cada estágio da requisição.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Essa combinação de sinais possibilita uma observabilidade muito mais rica e detalhada, permitindo que as equipes identifiquem rapidamente onde estão os problemas e como resolvê-los de forma eficiente.&lt;/p&gt;

&lt;h2&gt;
  
  
  Conclusão
&lt;/h2&gt;

&lt;p&gt;Em um mundo onde arquiteturas distribuídas e microserviços dominam, monitorar e entender o comportamento das aplicações exige mais do que simples métricas ou logs isolados. O OpenTelemetry, com seus sinais integrados de &lt;em&gt;traces&lt;/em&gt;, métricas, logs e &lt;em&gt;baggage&lt;/em&gt;, fornece a visibilidade necessária para que equipes de DevOps e desenvolvedores possam manter o desempenho ideal de suas aplicações.&lt;/p&gt;

&lt;p&gt;Se você ainda não está utilizando todos esses sinais de forma combinada, pode estar perdendo oportunidades de otimizar o monitoramento do seu sistema. Como você tem lidado com a observabilidade de suas aplicações distribuídas? Já utiliza OpenTelemetry? Compartilhe suas experiências nos comentários e siga-me no &lt;a href="https://www.linkedin.com/in/luisfabriciodellamas/" rel="noopener noreferrer"&gt;LinkedIn&lt;/a&gt; para mais insights sobre observabilidade e desempenho de sistemas complexos.&lt;/p&gt;

</description>
      <category>opentelemetry</category>
      <category>beginners</category>
      <category>java</category>
      <category>observability</category>
    </item>
    <item>
      <title>Explorando a Observabilidade com OpenTelemetry: Propagação de Contexto e Arquiteturas Distribuídas</title>
      <dc:creator>Luis Fabrício De Llamas</dc:creator>
      <pubDate>Wed, 02 Oct 2024 23:53:34 +0000</pubDate>
      <link>https://forem.com/dellamas/explorando-a-observabilidade-com-opentelemetry-propagacao-de-contexto-e-arquiteturas-distribuidas-28bi</link>
      <guid>https://forem.com/dellamas/explorando-a-observabilidade-com-opentelemetry-propagacao-de-contexto-e-arquiteturas-distribuidas-28bi</guid>
      <description>&lt;p&gt;A &lt;strong&gt;observabilidade&lt;/strong&gt; é um dos pilares para garantir o sucesso de sistemas complexos e distribuídos. Diferente do monitoramento tradicional, que reage a alertas específicos, a observabilidade oferece uma visão ampla e profunda do sistema, baseada em três pilares principais: &lt;strong&gt;métricas&lt;/strong&gt;, &lt;strong&gt;logs&lt;/strong&gt; e &lt;strong&gt;rastreamentos (traces)&lt;/strong&gt;. Isso possibilita não só a identificação de problemas, mas também a sua causa raiz, essencial para arquiteturas modernas como microservices.&lt;/p&gt;

&lt;h2&gt;
  
  
  O Papel do OpenTelemetry
&lt;/h2&gt;

&lt;p&gt;O &lt;strong&gt;OpenTelemetry&lt;/strong&gt; é uma estrutura open-source que facilita a implementação de uma estratégia robusta de observabilidade. Ele unifica a coleta de métricas, logs e rastreamentos distribuídos, padronizando como os dados são capturados e transportados. Dessa forma, mesmo em sistemas distribuídos, onde múltiplos serviços se interconectam, é possível ter uma visão clara do fluxo de dados. &lt;/p&gt;

&lt;h3&gt;
  
  
  Observabilidade vs Monitoramento
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Monitoramento&lt;/strong&gt;: Coleta dados estáticos para detectar se algo está errado.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Observabilidade&lt;/strong&gt;: Permite entender &lt;em&gt;por que&lt;/em&gt; algo está errado, correlacionando eventos de diversas fontes e serviços.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Um dos desafios enfrentados em arquiteturas distribuídas é garantir que os dados de uma requisição sejam correlacionados entre diferentes serviços. E é aqui que entra a &lt;strong&gt;propagação de contexto&lt;/strong&gt;.&lt;/p&gt;

&lt;h2&gt;
  
  
  O que é a Propagação de Contexto?
&lt;/h2&gt;

&lt;p&gt;Imagine um cenário onde uma requisição atravessa diversos microsserviços. Como rastrear cada uma dessas interações para entender todo o fluxo? Isso é possível graças à &lt;strong&gt;propagação de contexto&lt;/strong&gt;, que garante que as informações sobre uma requisição (como IDs de rastreamento e spans) sejam passadas de um serviço para outro.&lt;/p&gt;

&lt;p&gt;A propagação de contexto é como o fio condutor que liga todas as partes da aplicação, permitindo que você veja o trajeto completo de uma requisição. Esse processo é essencial para entender a performance e localizar problemas em sistemas altamente distribuídos. Sem a propagação de contexto, teríamos visibilidade apenas de partes isoladas do sistema, perdendo a correlação entre eventos.&lt;/p&gt;

&lt;h3&gt;
  
  
  Um Exemplo com OpenTelemetry:
&lt;/h3&gt;

&lt;p&gt;Vamos imaginar um exemplo prático com o Naruto: &lt;/p&gt;

&lt;p&gt;Naruto (Serviço A) pede ao Kakashi (Serviço B) para lhe dar uma missão, e Kakashi consulta o Banco de Dados de Missões (Serviço C). Cada interação precisa ser rastreada de forma que, se algo der errado entre Kakashi e o banco de dados, possamos identificar onde está o erro. O OpenTelemetry facilita isso associando spans (ou trechos de rastreamento) a cada parte da requisição, garantindo que todas as interações sejam correlacionadas.&lt;/p&gt;

&lt;h3&gt;
  
  
  Mecanismos da Propagação de Contexto
&lt;/h3&gt;

&lt;p&gt;O OpenTelemetry utiliza padrões como o &lt;strong&gt;W3C Trace Context&lt;/strong&gt; ( falaremos mais dele em outra ocasião), que define como o contexto de rastreamento deve ser propagado e lido por diferentes serviços. Esses dados podem ser transmitidos por meio de headers HTTP ou outros protocolos, permitindo a rastreabilidade em uma grande variedade de plataformas e ambientes.&lt;/p&gt;

&lt;h3&gt;
  
  
  Desafios na Propagação de Contexto
&lt;/h3&gt;

&lt;p&gt;Implementar a propagação de contexto traz alguns desafios:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Sobrecarga de dados&lt;/strong&gt;: Quanto mais serviços são envolvidos, mais spans e dados precisam ser coletados, processados e armazenados. Isso pode impactar a performance do sistema.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Compatibilidade entre serviços&lt;/strong&gt;: Todos os serviços devem implementar corretamente a propagação de contexto, ou a cadeia de rastreamento será quebrada, comprometendo a observabilidade.&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Conclusão
&lt;/h2&gt;

&lt;p&gt;A &lt;strong&gt;observabilidade&lt;/strong&gt; é indispensável para garantir a eficiência e confiabilidade de arquiteturas distribuídas. O OpenTelemetry desempenha um papel muito importante ao padronizar e simplificar a coleta de métricas, logs e rastreamentos. A &lt;strong&gt;propagação de contexto&lt;/strong&gt;, por sua vez, é o mecanismo que permite rastrear requisições em um sistema distribuído, garantindo que possamos ter uma visão completa de todas as interações, desde o início até o fim.&lt;/p&gt;

&lt;p&gt;Para quem está adotando ou pensando em adotar microsserviços, a implementação de uma estratégia sólida de observabilidade, com o OpenTelemetry, é inevitável. &lt;strong&gt;E você? Já utiliza o OpenTelemetry no seu ambiente?&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Me siga no &lt;a href="https://www.linkedin.com/in/luisfabriciodellamas/" rel="noopener noreferrer"&gt;LinkedIn&lt;/a&gt; para acompanhar mais conteúdos com este.&lt;/p&gt;

</description>
      <category>observability</category>
      <category>opensource</category>
      <category>java</category>
      <category>opentelemetry</category>
    </item>
    <item>
      <title>[ptbr] Podman, uma bela opção.</title>
      <dc:creator>Luis Fabrício De Llamas</dc:creator>
      <pubDate>Wed, 06 Sep 2023 19:31:43 +0000</pubDate>
      <link>https://forem.com/dellamas/ptbr-podman-uma-bela-opcao-1lg6</link>
      <guid>https://forem.com/dellamas/ptbr-podman-uma-bela-opcao-1lg6</guid>
      <description>&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F01jf14h54eal86tdm6ls.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F01jf14h54eal86tdm6ls.png" alt=" " width="800" height="450"&gt;&lt;/a&gt;&lt;br&gt;
Os Benefícios do Podman : Parte 1&lt;/p&gt;

&lt;p&gt;O mundo da computação em contêineres é movimentado e em constante evolução, e várias ferramentas estão disponíveis para criar, executar e gerenciar contêineres. O Docker tem sido amplamente popular nesse campo, mas o Podman surgiu como uma alternativa poderosa que oferece diversos benefícios.Neste primeiro posto veremos sobre o que é nos posteriores veremos seu uso junto ao Quarkus.&lt;/p&gt;

&lt;h1&gt;
  
  
  O Que é o Podman?
&lt;/h1&gt;

&lt;p&gt;O Podman é uma ferramenta de gerenciamento de contêineres de código aberto parecida ao Docker em muitos aspectos. Ele permite criar, executar e gerenciar contêineres Linux, mas com algumas vantagens bem interessantes.&lt;/p&gt;

&lt;h1&gt;
  
  
  Benefícios do Podman
&lt;/h1&gt;

&lt;p&gt;&lt;strong&gt;Sem Dependência de Daemon&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Uma das principais vantagens do Podman é que ele não requer um daemon (processo em segundo plano) para executar contêineres. Isso significa que não há necessidade de um processo constante em execução no sistema, como acontece com o Docker. Isso simplifica a configuração e a segurança, tornando o Podman uma escolha atraente para ambientes em que a simplicidade e o isolamento são essenciais.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Compatibilidade com o Docker&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;O Podman foi projetado para ser compatível com o Docker, o que significa que você pode usar comandos semelhantes aos do Docker para criar e gerenciar contêineres. Isso facilita a transição para o Podman, especialmente se você já estiver familiarizado com o Docker.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Segurança Aprimorada&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;O Podman oferece recursos avançados de segurança, como namespaces mais rigorosos e suporte a contêineres rootless (sem a necessidade de privilégios de superusuário). Isso ajuda a garantir que os contêineres executados com o Podman sejam altamente isolados e menos propensos a ameaças de segurança.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Pods para Orquestração Simples&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;O Podman introduz o conceito de "Pods", que são grupos de contêineres que compartilham um namespace de rede. Isso facilita a execução de várias contêineres como uma unidade coesa, o que é útil para aplicações que exigem comunicação próxima entre contêineres.&lt;/p&gt;

&lt;h1&gt;
  
  
  Exemplos de Comandos Podman
&lt;/h1&gt;

&lt;p&gt;Executar um Contêiner:&lt;/p&gt;

&lt;p&gt;&lt;code&gt;podman run -it --rm ubuntu:latest /bin/bash&lt;/code&gt;&lt;br&gt;
Este comando inicia um contêiner Ubuntu interativo e remove-o automaticamente após a saída.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Listar Contêineres em Execução:&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;&lt;code&gt;podman ps&lt;/code&gt;&lt;br&gt;
Esse comando exibe uma lista dos contêineres em execução.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Criar um Pod e Adicionar Contêineres:&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;&lt;code&gt;podman pod create --name mypod&lt;br&gt;
podman run -d --name webapp --pod mypod nginx:latest&lt;br&gt;
podman run -d --name db --pod mypod postgres:latest&lt;/code&gt;&lt;br&gt;
Aqui, criamos um pod chamado "mypod" e adicionamos contêineres web e de banco de dados a ele.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Parar e Remover Contêineres:&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;&lt;code&gt;podman stop &amp;lt;container_id&amp;gt;&lt;br&gt;
podman rm &amp;lt;container_id&amp;gt;&lt;/code&gt;&lt;br&gt;
Esses comandos interrompem e removem um contêiner específico.&lt;/p&gt;

&lt;p&gt;Se você está procurando uma ferramenta de contêiner que seja fácil de usar e ao mesmo tempo ofereça recursos avançados, o Podman pode ser a escolha certa para você. Na Parte 2 , veremos como os dev services do Quarkus funcionam com o Podman.&lt;/p&gt;

</description>
      <category>quarkus</category>
      <category>podman</category>
      <category>braziliandevs</category>
      <category>prbr</category>
    </item>
    <item>
      <title>Dev Services for Databases</title>
      <dc:creator>Luis Fabrício De Llamas</dc:creator>
      <pubDate>Mon, 04 Sep 2023 14:59:39 +0000</pubDate>
      <link>https://forem.com/dellamas/dev-services-for-databases-2b1c</link>
      <guid>https://forem.com/dellamas/dev-services-for-databases-2b1c</guid>
      <description>&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Ff3gnbtv0y055z08t40w5.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Ff3gnbtv0y055z08t40w5.png" alt=" " width="800" height="450"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h1&gt;
  
  
  Quarkus Dev Services for Java Developers.
&lt;/h1&gt;

&lt;p&gt;When it comes to Java development, agility and efficiency are crucial. One of the challenges developers face is configuring and managing databases for their applications. Quarkus, a modern and efficient Java framework, provides an elegant solution to this problem with its "Dev Services" functionality for databases.&lt;/p&gt;

&lt;h1&gt;
  
  
  What Are Dev Services?
&lt;/h1&gt;

&lt;p&gt;Dev Services are a feature of Quarkus that allow developers to have a fully configured and ready-to-use database without the need for complex configurations. This is particularly valuable during development and testing when agility is paramount. Quarkus supports various types of databases, including PostgreSQL, MySQL, MariaDB, H2, and others. Here are some of the benefits: &lt;/p&gt;

&lt;h1&gt;
  
  
  Zero Configuration
&lt;/h1&gt;

&lt;p&gt;You don't need to manually configure the database URL, username, and password in your application. Quarkus does this automatically for you, saving you time and effort.&lt;/p&gt;

&lt;h1&gt;
  
  
  Automatic Startup
&lt;/h1&gt;

&lt;p&gt;Dev Services automatically start a database server in development mode and during testing. This means you don't need to manually start a server. The application is configured automatically.&lt;/p&gt;

&lt;h1&gt;
  
  
  Ease of Use
&lt;/h1&gt;

&lt;p&gt;To use Dev Services, simply include the relevant extension for the type of database you want to use (reactive or JDBC). No need to configure a database URL, username, and password. Quarkus provides the database, and you can start coding without worrying about settings.&lt;/p&gt;

&lt;h1&gt;
  
  
  Configuration Examples for PostgreSQL:
&lt;/h1&gt;

&lt;p&gt;&lt;strong&gt;Enabling / Disabling Dev Services for the Database:&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;You can disable the automatic start of the Dev Services database in the application.properties file using the following configuration:&lt;/p&gt;

&lt;p&gt;properties&lt;/p&gt;

&lt;p&gt;&lt;code&gt;quarkus.datasource.devservices.enabled=false&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;License Acceptance for Proprietary Databases:&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;If you are using a proprietary database such as DB2 or MSSQL, you will need to accept the license agreement. Create a container-license-acceptance.txt file in your project and add the image name and tag of the database, as shown in the example:&lt;/p&gt;

&lt;p&gt;properties&lt;/p&gt;

&lt;p&gt;&lt;code&gt;src/main/resources/container-license-acceptance.txt&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;&lt;code&gt;ibmcom/db2:11.5.0.0a&lt;/code&gt;&lt;br&gt;
&lt;code&gt;mcr.microsoft.com/mssql/server:2017-CU12&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Mapping Volumes for Database Data Persistence:&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;You can map volumes from the Docker host's filesystem to containers to provide files such as scripts or configurations and to preserve database data. Here's an example:&lt;/p&gt;

&lt;p&gt;properties&lt;/p&gt;

&lt;p&gt;&lt;code&gt;quarkus.datasource.devservices.volumes."/path/from"=/container/to&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;In the above example, the directory "/path/from" on the local machine is accessible at "/container/to" in the container.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Connecting to a Database Running as a Dev Service:&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;You can connect to a database running as a Dev Service in the same way you would with any database running inside a Docker container.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Configuration Reference:&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Quarkus offers a wide range of configuration options to meet your project's specific needs. Here are some of the available configuration options:&lt;/p&gt;

&lt;p&gt;&lt;code&gt;quarkus.datasource.devservices.enabled&lt;/code&gt;: Allows you to explicitly enable or disable Dev Services.&lt;br&gt;
&lt;code&gt;quarkus.datasource.devservices.image-name&lt;/code&gt;: Sets the name of the container image to be used.&lt;br&gt;
&lt;code&gt;quarkus.datasource.devservices.container-env&lt;/code&gt;: Allows you to set environment variables to be passed to the container.&lt;br&gt;
&lt;code&gt;quarkus.datasource.devservices.container-properties&lt;/code&gt;: Allows you to set specific database properties for additional container configuration.&lt;br&gt;
&lt;code&gt;quarkus.datasource.devservices.port&lt;/code&gt;: Defines an optional fixed port for the Dev Service instead of a random port.&lt;br&gt;
&lt;code&gt;quarkus.datasource.devservices.init-script-path&lt;/code&gt;: Specifies a path to an SQL script to be loaded from the classpath and applied to the Dev Service database.&lt;/p&gt;

&lt;p&gt;These configurations can be adjusted according to your project's needs, providing flexibility in using Quarkus Dev Services.&lt;/p&gt;

&lt;p&gt;In summary, Quarkus Dev Services significantly simplifies the process of configuring and managing databases for Java developers. With minimal setup, you can start developing and testing your applications quickly and efficiently, saving time and effort. It's a valuable tool for enhancing productivity and accelerating Java application development.&lt;/p&gt;

</description>
      <category>quarkus</category>
      <category>java</category>
      <category>postgres</category>
      <category>opensource</category>
    </item>
  </channel>
</rss>
