code: @Override
      public Future<?> runBatchAsync(Batch<T> batch, AfterExecute<T> afterExecute) throws FullQueueException {
          /* 
           * Since ThreadPoolExecutor throws RejectedExecutionException when its queue is full,
           * we have to backoff and retry if execute() throws RejectedExecutionHandler.
           *
           * This will cause all other threads writing to this cube to block. This is the desired
           * behavior since we want to stop accepting new writes past a certain point if we can't
           * send them to the database.
           */
          try {
              // Submit this batch
              synchronized (batchesInFlight) {
                  batchesInFlight.add(batch);
              }
              return flushExecutor.submit(new FlushWorkerRunnable(batch, afterExecute));
          } catch (RejectedExecutionException ree) {
              throw new FullQueueException();
          }
      }
docs: Hands off the given batch to the flush executor to be sent to the database soon. Doesn't
  throw IOException, since batches are just asynchronously submitted for execution, but
  will throw AsyncException if some previous batch had a RuntimeException.
  
  @return a Future that the caller can use to detect when the database IO is done. The returned
  future will never have an ExecutionException.