9

I'm trying to speed up our code by calling session.executeAsync() instead of session.execute() for DB writes.

We have use cases where the DB connection might be down, currently the previous execute() throws an exception when the connection is lost (no hosts reachable in the cluster). We can catch these exceptions and retry or save the data somewhere else etc...

With executeAsync(), it doesn't look like there's any way to fulfill this use case - the returned ResultSetFuture object needs to be accessed to check the result, which would defeat the purpose of using the executeAsync() in the first place...

Is there any way to add a listener (or something similar) anywhere for the executeAsync() call that will asynchronously notify some other code that a DB write has failed?

Is this pertinent? Datastax 1.0.2 Java 1.7.40

Erick Ramirez
  • 13,964
  • 1
  • 18
  • 23

2 Answers2

15

You could try something like this since the ResultSetFuture implements ListenableFuture from the Guava library:

    ResultSetFuture resultSetFuture = session.executeAsync("SELECT * FROM test.t;");
    Futures.addCallback(resultSetFuture, new FutureCallback<ResultSet>() {
        @Override
        public void onSuccess(@Nullable com.datastax.driver.core.ResultSet resultSet) {
            // do nothing
        }

        @Override
        public void onFailure(Throwable throwable) {
            System.out.printf("Failed with: %s\n", throwable);
        }
    });

This approach will not block your application.

djatnieks
  • 734
  • 3
  • 11
1

You could pass a callback to the method to take action on exception. If you need the ResultSetFuture, you could try something like this:

interface ResultSetFutureHandler {
    void handle(ResultSetFuture rs);
}

public void catchException(ResultSetFutureHandler handler) {
    ResultSetFuture resultSet = null;
    try {
        resultSet = getSession().executeAsync(query);
        for (Row row : results.getUninterruptibly()) {
            // do something
        }
    } catch (RuntimeException e) {
        handler.handle(resultSet); // resultSet may or may not be null
    }
}

Then call it like this:

catchException(new ResultSetFutureHandler() {
    void handle(ResultSetFuture resultSet) {
        // do something with the ResultSetFuture
    }
});

If you need to know what the exception was, add an exception parameter too:

interface ResultSetFutureHandler {
    void handle(ResultSetFuture rs, RuntimeException e);
}
Bohemian
  • 412,405
  • 93
  • 575
  • 722
  • 2
    Hi! Thanks for the idea. But I think the getUninterruptibly() call is blocking until the query returns with results, so this seems like it would negate the benefits of using executeAsync()? I'm looking at how to use executeAsync() to "fire-and-forget" a query with some way to hook in some kind of async listener that will be called if there's an exception. – Phillip Atkinson Mar 12 '14 at 01:19
  • That's what this does. The "listener" is the `ResultSetFutureHandler` you pass in - it gets called when there's an exception just like you wanted. You could bundle it up differently to make it more formal or elegant, but the idea would be the same. – Bohemian Mar 12 '14 at 01:25
  • When there's an exception in your code example, haven't we already lost the advantages of executeAsync() since the code waits for the getUninterruptibly() call? This is how I see the example operating: ` // executeAsync() only throws IllegalStateException, which I believe doesn't indicate a network failure resultSet = getSession().executeAsync(query); // getUninterruptibly() blocks until the query is actually run and returns // from the javadoc: "Waits for the query to return and return its result." for (Row row : resultSet.getUninterruptibly()) { ` – Phillip Atkinson Mar 12 '14 at 08:04
  • cont'd Since getUniterruptibly() throws the looked-for NoHostAvailableException/QueryExecutionException yet also blocks until the query is run, I don't think calling that method helps me in my quest for async processing? – Phillip Atkinson Mar 12 '14 at 08:04
  • I was trying to avoid needing to thread anything, as by that point I might as well thread the entire DB call and simply use execute() instead of executeAsync(). Could be what I'm looking for just isn't possible :) – Phillip Atkinson Mar 13 '14 at 03:27
  • Ultimately, an asynchronous call requires a thread. I'm surprised the API doesn't allow you to provide a callback for when the query returns data. That would be my expectation - most asynchronous API's do that. – Bohemian Mar 13 '14 at 03:56