Skip to content

Commit a2e19ba

Browse files
garyrussellartembilan
authored andcommitted
AMQP-820: SMLC: Remove InternalConsumer decorator
JIRA: https://jira.spring.io/browse/AMQP-820 Use a discrete `InternalConsumer` for each queue. * Add debug logging for BrokerDeclaredQueueNameTests Can't reproduce travis failures; need to wait for a Bamboo failure.
1 parent 68d74bd commit a2e19ba

File tree

9 files changed

+134
-138
lines changed

9 files changed

+134
-138
lines changed

spring-rabbit/src/main/java/org/springframework/amqp/rabbit/core/RabbitTemplate.java

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2279,7 +2279,7 @@ public void handleConsumeOk(String consumerTag) {
22792279
@Override
22802280
public void handleDelivery(String consumerTag, Envelope envelope, BasicProperties properties, byte[] body)
22812281
throws IOException {
2282-
future.complete(new Delivery(consumerTag, envelope, properties, body));
2282+
future.complete(new Delivery(consumerTag, envelope, properties, body, queueName));
22832283
}
22842284

22852285
};

spring-rabbit/src/main/java/org/springframework/amqp/rabbit/listener/BlockingQueueConsumer.java

Lines changed: 44 additions & 99 deletions
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,7 @@
1919
import java.io.IOException;
2020
import java.util.ArrayList;
2121
import java.util.Arrays;
22+
import java.util.Collection;
2223
import java.util.Collections;
2324
import java.util.HashMap;
2425
import java.util.HashSet;
@@ -30,10 +31,12 @@
3031
import java.util.Set;
3132
import java.util.concurrent.BlockingQueue;
3233
import java.util.concurrent.ConcurrentHashMap;
34+
import java.util.concurrent.ConcurrentMap;
3335
import java.util.concurrent.LinkedBlockingQueue;
3436
import java.util.concurrent.TimeUnit;
3537
import java.util.concurrent.TimeoutException;
3638
import java.util.concurrent.atomic.AtomicBoolean;
39+
import java.util.stream.Collectors;
3740

