Asynchronous IO

Cassandra’s native binary protocol supports request pipelining. Essentially, this lets a single connection to be used for several simultaneous and independent request/response exchanges. Additionally, Ruby Driver doesn’t use any blocking apis internally and runs all requests in the background reactor thread.

Text Diagram

For consistency of API, all asynchronous methods end with _async (e.g. Session#execute_async) and return a Future object.

Methods like Session#prepare, Session#execute and Session#close are thin wrappers around Session#prepare_async, Session#execute_async and Session#close_async accordingly. These wrapper methods simply call their asynchronous counter part and block waiting for resulting future to be resolved.

A Cassandra::Future can be used to:

  • block application thread until execution has completed
  • register a listener to be notified when a result is available.

When describing different asynchronous method results, we will use a Cassandra::Future<Type> notation to signal the type of the result of the future. For example, Cassandra::Future<Cassandra::Result> is a future that returns an instance of Cassandra::Result when calling its #get method.

Example: getting a result

future = session.execute_async(statement)
result = future.get # will block and raise error or return result

Whenever a Future is resolved using its Cassandra::Future#get method, it will block until it has a value. Once a value is available, it will be returned. In case of an error, an exception will be raised.

Example: registering a listener

future = session.execute_async(statement)

# register success listener
future.on_success do |rows|
  rows.each do |row|
    puts "#{row["artist"]}: #{row["title"]} / #{row["album"]}"
  end
end