com.rabbitmq.client.impl.ConsumerDispatcher Maven / Gradle / Ivy
Go to download
Show more of this group Show more artifacts with this name
Show all versions of amqp-client Show documentation
Show all versions of amqp-client Show documentation
The RabbitMQ Java client library allows Java applications to interface with RabbitMQ.
// Copyright (c) 2007-2020 VMware, Inc. or its affiliates. All rights reserved.
//
// This software, the RabbitMQ Java client library, is triple-licensed under the
// Mozilla Public License 2.0 ("MPL"), the GNU General Public License version 2
// ("GPL") and the Apache License version 2 ("ASL"). For the MPL, please see
// LICENSE-MPL-RabbitMQ. For the GPL, please see LICENSE-GPL2. For the ASL,
// please see LICENSE-APACHE2.
//
// This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY KIND,
// either express or implied. See the LICENSE file for specific language governing
// rights and limitations of this software.
//
// If you have any questions regarding licensing, please contact us at
// [email protected].
package com.rabbitmq.client.impl;
import com.rabbitmq.client.AMQP;
import com.rabbitmq.client.Channel;
import com.rabbitmq.client.Consumer;
import com.rabbitmq.client.Envelope;
import com.rabbitmq.client.ShutdownSignalException;
import com.rabbitmq.utility.Utility;
import java.io.IOException;
import java.util.Map;
import java.util.concurrent.CountDownLatch;
/**
* Dispatches notifications to a {@link Consumer} on an internally-managed executor service and work
* pool.
*
* Each {@link Channel} has a single ConsumerDispatcher
, but the executor service and work
* pool may be shared with other channels, typically those on the same {@link AMQConnection}.
*/
final class ConsumerDispatcher {
private final ConsumerWorkService workService;
private final AMQConnection connection;
private final Channel channel;
private volatile boolean shuttingDown = false;
private volatile boolean shutdownConsumersDriven = false;
private volatile CountDownLatch shutdownConsumersComplete;
private volatile ShutdownSignalException shutdownSignal = null;
public ConsumerDispatcher(AMQConnection connection,
Channel channel,
ConsumerWorkService workService) {
this.connection = connection;
this.channel = channel;
workService.registerKey(channel);
this.workService = workService;
}
/** Prepare for shutdown of all consumers on this channel */
public void quiesce() {
// Prevent any more items being put on the queue (except the shutdown item)
this.shuttingDown = true;
}
public void setUnlimited(boolean unlimited) {
this.workService.setUnlimited(channel, unlimited);
}
public void handleConsumeOk(final Consumer delegate,
final String consumerTag) {
executeUnlessShuttingDown(
new Runnable() {
@Override
public void run() {
try {
delegate.handleConsumeOk(consumerTag);
} catch (Throwable ex) {
connection.getExceptionHandler().handleConsumerException(
channel,
ex,
delegate,
consumerTag,
"handleConsumeOk");
}
}
});
}
public void handleCancelOk(final Consumer delegate,
final String consumerTag) {
executeUnlessShuttingDown(
new Runnable() {
@Override
public void run() {
try {
delegate.handleCancelOk(consumerTag);
} catch (Throwable ex) {
connection.getExceptionHandler().handleConsumerException(
channel,
ex,
delegate,
consumerTag,
"handleCancelOk");
}
}
});
}
public void handleCancel(final Consumer delegate, final String consumerTag) {
executeUnlessShuttingDown(
new Runnable() {
@Override
public void run() {
try {
delegate.handleCancel(consumerTag);
} catch (Throwable ex) {
connection.getExceptionHandler().handleConsumerException(
channel,
ex,
delegate,
consumerTag,
"handleCancel");
}
}
});
}
public void handleRecoverOk(final Consumer delegate, final String consumerTag) {
executeUnlessShuttingDown(
new Runnable() {
@Override
public void run() {
delegate.handleRecoverOk(consumerTag);
}
});
}
public void handleDelivery(final Consumer delegate,
final String consumerTag,
final Envelope envelope,
final AMQP.BasicProperties properties,
final byte[] body) throws IOException {
executeUnlessShuttingDown(
new Runnable() {
@Override
public void run() {
try {
delegate.handleDelivery(consumerTag,
envelope,
properties,
body);
} catch (Throwable ex) {
connection.getExceptionHandler().handleConsumerException(
channel,
ex,
delegate,
consumerTag,
"handleDelivery");
}
}
});
}
public CountDownLatch handleShutdownSignal(final Map consumers,
final ShutdownSignalException signal) {
// ONLY CASE WHERE WE IGNORE shuttingDown
if (!this.shutdownConsumersDriven) {
final CountDownLatch latch = new CountDownLatch(1);
this.shutdownConsumersComplete = latch;
this.shutdownConsumersDriven = true;
// Execute shutdown processing even if there are no consumers.
execute(new Runnable() {
@Override
public void run() {
ConsumerDispatcher.this.notifyConsumersOfShutdown(consumers, signal);
ConsumerDispatcher.this.shutdown(signal);
ConsumerDispatcher.this.workService.stopWork(ConsumerDispatcher.this.channel);
latch.countDown();
}
});
}
return this.shutdownConsumersComplete;
}
private void notifyConsumersOfShutdown(Map consumers,
ShutdownSignalException signal) {
for (Map.Entry consumerEntry : consumers.entrySet()) {
notifyConsumerOfShutdown(consumerEntry.getKey(), consumerEntry.getValue(), signal);
}
}
private void notifyConsumerOfShutdown(String consumerTag,
Consumer consumer,
ShutdownSignalException signal) {
try {
consumer.handleShutdownSignal(consumerTag, signal);
} catch (Throwable ex) {
connection.getExceptionHandler().handleConsumerException(
channel,
ex,
consumer,
consumerTag,
"handleShutdownSignal");
}
}
private void executeUnlessShuttingDown(Runnable r) {
if (!this.shuttingDown) execute(r);
}
private void execute(Runnable r) {
checkShutdown();
this.workService.addWork(this.channel, r);
}
private void shutdown(ShutdownSignalException signal) {
this.shutdownSignal = signal;
}
private void checkShutdown() {
if (this.shutdownSignal != null) {
throw Utility.fixStackTrace(this.shutdownSignal);
}
}
}