3841
import org.apache.commons.logging.Log;
3942
import org.apache.commons.logging.LogFactory;
@@ -63,7 +66,6 @@
6366
import com.rabbitmq.client.AMQP;
6467
import com.rabbitmq.client.AlreadyClosedException;
6568
import com.rabbitmq.client.Channel;
66-
import com.rabbitmq.client.Consumer;
6769
import com.rabbitmq.client.DefaultConsumer;
6870
import com.rabbitmq.client.Envelope;
6971
import com.rabbitmq.client.Recoverable;
@@ -103,7 +105,7 @@ public class BlockingQueueConsumer implements RecoveryListener {
103105

104106
private RabbitResourceHolder resourceHolder;
105107

106-
private InternalConsumer consumer;
108+
private final ConcurrentMap<String, InternalConsumer> consumers = new ConcurrentHashMap<>();
107109

108110
/**
109111
* The flag indicating that consumer has been cancelled from all queues
@@ -129,8 +131,6 @@ public class BlockingQueueConsumer implements RecoveryListener {
129131

130132
private final boolean defaultRequeueRejected;
131133

132-
private final Map<String, String> consumerTags = new ConcurrentHashMap<String, String>();
133-
134134
private final Set<String> missingQueues = Collections.synchronizedSet(new HashSet<String>());
135135

136136
private long retryDeclarationInterval = 60000;
@@ -290,8 +290,11 @@ public Channel getChannel() {
290290
return this.channel;
291291
}
292292

293-
public String getConsumerTag() {
294-
return this.consumer.getConsumerTag();
293+
public Collection<String> getConsumerTags() {
294+
return this.consumers.values().stream()
295+
.map(c -> c.getConsumerTag())
296+
.filter(tag -> tag != null)
297+
.collect(Collectors.toList());
295298
}
296299

297300
public void setShutdownTimeout(long shutdownTimeout) {
@@ -394,8 +397,7 @@ protected void basicCancel() {
394397

395398
protected void basicCancel(boolean expected) {
396399
this.normalCancel = expected;
397-
for (String consumerTag : this.consumerTags.keySet()) {
398-
removeConsumer(consumerTag);
400+
getConsumerTags().forEach(consumerTag -> {
399401
try {
400402
if (this.channel.isOpen()) {
401403
this.channel.basicCancel(consumerTag);
@@ -411,7 +413,8 @@ protected void basicCancel(boolean expected) {
411413
logger.trace(this.channel + " is already closed");
412414
}
413415
}
414-
}
416+
});
417+
this.cancelled.set(true);
415418
this.abortStarted = System.currentTimeMillis();
416419
}
417420

@@ -455,7 +458,7 @@ private Message handle(Delivery delivery) throws InterruptedException {
455458
MessageProperties messageProperties = this.messagePropertiesConverter.toMessageProperties(
456459
delivery.getProperties(), envelope, "UTF-8");
457460
messageProperties.setConsumerTag(delivery.getConsumerTag());
458-
messageProperties.setConsumerQueue(this.consumerTags.get(delivery.getConsumerTag()));
461+
messageProperties.setConsumerQueue(delivery.getQueue());
459462
Message message = new Message(body, messageProperties);
460463
if (logger.isDebugEnabled()) {
461464
logger.debug("Received message: " + message);
@@ -573,7 +576,6 @@ public void start() throws AmqpException {
573576
catch (AmqpAuthenticationException e) {
574577
throw new FatalListenerStartupException("Authentication failure", e);
575578
}
576-
this.consumer = new InternalConsumer(this.channel);
577579
this.deliveryTags.clear();
578580
this.activeObjectCounter.add(this);
579581

@@ -666,13 +668,14 @@ private void addRecoveryListener() {
666668
}
667669

668670
private void consumeFromQueue(String queue) throws IOException {
671+
InternalConsumer consumer = new InternalConsumer(this.channel, queue);
669672
String consumerTag = this.channel.basicConsume(queue, this.acknowledgeMode.isAutoAck(),
670673
(this.tagStrategy != null ? this.tagStrategy.createConsumerTag(queue) : ""), this.noLocal,
671674
this.exclusive, this.consumerArgs,
672-
new ConsumerDecorator(queue, this.consumer, this.applicationEventPublisher));
675+
consumer);
673676

674677
if (consumerTag != null) {
675-
this.consumerTags.put(consumerTag, queue);
678+
this.consumers.put(queue, consumer);
676679
if (logger.isDebugEnabled()) {
677680
logger.debug("Started on queue '" + queue + "' with tag " + consumerTag + ": " + this);
678681
}
@@ -718,15 +721,13 @@ private void attemptPassiveDeclarations() {
718721
}
719722
}
720723

721-
public void stop() {
724+
public synchronized void stop() {
722725
if (this.abortStarted == 0) { // signal handle delivery to use offer
723726
this.abortStarted = System.currentTimeMillis();
724727
}
725-
if (this.consumer != null && this.consumer.getChannel() != null && this.consumerTags.size() > 0
726-
&& !this.cancelled.get()) {
728+
if (!this.cancelled()) {
727729
try {
728-
RabbitUtils.closeMessageConsumer(this.consumer.getChannel(), this.consumerTags.keySet(),
729-
this.transactional);
730+
RabbitUtils.closeMessageConsumer(this.channel, getConsumerTags(), this.transactional);
730731
}
731732
catch (Exception e) {
732733
if (logger.isDebugEnabled()) {
@@ -740,7 +741,7 @@ public void stop() {
740741
RabbitUtils.setPhysicalCloseRequired(this.channel, true);
741742
ConnectionFactoryUtils.releaseResources(this.resourceHolder);
742743
this.deliveryTags.clear();
743-
this.consumer = null;
744+
this.consumers.clear();
744745
this.queue.clear(); // in case we still have a client thread blocked
745746
}
746747

@@ -780,22 +781,6 @@ public void rollbackOnExceptionIfNecessary(Throwable ex) throws Exception {
780781
}
781782
}
782783

783-
/**
784-
* Remove the consumer and set cancelled if all are gone.
785-
* @param consumerTag the tag to remove.
786-
* @return true if consumers remain.
787-
*/
788-
private boolean removeConsumer(String consumerTag) {
789-
this.consumerTags.remove(consumerTag);
790-
if (this.consumerTags.isEmpty()) {
791-
this.cancelled.set(true);
792-
return false;
793-
}
794-
else {
795-
return true;
796-
}
797-
}
798-
799784
/**
800785
* Perform a commit or message acknowledgement, as appropriate.
801786
* @param locallyTransacted Whether the channel is locally transacted.
@@ -861,14 +846,18 @@ public void handleRecoveryStarted(Recoverable recoverable) {
861846
@Override
862847
public String toString() {
863848
return "Consumer@" + ObjectUtils.getIdentityHexString(this) + ": "
864-
+ "tags=[" + (this.consumerTags.toString()) + "], channel=" + this.channel
849+
+ "tags=[" + getConsumerTags()
850+
+ "], channel=" + this.channel
865851
+ ", acknowledgeMode=" + this.acknowledgeMode + " local queue size=" + this.queue.size();
866852
}
867853

868854
private final class InternalConsumer extends DefaultConsumer {
869855

870-
InternalConsumer(Channel channel) {
856+
private final String queue;
857+
858+
InternalConsumer(Channel channel, String queue) {
871859
super(channel);
860+
this.queue = queue;
872861
}
873862

874863
@Override
@@ -877,6 +866,10 @@ public void handleConsumeOk(String consumerTag) {
877866
if (logger.isDebugEnabled()) {
878867
logger.debug("ConsumeOK: " + BlockingQueueConsumer.this);
879868
}
869+
if (BlockingQueueConsumer.this.applicationEventPublisher != null) {
870+
BlockingQueueConsumer.this.applicationEventPublisher
871+
.publishEvent(new ConsumeOkEvent(this, this.queue, consumerTag));
872+
}
880873
}
881874

882875
@Override
@@ -899,19 +892,23 @@ public void handleShutdownSignal(String consumerTag, ShutdownSignalException sig
899892
public void handleCancel(String consumerTag) throws IOException {
900893
if (logger.isWarnEnabled()) {
901894
logger.warn("Cancel received for " + consumerTag + " ("
902-
+ BlockingQueueConsumer.this.consumerTags.get(consumerTag)
895+
+ this.queue
903896
+ "); " + BlockingQueueConsumer.this);
904897
}
905-
if (removeConsumer(consumerTag)) {
898+
BlockingQueueConsumer.this.consumers.remove(this.queue);
899+
if (!BlockingQueueConsumer.this.consumers.isEmpty()) {
906900
basicCancel(false);
907901
}
902+
else {
903+
BlockingQueueConsumer.this.cancelled.set(true);
904+
}
908905
}
909906

910907
@Override
911908
public void handleCancelOk(String consumerTag) {
912909
if (logger.isDebugEnabled()) {
913910
logger.debug("Received cancelOk for tag " + consumerTag + " ("
914-
+ BlockingQueueConsumer.this.consumerTags.get(consumerTag)
911+
+ this.queue
915912
+ "); " + BlockingQueueConsumer.this);
916913
}
917914
}
@@ -926,8 +923,10 @@ public void handleDelivery(String consumerTag, Envelope envelope, AMQP.BasicProp
926923
}
927924
try {
928925
if (BlockingQueueConsumer.this.abortStarted > 0) {
929-
if (!BlockingQueueConsumer.this.queue.offer(new Delivery(consumerTag, envelope, properties, body),
926+
if (!BlockingQueueConsumer.this.queue.offer(
927+
new Delivery(consumerTag, envelope, properties, body, this.queue),
930928
BlockingQueueConsumer.this.shutdownTimeout, TimeUnit.MILLISECONDS)) {
929+
931930
RabbitUtils.setPhysicalCloseRequired(getChannel(), true);
932931
// Defensive - should never happen
933932
BlockingQueueConsumer.this.queue.clear();
@@ -942,73 +941,19 @@ public void handleDelivery(String consumerTag, Envelope envelope, AMQP.BasicProp
942941
}
943942
}
944943
else {
945-
BlockingQueueConsumer.this.queue.put(new Delivery(consumerTag, envelope, properties, body));
944+
BlockingQueueConsumer.this.queue
945+
.put(new Delivery(consumerTag, envelope, properties, body, this.queue));
946946
}
947947
}
948948
catch (InterruptedException e) {
949949
Thread.currentThread().interrupt();
950950
}
951951
}
952952

953-
}
954-
955-
private static final class ConsumerDecorator implements Consumer {
956-
957-
private final String queue;
958-
959-
private final Consumer delegate;
960-
961-
private final ApplicationEventPublisher applicationEventPublisher;
962-
963-
private String consumerTag;
964-
965-
ConsumerDecorator(String queue, Consumer delegate, ApplicationEventPublisher applicationEventPublisher) {
966-
this.queue = queue;
967-
this.delegate = delegate;
968-
this.applicationEventPublisher = applicationEventPublisher;
969-
}
970-
971-
972-
@Override
973-
public void handleConsumeOk(String consumerTag) {
974-
this.consumerTag = consumerTag;
975-
this.delegate.handleConsumeOk(consumerTag);
976-
if (this.applicationEventPublisher != null) {
977-
this.applicationEventPublisher.publishEvent(new ConsumeOkEvent(this.delegate, this.queue, consumerTag));
978-
}
979-
}
980-
981-
@Override
982-
public void handleShutdownSignal(String consumerTag, ShutdownSignalException sig) {
983-
this.delegate.handleShutdownSignal(consumerTag, sig);
984-
}
985-
986-
@Override
987-
public void handleCancel(String consumerTag) throws IOException {
988-
this.delegate.handleCancel(consumerTag);
989-
}
990-
991-
@Override
992-
public void handleCancelOk(String consumerTag) {
993-
this.delegate.handleCancelOk(consumerTag);
994-
}
995-
996-
@Override
997-
public void handleDelivery(String consumerTag, Envelope envelope, AMQP.BasicProperties properties,
998-
byte[] body) throws IOException {
999-
1000-
this.delegate.handleDelivery(consumerTag, envelope, properties, body);
1001-
}
1002-
1003-
@Override
1004-
public void handleRecoverOk(String consumerTag) {
1005-
this.delegate.handleRecoverOk(consumerTag);
1006-
}
1007-
1008953
@Override
1009954
public String toString() {
1010-
return "ConsumerDecorator{" + "queue='" + this.queue + '\'' +
1011-
", consumerTag='" + this.consumerTag + '\'' +
955+
return "InternalConsumer{" + "queue='" + this.queue + '\'' +
956+
", consumerTag='" + getConsumerTag() + '\'' +
1012957
'}';
1013958
}
1014959

spring-rabbit/src/main/java/org/springframework/amqp/rabbit/support/Delivery.java

Lines changed: 14 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
/*
2-
* Copyright 2016 the original author or authors.
2+
* Copyright 2016-2018 the original author or authors.
33
*
44
* Licensed under the Apache License, Version 2.0 (the "License");
55
* you may not use this file except in compliance with the License.
@@ -32,15 +32,19 @@ public class Delivery {
3232

3333
private final Envelope envelope;
3434

35+
private final String queue;
36+
3537
private final AMQP.BasicProperties properties;
3638

3739
private final byte[] body;
3840

39-
public Delivery(String consumerTag, Envelope envelope, AMQP.BasicProperties properties, byte[] body) { //NOSONAR
41+
public Delivery(String consumerTag, Envelope envelope, AMQP.BasicProperties properties, byte[] body,
42+
String queue) { //NOSONAR
4043
this.consumerTag = consumerTag;
4144
this.envelope = envelope;
4245
this.properties = properties;
4346
this.body = body;
47+
this.queue = queue;
4448
}
4549

4650
/**
@@ -75,4 +79,12 @@ public byte[] getBody() {
7579
return this.body;
7680
}
7781

82+
/**
83+
* Retrieve the queue.
84+
* @return the queue.
85+
*/
86+
public String getQueue() {
87+
return this.queue;
88+
}
89+
7890
}

0 commit comments

Comments
 (0)