Java 21+ Spring Boot 4.0+ Quarkus 3.12+ Dropwizard 4.0+ Jakarta EE 10 MIT License

Distributed Idempotency Engine for Modern Java

Guaranteed exactly-once execution across microservices. Prevent duplicate side-effects, acquire concurrent in-flight locks, detect payload tampering, and replay byte-perfect HTTP responses based on the IETF Idempotency-Key specification.

🚀 Get Started 📂 View GitHub Source
AvoOnce Architecture Diagram

Built for Production Microservices

Designed with pure Java SPI, high-throughput caching, and multi-framework support.

🎯

Selective Endpoint Protection

Explicit, annotation-driven protection using @Idempotent. Unannotated health checks, metrics, and read endpoints bypass filtering with zero performance cost.

⚡

Byte-Perfect HTTP Replay

Captures exact HTTP status code, response headers, and raw response body bytes. Replays cached responses without triggering controller logic or database queries.

🔒

In-Flight Concurrency Locks

Prevents race conditions when clients send parallel duplicate requests. In-flight requests holding the lock receive an instant 409 Conflict response.

🛡️

SHA-256 Payload Hash Validation

Computes cryptographic request hashes. Rejects requests trying to reuse an existing key with altered parameters with a 422 Unprocessable Entity.

🔄

Fault-Tolerant Retry Engine

Transient server errors (HTTP 5xx) automatically transition state to FAILED, releasing the key so clients can safely retry execution.

🔌

Pluggable Storage SPI

Switch seamlessly between single-node Caffeine in-memory, distributed JDBC (PostgreSQL, MySQL, H2, Oracle, MariaDB, SQL Server), and distributed Redis.

Integrate in Minutes

Choose your preferred framework baseline below.

1. Add Dependency (pom.xml)
<dependency>
    <groupId>io.github.ravocode</groupId>
    <artifactId>avoonce-spring-boot-starter</artifactId>
    <version>1.0.0</version>
</dependency>
<dependency>
    <groupId>io.github.ravocode</groupId>
    <artifactId>avoonce-caffeine</artifactId>
    <version>1.0.0</version>
</dependency>
2. Annotate Controller Endpoints
import io.github.ravocode.spring.annotation.Idempotent;
import org.springframework.web.bind.annotation.*;
import org.springframework.http.ResponseEntity;

@RestController
@RequestMapping("/api/payments")
public class PaymentController {

    @PostMapping
    @Idempotent // Protected by AvoOnce
    public ResponseEntity<PaymentResponse> createPayment(@RequestBody PaymentRequest req) {
        return ResponseEntity.status(201).body(paymentService.process(req));
    }
}
1. Add Dependency (pom.xml)
<dependency>
    <groupId>io.github.ravocode</groupId>
    <artifactId>avoonce-jaxrs</artifactId>
    <version>1.0.0</version>
</dependency>
<dependency>
    <groupId>io.github.ravocode</groupId>
    <artifactId>avoonce-caffeine</artifactId>
    <version>1.0.0</version>
</dependency>
2. CDI Filter Producer & Endpoint Protection
@ApplicationScoped
public class IdempotencyProducer {
    @Produces @Singleton
    public IdempotencyContainerFilter filter() {
        return new IdempotencyContainerFilter(new CaffeineIdempotencyRepository(new IdempotencyConfig()));
    }
}

@Path("/api/payments")
public class PaymentResource {
    @POST
    @Idempotent // Name-bound JAX-RS protection
    public Response createPayment(PaymentRequest req) {
        return Response.status(201).entity(paymentService.process(req)).build();
    }
}
1. Register in Dropwizard Application.run
@Override
public void run(MyConfiguration config, Environment environment) {
    IdempotencyRepository repository = new CaffeineIdempotencyRepository(new IdempotencyConfig());
    
    // Register AvoOnce JAX-RS Name-Bound Filter
    environment.jersey().register(new IdempotencyContainerFilter(repository));
}
2. Annotate Resource Methods
import io.github.ravocode.jaxrs.Idempotent;
import jakarta.ws.rs.*;

@Path("/api/orders")
public class OrderResource {

    @POST
    @Idempotent // Name-bound protection for Dropwizard
    public Response placeOrder(OrderRequest request) {
        return Response.ok(orderService.place(request)).build();
    }
}
Standard Jersey / RESTEasy Filter Registration
ResourceConfig resourceConfig = new ResourceConfig();

IdempotencyRepository repository = new CaffeineIdempotencyRepository(new IdempotencyConfig());
resourceConfig.register(new IdempotencyContainerFilter(repository));

resourceConfig.register(PaymentResource.class);

Strict State Machine & IETF Standard

Clean separation between framework adapters, state machine, and pluggable storage engines.

AvoOnce Architecture Diagram
1

Key Extraction & Inspection

The @Idempotent filter intercepts the request, extracts Idempotency-Key header, and computes a SHA-256 body hash.

2

Payload Hash & Lock Check

If cached payload hash mismatches → returns 422 Unprocessable Entity. If key is currently IN_PROGRESS → returns 409 Conflict.

3

Execution & Response Caching

If lock acquired, controller executes. Response status, headers, and body bytes are stored as COMPLETED for instant replay.

4

Fault-Tolerant Retry

Server 5xx errors transition record to FAILED, allowing the client to safely retry the request with the same key.

Production-Ready Storage Backends

Pick the storage engine that matches your infrastructure topology.

☕ Caffeine (In-Memory)

Ultra-fast, zero-dependency in-memory store. Ideal for single-node applications or local testing with automated sliding-window eviction.

🗄️ JDBC (Relational DB)

Multi-dialect support for PostgreSQL, MySQL, H2, Oracle, MariaDB, and SQL Server. Features automatic table initialization (auto-ddl) and scheduled background cleanup.

⚡ Redis (Distributed Cache)

High-throughput distributed store leveraging Redis native TTL expiration and zero-dependency binary record serialization for maximum performance.