protected void addAndStartConsumers(int delta) {
   synchronized (this.consumersMonitor) {
     if (this.consumers != null) {
       for (int i = 0; i < delta; i++) {
         BlockingQueueConsumer consumer = createBlockingQueueConsumer();
         this.consumers.put(consumer, true);
         AsyncMessageProcessingConsumer processor = new AsyncMessageProcessingConsumer(consumer);
         this.taskExecutor.execute(processor);
         try {
           FatalListenerStartupException startupException = processor.getStartupException();
           if (startupException != null) {
             this.consumers.remove(consumer);
             throw new AmqpIllegalStateException(
                 "Fatal exception on listener startup", startupException);
           }
         } catch (InterruptedException ie) {
           Thread.currentThread().interrupt();
         } catch (Exception e) {
           consumer.stop();
           logger.error("Error starting new consumer", e);
           consumers.remove(consumer);
         }
       }
     }
   }
 }
  @Override
  protected void doShutdown() {

    if (!this.isRunning()) {
      return;
    }

    try {
      synchronized (consumersMonitor) {
        if (this.consumers != null) {
          for (BlockingQueueConsumer consumer : this.consumers.keySet()) {
            consumer.setQuiesce(this.shutdownTimeout);
          }
        }
      }
      logger.info("Waiting for workers to finish.");
      boolean finished = cancellationLock.await(shutdownTimeout, TimeUnit.MILLISECONDS);
      if (finished) {
        logger.info("Successfully waited for workers to finish.");
      } else {
        logger.info("Workers not finished.  Forcing connections to close.");
      }
    } catch (InterruptedException e) {
      Thread.currentThread().interrupt();
      logger.warn("Interrupted waiting for workers.  Continuing with shutdown.");
    }

    synchronized (this.consumersMonitor) {
      this.consumers = null;
    }
  }
  /**
   * Specify the number of concurrent consumers to create. Default is 1.
   *
   * <p>Raising the number of concurrent consumers is recommended in order to scale the consumption
   * of messages coming in from a queue. However, note that any ordering guarantees are lost once
   * multiple consumers are registered. In general, stick with 1 consumer for low-volume queues.
   * Cannot be less than {@link #maxConcurrentConsumers} (if set).
   *
   * @see #setMaxConcurrentConsumers(int)
   * @param concurrentConsumers the minimum number of consumers to create.
   */
  public void setConcurrentConsumers(final int concurrentConsumers) {
    Assert.isTrue(concurrentConsumers > 0, "'concurrentConsumers' value must be at least 1 (one)");
    if (this.maxConcurrentConsumers != null) {
      Assert.isTrue(
          concurrentConsumers <= this.maxConcurrentConsumers,
          "'concurrentConsumers' cannot be more than 'maxConcurrentConsumers'");
    }
    synchronized (consumersMonitor) {
      if (logger.isDebugEnabled()) {
        logger.debug(
            "Changing consumers from " + this.concurrentConsumers + " to " + concurrentConsumers);
      }
      int delta = this.concurrentConsumers - concurrentConsumers;
      this.concurrentConsumers = concurrentConsumers;
      if (isActive() && this.consumers != null) {
        if (delta > 0) {
          Iterator<Entry<BlockingQueueConsumer, Boolean>> entryIterator =
              consumers.entrySet().iterator();
          while (entryIterator.hasNext() && delta > 0) {
            Entry<BlockingQueueConsumer, Boolean> entry = entryIterator.next();
            if (entry.getValue()) {
              BlockingQueueConsumer consumer = entry.getKey();
              consumer.setQuiesce(this.shutdownTimeout);
              this.consumers.put(consumer, false);
              delta--;
            }
          }

        } else {
          addAndStartConsumers(-delta);
        }
      }
    }
  }
  private boolean doReceiveAndExecute(BlockingQueueConsumer consumer) throws Throwable {

    Channel channel = consumer.getChannel();

    for (int i = 0; i < txSize; i++) {

      logger.trace("Waiting for message from consumer.");
      Message message = consumer.nextMessage(receiveTimeout);
      if (message == null) {
        break;
      }
      try {
        executeListener(channel, message);
      } catch (ImmediateAcknowledgeAmqpException e) {
        break;
      } catch (Throwable ex) {
        consumer.rollbackOnExceptionIfNecessary(ex);
        throw ex;
      }
    }

    return consumer.commitIfNecessary(isChannelLocallyTransacted(channel));
  }
 private void restart(BlockingQueueConsumer consumer) {
   synchronized (this.consumersMonitor) {
     if (this.consumers != null) {
       try {
         // Need to recycle the channel in this consumer
         consumer.stop();
         // Ensure consumer counts are correct (another is going
         // to start because of the exception, but
         // we haven't counted down yet)
         this.cancellationLock.release(consumer);
         this.consumers.remove(consumer);
         consumer = createBlockingQueueConsumer();
         this.consumers.add(consumer);
       } catch (RuntimeException e) {
         logger.warn(
             "Consumer failed irretrievably on restart. " + e.getClass() + ": " + e.getMessage());
         // Re-throw and have it logged properly by the caller.
         throw e;
       }
       this.taskExecutor.execute(new AsyncMessageProcessingConsumer(consumer));
     }
   }
 }
 private void restart(BlockingQueueConsumer consumer) {
   synchronized (this.consumersMonitor) {
     if (this.consumers != null) {
       try {
         // Need to recycle the channel in this consumer
         consumer.stop();
         // Ensure consumer counts are correct (another is going
         // to start because of the exception, but
         // we haven't counted down yet)
         this.cancellationLock.release(consumer);
         this.consumers.remove(consumer);
         consumer = createBlockingQueueConsumer();
         this.consumers.add(consumer);
       } catch (RuntimeException e) {
         logger.warn("Consumer died on restart. " + e.getClass() + ": " + e.getMessage());
         // Thrown into the void (probably) in a background thread.
         // Oh well, here goes...
         throw e;
       }
       this.taskExecutor.execute(new AsyncMessageProcessingConsumer(consumer));
     }
   }
 }
    public void run() {

      boolean aborted = false;

      try {

        try {
          consumer.start();
          start.countDown();
        } catch (FatalListenerStartupException ex) {
          throw ex;
        } catch (Throwable t) {
          start.countDown();
          handleStartupFailure(t);
          throw t;
        }

        // Always better to stop receiving as soon as possible if
        // transactional
        boolean continuable = false;
        while (isActive() || continuable) {
          try {
            // Will come back false when the queue is drained
            continuable = receiveAndExecute(consumer) && !isChannelTransacted();
          } catch (ListenerExecutionFailedException ex) {
            // Continue to process, otherwise re-throw
          }
        }

      } catch (InterruptedException e) {
        logger.debug("Consumer thread interrupted, processing stopped.");
        Thread.currentThread().interrupt();
        aborted = true;
      } catch (FatalListenerStartupException ex) {
        logger.error("Consumer received fatal exception on startup", ex);
        this.startupException = ex;
        // Fatal, but no point re-throwing, so just abort.
        aborted = true;
      } catch (FatalListenerExecutionException ex) {
        logger.error("Consumer received fatal exception during processing", ex);
        // Fatal, but no point re-throwing, so just abort.
        aborted = true;
      } catch (Throwable t) {
        if (logger.isDebugEnabled()) {
          logger.warn(
              "Consumer raised exception, processing can restart if the connection factory supports it",
              t);
        } else {
          logger.warn(
              "Consumer raised exception, processing can restart if the connection factory supports it. "
                  + "Exception summary: "
                  + t);
        }
      }

      // In all cases count down to allow container to progress beyond startup
      start.countDown();

      if (!isActive() || aborted) {
        logger.debug("Cancelling " + consumer);
        try {
          consumer.stop();
        } catch (AmqpException e) {
          logger.info("Could not cancel message consumer", e);
        }
        if (aborted) {
          logger.info("Stopping container from aborted consumer");
          stop();
        }
      } else {
        logger.info("Restarting " + consumer);
        restart(consumer);
      }
    }
    @Override
    public void run() {

      boolean aborted = false;

      int consecutiveIdles = 0;

      int consecutiveMessages = 0;

      try {

        try {
          this.consumer.start();
          this.start.countDown();
        } catch (FatalListenerStartupException ex) {
          throw ex;
        } catch (Throwable t) {
          this.start.countDown();
          handleStartupFailure(t);
          throw t;
        }

        if (SimpleMessageListenerContainer.this.transactionManager != null) {
          /*
           * Register the consumer's channel so it will be used by the transaction manager
           * if it's an instance of RabbitTransactionManager.
           */
          ConsumerChannelRegistry.registerConsumerChannel(
              consumer.getChannel(), getConnectionFactory());
        }

        // Always better to stop receiving as soon as possible if
        // transactional
        boolean continuable = false;
        while (isActive(this.consumer) || continuable) {
          try {
            // Will come back false when the queue is drained
            continuable = receiveAndExecute(this.consumer) && !isChannelTransacted();
            if (SimpleMessageListenerContainer.this.maxConcurrentConsumers != null) {
              if (continuable) {
                consecutiveIdles = 0;
                if (consecutiveMessages++
                    > SimpleMessageListenerContainer.this.consecutiveActiveTrigger) {
                  considerAddingAConsumer();
                  consecutiveMessages = 0;
                }
              } else {
                consecutiveMessages = 0;
                if (consecutiveIdles++
                    > SimpleMessageListenerContainer.this.consecutiveIdleTrigger) {
                  considerStoppingAConsumer(this.consumer);
                  consecutiveIdles = 0;
                }
              }
            }
          } catch (ListenerExecutionFailedException ex) {
            // Continue to process, otherwise re-throw
          }
        }

      } catch (InterruptedException e) {
        logger.debug("Consumer thread interrupted, processing stopped.");
        Thread.currentThread().interrupt();
        aborted = true;
      } catch (FatalListenerStartupException ex) {
        logger.error("Consumer received fatal exception on startup", ex);
        this.startupException = ex;
        // Fatal, but no point re-throwing, so just abort.
        aborted = true;
      } catch (FatalListenerExecutionException ex) {
        logger.error("Consumer received fatal exception during processing", ex);
        // Fatal, but no point re-throwing, so just abort.
        aborted = true;
      } catch (ShutdownSignalException e) {
        Object shutdownReason = e.getReason();
        if (shutdownReason instanceof AMQP.Connection.Close
            && AMQP.REPLY_SUCCESS == ((AMQP.Connection.Close) shutdownReason).getReplyCode()
            && "OK".equals(((AMQP.Connection.Close) shutdownReason).getReplyText())) {
          logger.debug("Consumer received Shutdown Signal, processing stopped.", e);
        } else {
          this.logConsumerException(e);
        }
      } catch (Error e) {
        logger.error("Consumer thread error, thread abort.", e);
        aborted = true;
      } catch (Throwable t) {
        this.logConsumerException(t);
      } finally {
        if (SimpleMessageListenerContainer.this.transactionManager != null) {
          ConsumerChannelRegistry.unRegisterConsumerChannel();
        }
      }

      // In all cases count down to allow container to progress beyond startup
      start.countDown();

      if (!isActive(consumer) || aborted) {
        logger.debug("Cancelling " + this.consumer);
        try {
          this.consumer.stop();
          synchronized (consumersMonitor) {
            if (SimpleMessageListenerContainer.this.consumers != null) {
              SimpleMessageListenerContainer.this.consumers.remove(this.consumer);
            }
          }
        } catch (AmqpException e) {
          logger.info("Could not cancel message consumer", e);
        }
        if (aborted) {
          logger.info("Stopping container from aborted consumer");
          stop();
        }
      } else {
        logger.info("Restarting " + this.consumer);
        restart(this.consumer);
      }
    }