Skip to content

A lightweight, zero-maintenance Java library that wraps your existing PostgreSQL JDBC connection to automatically retry transient failures commonly encountered when using CockroachDB.

License

Notifications You must be signed in to change notification settings

viragtripathi/cockroachdb-jdbc-wrapper

Repository files navigation

Build GitHub release License

CockroachDB JDBC Wrapper

A lightweight, zero-maintenance Java library that wraps your existing PostgreSQL JDBC connection to automatically retry transient failures commonly encountered when using CockroachDB. These include:


🎯 Purpose

CockroachDB provides strong consistency and serializable isolation, which can lead to expected 40001 transaction retry errors. Instead of pushing that complexity to every application developer or service maintainer, this library provides a simple, non-intrusive solution that:

  • Automatically retries transactional errors internally
  • Works transparently with your existing JDBC logic
  • Adds no proxies, reflection, bytecode hacks, or driver replacements
  • Includes integration-tested retry logic with CockroachDB
  • Lets you opt-in to optional wrapper types if needed

🧰 Features

  • RetryableExecutor – simple utility to retry logic with execute() and executeVoid()
  • Optional RetryableDataSource and RetryableConnection for automatic retry of commit() and rollback()
  • Built-in handling of well-known CockroachDB/SQL state codes
  • Supports Resilience4j backoff and retry configuration
  • Zero-maintenance: no proxy servers, agents, or instrumentation

🚀 Quick Start

1. Add Dependency

<dependency>
  <groupId>com.cockroachdb</groupId>
  <artifactId>cockroachdb-jdbc-wrapper</artifactId>
  <version>0.1.0</version>
</dependency>

If using the slim JAR, include dependencies manually:

<dependency>
  <groupId>io.github.resilience4j</groupId>
  <artifactId>resilience4j-core</artifactId>
</dependency>
<dependency>
  <groupId>io.github.resilience4j</groupId>
  <artifactId>resilience4j-retry</artifactId>
</dependency>
<dependency>
  <groupId>org.postgresql</groupId>
  <artifactId>postgresql</artifactId>
</dependency>

💡 Download Options

File Description
cockroachdb-jdbc-wrapper-0.1.0.jar Slim JAR (no deps, requires Resilience4j + JDBC)
cockroachdb-jdbc-wrapper-0.1.0-all.jar Uber JAR with Resilience4j shaded

✅ Usage Examples

✅ Recommended (Minimal) – Use RetryableExecutor

RetryableExecutor executor = new RetryableExecutor();

executor.executeVoid(() -> {
    try (Connection conn = dataSource.getConnection()) {
        conn.setAutoCommit(false);
        // ... your DB ops
        conn.commit();
    }
});

This keeps your code unchanged while centralizing retry logic.


🧩 Optional: Wrap Your DataSource or Connection

If you want automatic retries for commit() / rollback() without calling the executor explicitly:

PGSimpleDataSource pgds = new PGSimpleDataSource();
pgds.setUrl("jdbc:postgresql://localhost:26257/defaultdb?sslmode=disable");
pgds.setUser("root");

DataSource retryable = new RetryableDataSource(pgds);
Connection conn = retryable.getConnection();  // wraps with retry logic for commit/rollback

✅ These wrappers are safe, pure Java delegations — they don’t override driver behavior, proxy the JDBC layer, or touch internal state.


🔁 Retry of Reads

int userCount = executor.execute(() -> {
    try (PreparedStatement ps = conn.prepareStatement("SELECT COUNT(*) FROM users");
         ResultSet rs = ps.executeQuery()) {
        rs.next();
        return rs.getInt(1);
    } catch (SQLException e) {
        throw new RuntimeException(e);
    }
});

🔧 Custom Retry Configuration

RetryConfig config = RetryConfig.custom()
    .maxAttempts(7)
    .waitDuration(Duration.ofMillis(250))
    .retryOnException(RetryableExecutor::isRetryable)
    .build();

RetryableExecutor executor = new RetryableExecutor(config);

🌀 Exponential Backoff

.intervalFunction(IntervalFunction.ofExponentialBackoff())

🔁 Retry Behavior

Retries are automatically triggered for:

  • 40001: Serialization failures
  • Any 08XXX: Connection issues
  • 57P01: Admin shutdown

Backoff is managed via Resilience4j and is fully customizable.


🧪 Integration Testing with CockroachDB

version: '3.8'
services:
  cockroach:
    image: cockroachdb/cockroach:latest
    command: start-single-node --insecure
    ports:
      - "26257:26257"
      - "8080:8080"
docker-compose up -d
./mvnw clean test

🧪 Sample Integration Demo

Looking for a complete working example?

👉 Check out the cockroachdb-jdbc-wrapper-demo repository.

It shows how to:

  • Connect to CockroachDB using the JDBC wrapper
  • Use RetryableExecutor for clean, retryable read/write logic
  • Simulate 40001 errors for live retry demos
  • Run everything locally using Docker and Maven

Great for onboarding, testing, and CI!


🛠️ Build

This project includes the Maven Wrapper (mvnw) so you don't need to install Maven separately.

🔨 Build the Project

./mvnw clean package

This produces:

  • target/cockroachdb-jdbc-wrapper-0.1.0.jar — Slim JAR
  • target/cockroachdb-jdbc-wrapper-0.1.0-all.jar — Uber JAR with Resilience4j included

🔧 Prerequisites

  • Java 21+ (JDK) to build the project
  • Java 17 or higher to run the JARs
  • Maven 3.9+ (optional — ./mvnw is included)
  • Docker (for optional demo environment)

Note: While the JAR is compatible with Java 17+, building from source requires JDK 21 due to Maven compiler target settings.

About

A lightweight, zero-maintenance Java library that wraps your existing PostgreSQL JDBC connection to automatically retry transient failures commonly encountered when using CockroachDB.

Topics

Resources

License

Stars

Watchers

Forks

Packages

No packages published

Languages