<?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>DEV Community: Joaquinriosheredia</title>
    <description>The latest articles on DEV Community by Joaquinriosheredia (@joaquinriosheredia).</description>
    <link>https://dev.to/joaquinriosheredia</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%2F3983458%2Fc0eaeefa-e449-432f-9ff2-60154dfc3994.jpeg</url>
      <title>DEV Community: Joaquinriosheredia</title>
      <link>https://dev.to/joaquinriosheredia</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/joaquinriosheredia"/>
    <language>en</language>
    <item>
      <title>From Warnings to Evidence: Reproducing Java Runtime Failures with Testcontainers</title>
      <dc:creator>Joaquinriosheredia</dc:creator>
      <pubDate>Sun, 14 Jun 2026 11:13:54 +0000</pubDate>
      <link>https://dev.to/joaquinriosheredia/from-warnings-to-evidence-reproducing-java-runtime-failures-with-testcontainers-4g5i</link>
      <guid>https://dev.to/joaquinriosheredia/from-warnings-to-evidence-reproducing-java-runtime-failures-with-testcontainers-4g5i</guid>
      <description>&lt;p&gt;Last year I noticed something frustrating:&lt;/p&gt;

&lt;p&gt;The more advanced the warning, the more likely developers were to ignore it.&lt;/p&gt;

&lt;p&gt;Not because they were careless. Because the warning stopped at "this is dangerous" and never showed why.&lt;/p&gt;

&lt;p&gt;So I tried to fix that.&lt;/p&gt;

&lt;p&gt;The Idea: Detect → Explain → Verify&lt;/p&gt;

&lt;p&gt;Most static analyzers stop at detection. They tell you what is wrong.&lt;/p&gt;

&lt;p&gt;I wanted to build something that shows why it matters — reproducibly, on any machine, in under a minute:&lt;/p&gt;

&lt;p&gt;bashjava-vibe-guard .&lt;/p&gt;

&lt;p&gt;❌ VIBE-001 detected&lt;br&gt;
Evidence available: Java Production Lab #04&lt;br&gt;
Verify locally: java-vibe-guard --verify VIBE-001&lt;/p&gt;

&lt;p&gt;bashjava-vibe-guard --verify VIBE-001&lt;/p&gt;

&lt;p&gt;Environment Check&lt;br&gt;
✓ Docker 29.x&lt;br&gt;
✓ Java 21&lt;br&gt;
✓ Memory OK&lt;/p&gt;

&lt;p&gt;VIBE-001 Verification&lt;/p&gt;

&lt;p&gt;Observed:&lt;br&gt;
✓ Connection pool fully utilized (utilization: 100%)&lt;br&gt;
✓ Requests blocked waiting for connections (waiting: 15)&lt;br&gt;
✓ Latency amplification under concurrency (p95: 1540ms)&lt;/p&gt;

&lt;p&gt;Matches behavior documented in:&lt;br&gt;
Java Production Lab #04&lt;/p&gt;

&lt;p&gt;The verifier turns a warning into evidence.&lt;/p&gt;

&lt;p&gt;The Anti-Pattern: VIBE-001&lt;/p&gt;

&lt;p&gt;java@Transactional&lt;br&gt;
public void createOrder() {&lt;br&gt;
    repository.save(new Order());&lt;/p&gt;
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;CompletableFuture
    .supplyAsync(() -&amp;gt; {
        Thread.sleep(500); // simulating external IO
        return "OK";
    })
    .join(); // DB connection still held here
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;
&lt;p&gt;}&lt;/p&gt;

&lt;p&gt;This code compiles. Unit tests pass. In development with one or two concurrent users, nothing breaks.&lt;/p&gt;

&lt;p&gt;The problem: @Transactional acquires a HikariCP connection at the start of the method and holds it until the method returns. While join() blocks the thread waiting for async work, that connection sits idle — unavailable to other requests.&lt;/p&gt;

&lt;p&gt;With a pool of 5 connections and 20 concurrent users, requests queue up in batches. Latency compounds with each batch. The connection pool becomes the bottleneck.&lt;/p&gt;

&lt;p&gt;The Evidence: Lab #04&lt;/p&gt;

&lt;p&gt;Before building the verifier, I ran this pattern under load using Testcontainers in Java Production Lab #04:&lt;/p&gt;

&lt;p&gt;Min latency: 510ms (first batch, pool available)&lt;br&gt;
Max latency: 2025ms (fourth batch, pool exhausted)&lt;br&gt;
Spread: 1515ms&lt;/p&gt;

&lt;p&gt;What mattered wasn't the exact numbers. What mattered was that the shape of the failure was reproducible.&lt;/p&gt;

&lt;p&gt;That spread is the signature of connection pool contention — not hardware variance, not network noise. The pool exhausting and recovering in predictable cycles.&lt;/p&gt;

