<?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: Bibek Maharjan</title>
    <description>The latest articles on DEV Community by Bibek Maharjan (@bibekmhj).</description>
    <link>https://dev.to/bibekmhj</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.us-east-2.amazonaws.com%2Fuploads%2Fuser%2Fprofile_image%2F4090292%2Fc4006f6a-e29d-4b9d-8b57-25a027094ebb.jpg</url>
      <title>DEV Community: Bibek Maharjan</title>
      <link>https://dev.to/bibekmhj</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/bibekmhj"/>
    <language>en</language>
    <item>
      <title>Preview the November 2026 AWS SDK for Java retry defaults on your own traffic</title>
      <dc:creator>Bibek Maharjan</dc:creator>
      <pubDate>Sun, 23 Aug 2026 01:50:10 +0000</pubDate>
      <link>https://dev.to/bibekmhj/preview-the-november-2026-aws-sdk-for-java-retry-defaults-on-your-own-traffic-2g4i</link>
      <guid>https://dev.to/bibekmhj/preview-the-november-2026-aws-sdk-for-java-retry-defaults-on-your-own-traffic-2g4i</guid>
      <description>&lt;p&gt;If you run a Java app that talks to AWS, there's a change coming on &lt;strong&gt;November 1, 2026&lt;/strong&gt; that will quietly alter how your services behave under partial failure — and unless you take deliberate action, you will not find out until your dashboards do.&lt;/p&gt;

&lt;p&gt;AWS is changing the &lt;strong&gt;default retry behavior&lt;/strong&gt; in every one of its SDKs (Java, Python, JS, Go, PHP, plus the CLI) as part of a &lt;a href="https://github.com/aws/aws-sdk-java-v2/issues/6987" rel="noopener noreferrer"&gt;cross-SDK announcement&lt;/a&gt;. The values that change are small on paper and significant in production:&lt;/p&gt;

&lt;h2&gt;
  
  
  What changes on Nov 1, 2026
&lt;/h2&gt;

&lt;p&gt;&lt;strong&gt;Max attempts (most services)&lt;/strong&gt; — from 4 to 3&lt;br&gt;
&lt;strong&gt;Max attempts (DynamoDB)&lt;/strong&gt; — from 9 to 4  ← the big one&lt;br&gt;
&lt;strong&gt;Base delay for transient errors&lt;/strong&gt; — from 100 ms to 50 ms&lt;br&gt;
&lt;strong&gt;Base delay for throttling&lt;/strong&gt; — from 500 ms to 1000 ms&lt;br&gt;
&lt;strong&gt;New retryable exceptions&lt;/strong&gt; — LimitExceededException and STS IdpCommunicationErrorException                 &lt;/p&gt;

&lt;p&gt;The most consequential row is the second one. DynamoDB has always had a per-service override that lets the SDK retry a call up to nine times before giving up. In November it will retry four times. If your write path relies on that longer tail to survive brief throttling bursts — many do, quietly — a real number of writes that succeed today will fail on Nov 1st.&lt;/p&gt;

&lt;p&gt;You can opt in early on AWS SDK for Java 2.44+ by setting &lt;em&gt;AWS_NEW_RETRIES_2026=true&lt;/em&gt;. But that's a binary switch, and the only way to know if it hurts is to flip it and watch. That's not a plan.&lt;/p&gt;
&lt;h2&gt;
  
  
  The gap
&lt;/h2&gt;

&lt;p&gt;The only question that matters is &lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;"what would the new defaults do to my traffic?"&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;The AWS announcement can't answer that; it doesn't know how often your DynamoDB &lt;em&gt;PutItem&lt;/em&gt; gets throttled at 3 AM, or which of your SQS consumers has a p95 that walks right up to the timeout.&lt;/p&gt;

&lt;p&gt;Your logs can't answer it either. The SDK's retry loop is largely invisible from the outside - you see either a successful result or a final failure, not the attempts in between.&lt;/p&gt;
&lt;h2&gt;
  
  
  What I built
