检测Oracle数据库瞬态故障并减少多个Runnable的重试

时间:2015-08-30 15:57:11

标签: java multithreading oracle jdbc exception-handling

我有JobRequest个对象的集合,这些对象包含在Worker个对象中:

public class Worker implements Runnable {
    private final ProcExecutor executor;
    private final JobRequest request;

    public Worker(ProcExecutor executor, JobRequest request) {
        this.executor = executor;
        this.request = request;
    }

    @Override
    public void run() {
        // this might throw an SQLException
        executor.execute(request);
    }
}

这些是针对具有8个核心线程和无限制任务队列的ThreadPoolExecutor执行的。

ProcExecutor打开OracleConnection,从OracleConnectionJobRequest创建CallableStatement,执行CallableStatement,然后关闭所有内容。创建连接,创建语句和执行语句都可以抛出SQLExceptions

我遇到的问题是我希望Worker重试作业(使用ExponentialBackoffPolicy中的Spring-Retry,初始时间为500毫秒,最终时间为30,000 ms和无限次重试 - 如果异常是暂时的,用户可以干预并取消重试循环)如果异常是暂时的,则记录异常并在异常是致命的情况下退出Worker。目前我正在使用pingDatabase来测试瞬态故障:

public class DatabasePingException extends SQLException {
    public DatabasePingException(SQLException cause) {
        super("Ping Exception", cause);
    }
}

public class ProcExecutor {
    public void execute(JobRequest request) throws SQLException {
        try(OracleConnection connection = // create connection) {
            try {
                if (oracleConnection.pingDatabase() != OracleConnection.DATABASE_OK) {
                    throw new SQLException("Invalid database connection");
                }
            } catch(SQLException e) {
                throw new DatabasePingException(e);
            }
            // create and execute CallableStatement
        }
    }
}

Worker然后在DatabasePingException上重试,否则会记录异常并退出普通SQLException

(至少)两个问题:

  1. 有没有更好的方法来区分瞬态和非瞬态故障?我意识到SQLExceptiontransientnon-transient个错误的子类,但我不清楚我应该如何对待SQLRecoverableException这样的子类,例如在固定的重试周期内重试固定次数,或者将其视为非暂时性故障,或者甚至是否需要重试SQLWarning

  2. 如果所有Workers都遇到瞬态故障,那么理想情况下我想暂停其中一个,直到问题清除为止。我提出的唯一解决方案涉及使用共享Worker之类的内容打破Semaphore封装,或者使用ThreadPoolExecutor重量级内容,例如调用shutDownNow()并重新启动所有已被取消或从未执行的Workers。如果我使用指数退避,即使有8个线程,我怀疑所有这些都是过度的,这只会是每个线程在退避达到最大值时每30秒对数据库执行一次ping操作,但是如果有一个简单的解决方案那么我应该使用它。

0 个答案:

没有答案