&lt;p&gt;Building the Verifier: Decisions That Matter&lt;/p&gt;

&lt;p&gt;Why Thread.sleep(500) and not an HTTP mock&lt;/p&gt;

&lt;p&gt;I wanted to simulate blocking IO without introducing unrelated variables — DNS resolution, network latency, connection timeouts. All of those would obscure the phenomenon I was trying to demonstrate.&lt;/p&gt;

&lt;p&gt;Thread.sleep(500) isolates what matters: the thread is blocked, the connection is held, the pool drains. One variable, one cause.&lt;/p&gt;

&lt;p&gt;Why observable phenomena instead of exact metrics&lt;/p&gt;

&lt;p&gt;Early versions checked for specific numbers: p95 &amp;gt; 2000ms. Brittle. Different machines, different CI runners — the numbers shifted.&lt;/p&gt;

&lt;p&gt;The stable version checks for phenomena:&lt;/p&gt;

&lt;p&gt;maxLatency &amp;gt; minLatency * 2&lt;br&gt;
spread &amp;gt; 800ms&lt;/p&gt;

&lt;p&gt;The verifier is designed to confirm the phenomenon, not benchmark performance. The threshold is generous enough to survive hardware variation while being strict enough to be meaningful.&lt;/p&gt;

&lt;p&gt;Making the test invisible to normal builds&lt;/p&gt;

&lt;p&gt;java@EnabledIfSystemProperty(named = "vibe.verify", matches = "true")&lt;br&gt;
class Vibe001VerificationTest { ... }&lt;/p&gt;

&lt;p&gt;Running mvn test never triggers this. The Node.js verifier activates it explicitly. The verification layer stays completely separate from the normal development cycle.&lt;/p&gt;

&lt;p&gt;Unexpected Findings&lt;/p&gt;

&lt;p&gt;Testcontainers and Docker Engine compatibility&lt;/p&gt;

&lt;p&gt;While debugging compatibility issues with Docker Engine 29.x, I found that configuring api.version=1.44 in Maven Surefire resolved connection failures in my setup:&lt;/p&gt;

&lt;p&gt;xml&lt;br&gt;
  1.44&lt;br&gt;
&lt;/p&gt;

&lt;p&gt;If you're running Testcontainers 1.20.x with a recent Docker Engine and hitting unexplained connection errors, this is worth checking.&lt;/p&gt;

&lt;p&gt;A note on CI hardening&lt;/p&gt;

&lt;p&gt;The verifier installs testcontainers-doctor as a CI dependency. Given recent supply chain incidents in the npm ecosystem, I pinned the version and blocked install scripts:&lt;/p&gt;

&lt;p&gt;yamlrun: npm install -g --ignore-scripts &lt;a href="mailto:testcontainers-doctor@1.0.0"&gt;testcontainers-doctor@1.0.0&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Small habit. Worth keeping.&lt;/p&gt;

&lt;p&gt;Results&lt;/p&gt;

&lt;p&gt;EnvironmentOutcomeLocal✅ p95: 1521ms · pool: 100% · waiting: 15CI — mvn test✅ spread &amp;gt; 800ms confirmedCI — CLI✅ exit code 0Clean machine (fresh clone)✅ p95: 1540ms · pool: 100% · waiting: 15&lt;/p&gt;

&lt;p&gt;The numbers are consistent enough across environments that the phenomenon is clearly portable, not hardware-dependent.&lt;/p&gt;

&lt;p&gt;The Interesting Part&lt;/p&gt;

&lt;p&gt;Static analysis tells you where to look.&lt;br&gt;
Evidence tells you what happens next.&lt;br&gt;
The gap between those two things is where many production incidents hide.&lt;/p&gt;

&lt;p&gt;Developers trust evidence more than warnings. A warning says "this might fail." Evidence says "here is what happens when it does."&lt;/p&gt;

&lt;p&gt;And reproducible evidence — the kind you can run on your own machine, in a controlled experiment — is something our tooling still provides surprisingly little of.&lt;/p&gt;

&lt;p&gt;Repo: &lt;a href="https://github.com/Joaquinriosheredia/java-vibe-guard" rel="noopener noreferrer"&gt;https://github.com/Joaquinriosheredia/java-vibe-guard&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;testcontainers-doctor: &lt;a href="https://www.npmjs.com/package/testcontainers-doctor" rel="noopener noreferrer"&gt;https://www.npmjs.com/package/testcontainers-doctor&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Java Production Labs: &lt;a href="https://github.com/Joaquinriosheredia/Java-Production-Labs" rel="noopener noreferrer"&gt;https://github.com/Joaquinriosheredia/Java-Production-Labs&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Tags: #java #testing #docker #opensource #security&lt;/p&gt;

</description>
      <category>java</category>
      <category>testing</category>
      <category>docker</category>
      <category>opensource</category>
    </item>
  </channel>
</rss>