&lt;/h2&gt;

&lt;p&gt;I published a small library called &lt;strong&gt;retrylens&lt;/strong&gt; (&lt;a href="https://central.sonatype.com/artifact/io.github.bibekmhj/retrylens" rel="noopener noreferrer"&gt;Maven Central&lt;/a&gt;, &lt;a href="https://github.com/bibekmhj/retrylens" rel="noopener noreferrer"&gt;GitHub&lt;/a&gt;) that does one thing: it attaches a single &lt;em&gt;ExecutionInterceptor&lt;/em&gt; to any AWS SDK v2 client, records every attempt into a bounded ring buffer, and then lets you &lt;strong&gt;simulate what the November 2026 defaults would have done to that same traffic.&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;The simulator is a pure function over the recorded outcomes. It never re-issues a request, never talks to AWS, and never needs credentials. It's arithmetic on data you already have — which is what makes it safe to run against a real production app.&lt;/p&gt;
&lt;h2&gt;
  
  
  The whole API in one screen
&lt;/h2&gt;


&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight java"&gt;&lt;code&gt;&lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="nn"&gt;io.github.bibekmhj.retrylens.RetryLens&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.github.bibekmhj.retrylens.RetryMode&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.github.bibekmhj.retrylens.RetryReport&lt;/span&gt;&lt;span class="o"&gt;;&lt;/span&gt;

&lt;span class="nc"&gt;RetryLens&lt;/span&gt; &lt;span class="n"&gt;lens&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nc"&gt;RetryLens&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="nc"&gt;DynamoDbClient&lt;/span&gt; &lt;span class="n"&gt;ddb&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nc"&gt;DynamoDbClient&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;builder&lt;/span&gt;&lt;span class="o"&gt;()&lt;/span&gt;
    &lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;overrideConfiguration&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;o&lt;/span&gt; &lt;span class="o"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;o&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;addExecutionInterceptor&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;lens&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;interceptor&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="c1"&gt;// … exercise the client on real traffic for a while …&lt;/span&gt;

&lt;span class="nc"&gt;RetryReport&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;lens&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;report&lt;/span&gt;&lt;span class="o"&gt;();&lt;/span&gt;
&lt;span class="nc"&gt;RetryReport&lt;/span&gt; &lt;span class="n"&gt;in2026&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="na"&gt;previewFor&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="nc"&gt;RetryMode&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;STANDARD_2026&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;now&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;toText&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;in2026&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;toText&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;now&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;diff&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;in2026&lt;/span&gt;&lt;span class="o"&gt;).&lt;/span&gt;&lt;span class="na"&gt;totalFailuresDelta&lt;/span&gt;&lt;span class="o"&gt;()&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="s"&gt;" extra failures under 2026 defaults"&lt;/span&gt;&lt;span class="o"&gt;);&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;


&lt;p&gt;That's the entire integration. There's no framework, no proxy, no wrapper — the SDK's own &lt;em&gt;ExecutionInterceptor&lt;/em&gt; SPI is doing all the work.&lt;/p&gt;
&lt;h2&gt;
  
  
  What comes out the other side
&lt;/h2&gt;

&lt;p&gt;A representative snapshot from a synthetic DynamoDB + S3 + SQS workload:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;retrylens report — observed (your current retry mode)
  calls=1428  attempts=1837  retries=409  throttled=118  failures=6

  operation                calls  attempts  retries  throttled  failures    p50    p95
  ------------------------------------------------------------------------------------
  DynamoDb.PutItem          310       498      188         12         2    31ms  410ms
      top errors: ProvisionedThroughputExceededException=12
  S3.GetObject              812       912      100          0         0     8ms   41ms
  Sqs.ReceiveMessage        201       253       52         83         3    21ms  2.10s
      top errors: RequestThrottled=83

retrylens report — projected under STANDARD_2026
  calls=1428  attempts=1614  retries=186  throttled=118  failures=27

