/**
  * Wait until all the results that are in the pipeline come back to the reply channel.
  *
  * @return true if successfully received a result, false if timed out
  */
 private boolean waitForResults() {
   int count = 0;
   int maxCount = maxWaitTimeouts;
   while (localState.getExpecting() > 0 && count++ < maxCount) {
     long expecting = localState.getExpecting();
     getNextResult();
     if (expecting == localState.getExpecting()) {
       try {
         Thread.sleep(100);
       } catch (InterruptedException e) {
         throw new RuntimeException(e);
       }
     }
   }
   return count < maxCount;
 }
 @Override
 public ExitStatus afterStep(StepExecution stepExecution) {
   if (!(stepExecution.getStatus() == BatchStatus.COMPLETED)) {
     return ExitStatus.EXECUTING;
   }
   long expecting = localState.getExpecting();
   boolean timedOut;
   try {
     logger.debug("Waiting for results in step listener...");
     timedOut = !waitForResults();
     logger.debug("Finished waiting for results in step listener.");
   } catch (RuntimeException e) {
     logger.debug("Detected failure waiting for results in step listener.", e);
     stepExecution.setStatus(BatchStatus.FAILED);
     return ExitStatus.FAILED.addExitDescription(e.getClass().getName() + ": " + e.getMessage());
   }
   if (timedOut) {
     stepExecution.setStatus(BatchStatus.FAILED);
     throw new ItemStreamException("Timed out waiting for back log at end of step");
   }
   return ExitStatus.COMPLETED.addExitDescription("Waited for " + expecting + " results.");
 }
  public void write(List<? extends T> items) throws Exception {

    // Block until expecting <= throttle limit
    while (localState.getExpecting() > throttleLimit) {
      getNextResult();
    }

    if (!items.isEmpty()) {
      logger.debug("Dispatching chunk: " + items);
      ChunkRequest<T> request =
          new ChunkRequest<T>(items, localState.getJobId(), localState.createStepContribution());

      // Create & launch task
      ChunkTask<T> task = new ChunkTask<T>();
      task.setProcessor(chunkProcessor);
      GridTaskFuture<ChunkResponse> future =
          grid.<ChunkRequest<T>, ChunkResponse>execute(task, request);
      futures.add(future);

      localState.expected++;
    }
  }