Question

The situation is, I have to make sure only one RecoveryThread gets created when I try to getConnection and if it fails on getConnection on PrimaryData Source fails., the code I have is:

public Connection getConnection() throws SQLException {
        if (isFailedOver()) {
            try {
                return failoverDataSource.getConnection();
            } catch (SQLException e) {
                throwBigError();
            }
        }
        Connection connection = null;
        try {
            connection = dataSource.getConnection();
            return connection;
        }
        catch (SQLException unexpected) {
            return requestFailover();
        }
    }

    private Connection requestFailover() throws SQLException {
        this.dbFailoverMutex.requestFailover();
        DBFailoverRecoveryService recoveryService = new DBFailoverRecoveryService(this.dbFailoverMutex,this.dataSource);
        Thread recoveryServiceThread = new Thread(recoveryService, "DBFailover Recovery Service");
        recoveryServiceThread.start();
        try {
            return failoverDataSource.getConnection();
        } catch (SQLException e) {
            throwBigError();
        }
        return null;
    }

If there are two different threads trying to getConnection, this might endup calling requestFailover() method twice, and when it gets call twice this will end up in creating two recoveryService threads, what can I do to make sure that never happens?

thanks in advance for your help.

Was it helpful?

Solution

what can I do to make sure that never happens?

One thing to consider is to switch to using an Executors.newSingleThreadExecutor() which will only fork one thread to do the running. Then you can submit as many tasks as you want without having to worry about them overlapping.

private final ExecutorService threadPool =
      Executors.newSingleThreadExecutor(/* pass in ThreadFactory to set name */);
...
DBFailoverRecoveryService recoveryService =
       new DBFailoverRecoveryService(this.dbFailoverMutex, this.dataSource);
threadPool.submit(recoveryService);

As always with the ExecutorService, you need to call threadPool.shutdown() once you submit the last task to the pool otherwise it will hang your application. You could add a Datasource.destroy(); method to do this.

OTHER TIPS

You could add the "synchronized" modifier to your getConnection method, then add a boolean flag to indicate whether a failover was already requested, e.g.

public synchronized getConnection(){ throws SQLException
  if(alreadyRequestedFailover){
    return;
  }
  ....
  catch (SQLException unexpected) {
     alreadyRequestedFailover = true;
     return requestFailover();
  }
}

This will prevent two threads from simultaneously entering the getConnection() method and ensure that if a thread requests a failover it will update the alreadyRequestedFailover flag before allowing another thread into getConnection().

Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top