Δ attempts:  -223  (mostly DynamoDB PutItem: 9-attempt cap → 4)
Δ failures:  +21  (DynamoDB PutItem exhausts retries sooner on sustained throttling)
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The two numbers on the last line are the ones you can actually take to a design review. &lt;strong&gt;21 extra failures per 1,428 calls&lt;/strong&gt; is a specific claim you can act on: raise DynamoDB write capacity, or set a per-operation retry override, or accept the drop as within budget. Without a number, you're guessing.&lt;/p&gt;

&lt;h2&gt;
  
  
  What retrylens deliberately does not do
&lt;/h2&gt;

&lt;p&gt;Honesty about the sharp edges:&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;It does not model the standard-mode retry quota&lt;/strong&gt;. In practice the SDK's standard mode uses a token bucket that can suppress retries under sustained failure; retrylens's numbers are therefore an upper bound on how much retrying the new mode would do. Real production will retry no more than what the simulator projects, sometimes less.&lt;br&gt;
&lt;strong&gt;It does not model live jitter&lt;/strong&gt;. Backoff wall-clock is reported as the expected value of full-jitter, not a specific outcome.&lt;br&gt;
&lt;strong&gt;It does not re-issue requests&lt;/strong&gt;. The simulator is arithmetic on recorded outcomes. If your traffic mix changes tomorrow, run it again on the new traffic.&lt;/p&gt;

&lt;h2&gt;
  
  
  Install
&lt;/h2&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight xml"&gt;&lt;code&gt;&lt;span class="nt"&gt;&amp;lt;dependency&amp;gt;&lt;/span&gt;
    &lt;span class="nt"&gt;&amp;lt;groupId&amp;gt;&lt;/span&gt;io.github.bibekmhj&lt;span class="nt"&gt;&amp;lt;/groupId&amp;gt;&lt;/span&gt;
    &lt;span class="nt"&gt;&amp;lt;artifactId&amp;gt;&lt;/span&gt;retrylens&lt;span class="nt"&gt;&amp;lt;/artifactId&amp;gt;&lt;/span&gt;
    &lt;span class="nt"&gt;&amp;lt;version&amp;gt;&lt;/span&gt;0.1.0&lt;span class="nt"&gt;&amp;lt;/version&amp;gt;&lt;/span&gt;
&lt;span class="nt"&gt;&amp;lt;/dependency&amp;gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Zero required runtime dependencies. AWS SDK is declared &lt;em&gt;provided&lt;/em&gt;, so you keep whichever version you already use (2.20+ recommended, retry values calibrated for 2.44+).&lt;/p&gt;

&lt;h2&gt;
  
  
  What to do this week
&lt;/h2&gt;

&lt;p&gt;Whether or not you use this specific library, do one of these:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Run your app under &lt;em&gt;AWS_NEW_RETRIES_2026=true&lt;/em&gt; in a staging environment for a week and diff your CloudWatch failure metrics against the previous week.&lt;/li&gt;
&lt;li&gt;Or, run retrylens against a canary of production traffic for 30 minutes and read the diff.&lt;/li&gt;
&lt;li&gt;Or, set &lt;em&gt;AWS_RETRY_MODE=legacy&lt;/em&gt; explicitly in your production environment right now, so that when Nov 1st arrives you have already opted out and can plan the migration on your own timeline.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;The one option you don't have is finding out on Nov 1st.&lt;/p&gt;

&lt;p&gt;If you try &lt;strong&gt;retrylens&lt;/strong&gt; and it either helps or breaks in an interesting way, I'd love to hear about it in the &lt;a href="https://github.com/bibekmhj/retrylens/issues" rel="noopener noreferrer"&gt;GitHub&lt;/a&gt; issues. The library is Apache 2.0, ~600 lines of Java, and reviewable in one PR.&lt;/p&gt;

</description>
      <category>java</category>
      <category>aws</category>
      <category>springboot</category>
      <category>opensource</category>
    </item>
  </channel>
</rss>
