惯性聚合 高效追踪和阅读你感兴趣的博客、新闻、科技资讯
阅读原文 在惯性聚合中打开

推荐订阅源

L
LangChain Blog
Recent Announcements
Recent Announcements
GbyAI
GbyAI
H
Hackread – Cybersecurity News, Data Breaches, AI and More
Microsoft Azure Blog
Microsoft Azure Blog
N
Netflix TechBlog - Medium
人人都是产品经理
人人都是产品经理
MongoDB | Blog
MongoDB | Blog
D
DataBreaches.Net
freeCodeCamp Programming Tutorials: Python, JavaScript, Git & More
WordPress大学
WordPress大学
U
Unit 42
腾讯CDC
D
Docker
The GitHub Blog
The GitHub Blog
阮一峰的网络日志
阮一峰的网络日志
Vercel News
Vercel News
I
InfoQ
Jina AI
Jina AI
爱范儿
爱范儿
宝玉的分享
宝玉的分享
博客园 - Franky
G
Google Developers Blog
P
Proofpoint News Feed

DEV Community

Authentication Security Deep Dive: From Brute Force to Salted Hashing (With Java Examples) Why AI Systems Don’t Fail — They Drift Spilling beans for how i learn for exam😁"Reinforcement Learning Cheat Sheet" I Replaced Chrome with Safari for AI Browser Automation. Here's What Broke (and What Finally Worked) How Python Borrows Other People's Work The $40 Architecture: Processing 1 Billion API Requests with 99.99% Uptime Vibe Coding: A Workflow Guide (From Zero to SaaS) Most webhook security guides protect the wrong side. The scary part is delivery. Headless CMS for TanStack Start: Build a Blog with Cosmic EU Age Verification App "Hacked in 2 Minutes" — What Actually Happened Comfy Cloud’s delete function does not actually remove files Running AI Models on GPU Cloud Servers: A Beginner Guide Event-driven media intelligence with AWS Step Functions and Bedrock I scored 500 AI prompts across 8 quality dimensions — here's what broke How to Call Google Gemini API from Next.js (Free Tier, No Backend Needed) The Portal Protocol: Reclaiming Human Connection in the Age of AI How to Fix Your Team's Scattered Knowledge Problem With a Self-Hosted Forum Intro to tc Cloud Functors: A Graph-First Mental Model for the Modern Cloud Designing Multi-Tenant Backends With Both Ownership and Team Access I Built a Neumorphic CSS Library with 77+ Components — Here's What I Learned PostgreSQL Performance Optimization: Why Connection Pooling Is Critical at Scale Cómo construí un SaaS multi-rubro para gestionar expensas en Argentina con FastAPI + Vue 3 🚀 I Built an Ethical Hacking Scanner Tool – Open Source Project I Replaced /usage and /context in Claude Code With a Single Statusline A Pythonic Way to Handle Emails (IMAP/SMTP) with Auto-Discovery and AI-Ready Design I Collected 8.9 Million Polymarket Price Points — Here's What I Found About How Markets Really Move EcoTrack AI — Carbon Footprint Tracker & Dashboard Everyone's Using AI. No One Agrees How. 5 self-hosted ebook managers worth trying in 2026 Building Your First AI Agent with LangChain: From Chatbot to Autonomous Assistant
I was tired of pulling in 500KB just to retry a HTTP call...
Amine Canina · 2026-04-24 · via DEV Community

Your microservice calls an external API. It fails.

You add Resilience4j. Now you have 10 transitive dependencies, a 500KB JAR, 3 config classes, and a @Bean method just to say "try 3 times, wait 1 second".

I hit that wall one too many times. So I built RetryKit — a zero-dependency Java 17 retry & circuit breaker library. No Spring required. No transitive pulls. JAR under 50KB.

<dependency>
  <groupId>io.github.caninaam</groupId>
  <artifactId>retrykit</artifactId>
  <version>1.0.1</version>
</dependency>

Enter fullscreen mode Exit fullscreen mode

Fixed delay retry with fallback — the most common case:

String result = RetryKit.<String>retry()
    .maxAttempts(3)
    .waitDuration(Duration.ofSeconds(1))
    .fallback(ctx -> "default")
    .call(() -> myService.call());

