How can I set a timer in Java to attempt a database connection for 2 minutes before throwing an exception?

I need to implement a Java timer that tries to connect to a database for up to 2 minutes. If the connection fails within that time, an exception should be thrown.

What is the best way to achieve this in Java?

A great way to implement a Java timer for your database connection is by using ScheduledExecutorService, which allows you to run tasks at fixed intervals while keeping track of elapsed time.

import java.sql.Connection;
import java.sql.DriverManager;
import java.sql.SQLException;
import java.util.concurrent.*;

public class DatabaseConnector {
    public static void main(String[] args) {
        ScheduledExecutorService scheduler = Executors.newScheduledThreadPool(1);
        long startTime = System.currentTimeMillis();
        
        Runnable task = () -> {
            try {
                Connection conn = DriverManager.getConnection("jdbc:mysql://localhost:3306/mydb", "user", "password");
                System.out.println("Connected successfully!");
                scheduler.shutdown();
            } catch (SQLException e) {
                if (System.currentTimeMillis() - startTime > 120_000) { // 2-minute limit
                    scheduler.shutdown();
                    throw new RuntimeException("Failed to connect within 2 minutes.", e);
                }
                System.out.println("Retrying...");
            }
        };

        scheduler.scheduleAtFixedRate(task, 0, 5, TimeUnit.SECONDS); // Retry every 5 seconds
    }
}

:white_check_mark: Why use this?

  • Precise timing using scheduled retries.
  • Non-blocking, allowing the program to continue running.
  • Exception thrown properly after 2 minutes.

:rotating_light: When to avoid?

If your database connection should block until success or timeout.

If you prefer a simple and blocking solution, a loop with Thread.sleep() can help.

import java.sql.Connection;
import java.sql.DriverManager;
import java.sql.SQLException;

public class DatabaseConnector {
    public static void main(String[] args) throws InterruptedException {
        long startTime = System.currentTimeMillis();
        while (System.currentTimeMillis() - startTime < 120_000) { // Try for 2 minutes
            try {
                Connection conn = DriverManager.getConnection("jdbc:mysql://localhost:3306/mydb", "user", "password");
                System.out.println("Connected successfully!");
                return;
            } catch (SQLException e) {
                System.out.println("Retrying in 5 seconds...");
                Thread.sleep(5000); // Wait before retrying
            }
        }
        throw new RuntimeException("Failed to connect within 2 minutes.");
    }
}

:white_check_mark: Why use this?

  • Very easy to implement with minimal dependencies.
  • Straightforward retry mechanism.

:rotating_light: When to avoid?

If you need a non-blocking or concurrent approach.

A more modern approach using CompletableFuture allows setting a timeout while attempting the database connection asynchronously.

import java.sql.Connection;
import java.sql.DriverManager;
import java.sql.SQLException;
import java.util.concurrent.*;

public class DatabaseConnector {
    public static void main(String[] args) {
        ExecutorService executor = Executors.newSingleThreadExecutor();

        CompletableFuture<Void> future = CompletableFuture.runAsync(() -> {
            while (true) {
                try {
                    Connection conn = DriverManager.getConnection("jdbc:mysql://localhost:3306/mydb", "user", "password");
                    System.out.println("Connected successfully!");
                    return;
                } catch (SQLException e) {
                    System.out.println("Retrying in 5 seconds...");
                    try {
                        Thread.sleep(5000);
                    } catch (InterruptedException ignored) {}
                }
            }
        }, executor);

        try {
            future.get(2, TimeUnit.MINUTES); // Timeout after 2 minutes
        } catch (TimeoutException e) {
            future.cancel(true);
            throw new RuntimeException("Failed to connect within 2 minutes.", e);
        } catch (Exception e) {
            throw new RuntimeException("Unexpected error occurred.", e);
        } finally {
            executor.shutdown();
        }
    }
}

:white_check_mark: Why use this?

  • Non-blocking execution.
  • Automatically stops after 2 minutes without needing manual checks.

:rotating_light: When to avoid?

  • If your application doesn’t use CompletableFuture yet and you prefer simpler solutions.