Enter fullscreen mode Exit fullscreen mode

Exponential backoff with jitter — for avoiding thundering herd under load:

RetryKit.<String>retry()
    .maxAttempts(4)
    .exponentialBackoff(Duration.ofMillis(500), 2.0, Duration.ofSeconds(10))
    .withJitter(0.2)
    .call(() -> myService.call());

Enter fullscreen mode Exit fullscreen mode

Retry only on specific exceptions — don't retry a 400 Bad Request:

RetryKit.<String>retry()
    .maxAttempts(3)
    .retryOn(IOException.class, HttpServerErrorException.class)
    .call(() -> myService.call());

Enter fullscreen mode Exit fullscreen mode

Most retry libraries make you choose: retry OR circuit breaker OR timeout. In real production systems you need all three, composed in the right order. RetryKit lets you express that as a single string:

RetryKit.<String>retry()
    .pipeline("TIMEOUT(3s) > RETRY(3) > CB(50%)")
    .call(() -> myService.call());

Enter fullscreen mode Exit fullscreen mode

Read it left to right — outermost wrapper first. TIMEOUT(3s) — each attempt must complete within 3 seconds. RETRY(3) — retry up to 3 times on failure. CB(50%) — open the circuit if 50%+ of calls fail.

The full DSL syntax:

TIMEOUT(5s)
TIMEOUT(500ms)

RETRY(3)
RETRY(maxAttempts:5, waitDuration:500ms)
RETRY(maxAttempts:4, waitDuration:1s, backoff:2.0, maxWait:10s, jitter:0.2)

CB(50%)
CB(failureRate:50%, minCalls:5, wait:1m, halfOpen:2, timeout:2s)

Enter fullscreen mode Exit fullscreen mode

A realistic production pipeline in one line:

.pipeline("TIMEOUT(2s) > RETRY(maxAttempts:4, waitDuration:500ms, backoff:2.0, jitter:0.2) > CB(failureRate:60%, minCalls:10, wait:30s)")

Enter fullscreen mode Exit fullscreen mode

This used to take 40+ lines of config. Now it's one.

For teams that want to tune retry behavior without redeploying:

production:
  mode: RETRY_FIRST
  maxAttempts: 3
  waitDuration: PT1S
  circuitBreaker:
    failureRateThreshold: 50
    minimumNumberOfCalls: 5
    waitDurationInOpenState: PT1M

aggressive:
  mode: PIPELINE
  pipeline: "TIMEOUT(2s) > RETRY(3) > CB(50%)"

Enter fullscreen mode Exit fullscreen mode

Load it in your app:

RetryKit.<String>fromYaml("/etc/myapp/retrykit.yaml")
    .profile("production")
    .<String>as()
    .withHotReload(Duration.ofSeconds(10))
    .fallback(ctx -> "fallback")
    .build();

Enter fullscreen mode Exit fullscreen mode

Change maxAttempts or failureRateThreshold in the file — the running service picks it up in 10 seconds. No restart, no redeploy.

Two workflow modes depending on your use case. RETRY_FIRST — retry exhausts attempts, CB accumulates failures across retries. CB_FIRST — circuit breaker is checked before any retry attempt, if OPEN fail immediately — no retries wasted. Use CB_FIRST when the downstream service is known to be down.

Two distinct exceptions so you always know what happened:

try {
    kit.call(() -> myService.call());
} catch (RetryException e) {
    // service WAS called — all e.attempts() failed
} catch (CircuitBreakerOpenException e) {
    // service was NOT called — CB is open, we already know it's down
}

Enter fullscreen mode Exit fullscreen mode

How does RetryKit compare?

RetryKit Resilience4j
Dependencies 0 ~10
JAR size < 50 KB ~500 KB
Pipeline DSL yes no
YAML hot reload yes no
Java version 17+ 8+
Setup time 5 min 30 min+

Most enterprise retry libraries are built for every possible use case — you pay that cost even when you need none of it. RetryKit does one thing well.

GitHub: https://github.com/caninaam/retry-kit
Maven Central: https://central.sonatype.com/artifact/io.github.caninaam/retrykit

Next post — how the circuit breaker state machine works under the hood, and why compareAndSet matters in concurrent systems.