From 6c781cd10adbd4524a04a7ca5705ff3008b9d21b Mon Sep 17 00:00:00 2001 From: SJ Date: Thu, 13 Dec 2018 11:55:01 -0800 Subject: [PATCH 01/42] Update Apache Proton-J dependency (0.29.0 --> 0.31.0) (#407) --- pom.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pom.xml b/pom.xml index 12e91a000a89..867a20c7f54e 100644 --- a/pom.xml +++ b/pom.xml @@ -12,7 +12,7 @@ https://github.com/Azure/azure-event-hubs - 0.29.0 + 0.31.0 1.1.0 4.12 1.8.0-alpha2 From 71f856213816b33a182ff3ed41a22d06b9f7399d Mon Sep 17 00:00:00 2001 From: SJ Date: Thu, 13 Dec 2018 13:21:46 -0800 Subject: [PATCH 02/42] PartitionReceiver - add a method that provides an EventPosition which corresponds to an EventData returned last by the receiver (#408) --- .../azure/eventhubs/EventPosition.java | 28 +++++++++++++++++++ .../azure/eventhubs/PartitionReceiver.java | 8 ++++++ .../azure/eventhubs/impl/EventDataUtil.java | 13 +++++---- .../eventhubs/impl/EventPositionImpl.java | 16 +++++++++++ .../azure/eventhubs/impl/MessageWrapper.java | 26 +++++++++++++++++ .../eventhubs/impl/PartitionReceiverImpl.java | 15 ++++++---- .../sendrecv/ReceiverRuntimeMetricsTest.java | 5 +++- 7 files changed, 100 insertions(+), 11 deletions(-) create mode 100644 azure-eventhubs/src/main/java/com/microsoft/azure/eventhubs/impl/MessageWrapper.java diff --git a/azure-eventhubs/src/main/java/com/microsoft/azure/eventhubs/EventPosition.java b/azure-eventhubs/src/main/java/com/microsoft/azure/eventhubs/EventPosition.java index 19c6979c93bb..797fbb2d0446 100644 --- a/azure-eventhubs/src/main/java/com/microsoft/azure/eventhubs/EventPosition.java +++ b/azure-eventhubs/src/main/java/com/microsoft/azure/eventhubs/EventPosition.java @@ -89,4 +89,32 @@ static EventPosition fromStartOfStream() { static EventPosition fromEndOfStream() { return EventPositionImpl.fromEndOfStream(); } + + /** + * Gets the sequence number. + *

+ * @return the sequence number. + */ + Long getSequenceNumber(); + + /** + * Gets the enqueued time. + *

+ * @return the enqueued time. + */ + Instant getEnqueuedTime(); + + /** + * Gets the offset. + *

+ * @return the offset. + */ + String getOffset(); + + /** + * Gets the inclusive value. + *

+ * @return the inclusive value. + */ + boolean getInclusiveFlag(); } diff --git a/azure-eventhubs/src/main/java/com/microsoft/azure/eventhubs/PartitionReceiver.java b/azure-eventhubs/src/main/java/com/microsoft/azure/eventhubs/PartitionReceiver.java index f0cf42a5dc5c..979382f0d8a3 100644 --- a/azure-eventhubs/src/main/java/com/microsoft/azure/eventhubs/PartitionReceiver.java +++ b/azure-eventhubs/src/main/java/com/microsoft/azure/eventhubs/PartitionReceiver.java @@ -78,6 +78,14 @@ public interface PartitionReceiver { */ ReceiverRuntimeInformation getRuntimeInformation(); + /** + * Get the {@link EventPosition} that corresponds to an {@link EventData} which was returned last by the receiver. + *

This value will not be populated, unless the knob {@link ReceiverOptions#setReceiverRuntimeMetricEnabled(boolean)} is set. + * + * @return the EventPosition object. + */ + EventPosition getEventPosition(); + /** * Synchronous version of {@link #receive}. * diff --git a/azure-eventhubs/src/main/java/com/microsoft/azure/eventhubs/impl/EventDataUtil.java b/azure-eventhubs/src/main/java/com/microsoft/azure/eventhubs/impl/EventDataUtil.java index 4f339cb84a31..491ee6b6e60e 100644 --- a/azure-eventhubs/src/main/java/com/microsoft/azure/eventhubs/impl/EventDataUtil.java +++ b/azure-eventhubs/src/main/java/com/microsoft/azure/eventhubs/impl/EventDataUtil.java @@ -5,6 +5,7 @@ package com.microsoft.azure.eventhubs.impl; import com.microsoft.azure.eventhubs.EventData; +import com.microsoft.azure.eventhubs.EventPosition; import org.apache.qpid.proton.message.Message; import java.util.*; @@ -27,7 +28,7 @@ final class EventDataUtil { private EventDataUtil() { } - static LinkedList toEventDataCollection(final Collection messages, final PassByRef lastMessageRef) { + static LinkedList toEventDataCollection(final Collection messages, final PassByRef lastMessageRef) { if (messages == null) { return null; @@ -35,11 +36,13 @@ static LinkedList toEventDataCollection(final Collection mes LinkedList events = new LinkedList<>(); for (Message message : messages) { + EventData eventData = new EventDataImpl(message); + events.add(eventData); - events.add(new EventDataImpl(message)); - - if (lastMessageRef != null) - lastMessageRef.set(message); + if (lastMessageRef != null) { + lastMessageRef.set(new MessageWrapper(message, + EventPosition.fromSequenceNumber(eventData.getSystemProperties().getSequenceNumber(), true))); + } } return events; diff --git a/azure-eventhubs/src/main/java/com/microsoft/azure/eventhubs/impl/EventPositionImpl.java b/azure-eventhubs/src/main/java/com/microsoft/azure/eventhubs/impl/EventPositionImpl.java index 154ca360ce41..898975d5b0e2 100644 --- a/azure-eventhubs/src/main/java/com/microsoft/azure/eventhubs/impl/EventPositionImpl.java +++ b/azure-eventhubs/src/main/java/com/microsoft/azure/eventhubs/impl/EventPositionImpl.java @@ -54,6 +54,22 @@ public static EventPositionImpl fromEndOfStream() { return new EventPositionImpl(ClientConstants.END_OF_STREAM, null, null, false); } + public Long getSequenceNumber() { + return this.sequenceNumber; + } + + public Instant getEnqueuedTime() { + return this.dateTime; + } + + public String getOffset() { + return this.offset; + } + + public boolean getInclusiveFlag() { + return this.inclusiveFlag; + } + String getExpression() { // order of preference if (this.offset != null) { diff --git a/azure-eventhubs/src/main/java/com/microsoft/azure/eventhubs/impl/MessageWrapper.java b/azure-eventhubs/src/main/java/com/microsoft/azure/eventhubs/impl/MessageWrapper.java new file mode 100644 index 000000000000..f2388659bb5c --- /dev/null +++ b/azure-eventhubs/src/main/java/com/microsoft/azure/eventhubs/impl/MessageWrapper.java @@ -0,0 +1,26 @@ +/* + * Copyright (c) Microsoft. All rights reserved. + * Licensed under the MIT license. See LICENSE file in the project root for full license information. + */ +package com.microsoft.azure.eventhubs.impl; + +import com.microsoft.azure.eventhubs.EventPosition; +import org.apache.qpid.proton.message.Message; + +final class MessageWrapper { + private final Message message; + private final EventPosition eventPosition; + + MessageWrapper(Message message, EventPosition eventPosition) { + this.message = message; + this.eventPosition = eventPosition; + } + + Message getMessage() { + return this.message; + } + + EventPosition getEventPosition() { + return this.eventPosition; + } +} diff --git a/azure-eventhubs/src/main/java/com/microsoft/azure/eventhubs/impl/PartitionReceiverImpl.java b/azure-eventhubs/src/main/java/com/microsoft/azure/eventhubs/impl/PartitionReceiverImpl.java index eab32117d85d..ed8fcde51328 100644 --- a/azure-eventhubs/src/main/java/com/microsoft/azure/eventhubs/impl/PartitionReceiverImpl.java +++ b/azure-eventhubs/src/main/java/com/microsoft/azure/eventhubs/impl/PartitionReceiverImpl.java @@ -36,6 +36,7 @@ final class PartitionReceiverImpl extends ClientEntity implements ReceiverSettin private volatile MessageReceiver internalReceiver; private ReceivePump receivePump; + private EventPosition currentEventPosition; private PartitionReceiverImpl(MessagingFactory factory, final String eventHubName, @@ -60,6 +61,7 @@ private PartitionReceiverImpl(MessagingFactory factory, this.runtimeInformation = (this.receiverOptions != null && this.receiverOptions.getReceiverRuntimeMetricEnabled()) ? new ReceiverRuntimeInformation(partitionId) : null; + this.currentEventPosition = EventPosition.fromStartOfStream(); } static CompletableFuture create(MessagingFactory factory, @@ -134,31 +136,34 @@ public final long getEpoch() { } public final ReceiverRuntimeInformation getRuntimeInformation() { - return this.runtimeInformation; } + public final EventPosition getEventPosition() { + return this.currentEventPosition; + } + public CompletableFuture> receive(final int maxEventCount) { return this.internalReceiver.receive(maxEventCount).thenApplyAsync(new Function, Iterable>() { @Override public Iterable apply(Collection amqpMessages) { - PassByRef lastMessageRef = null; + PassByRef lastMessageRef = null; if (PartitionReceiverImpl.this.receiverOptions != null && PartitionReceiverImpl.this.receiverOptions.getReceiverRuntimeMetricEnabled()) lastMessageRef = new PassByRef<>(); final Iterable events = EventDataUtil.toEventDataCollection(amqpMessages, lastMessageRef); if (lastMessageRef != null && lastMessageRef.get() != null) { - - final DeliveryAnnotations deliveryAnnotations = lastMessageRef.get().getDeliveryAnnotations(); + final DeliveryAnnotations deliveryAnnotations = lastMessageRef.get().getMessage().getDeliveryAnnotations(); if (deliveryAnnotations != null && deliveryAnnotations.getValue() != null) { - final Map deliveryAnnotationsMap = deliveryAnnotations.getValue(); PartitionReceiverImpl.this.runtimeInformation.setRuntimeInformation( (long) deliveryAnnotationsMap.get(ClientConstants.LAST_ENQUEUED_SEQUENCE_NUMBER), ((Date) deliveryAnnotationsMap.get(ClientConstants.LAST_ENQUEUED_TIME_UTC)).toInstant(), (String) deliveryAnnotationsMap.get(ClientConstants.LAST_ENQUEUED_OFFSET)); } + + PartitionReceiverImpl.this.currentEventPosition = lastMessageRef.get().getEventPosition(); } return events; diff --git a/azure-eventhubs/src/test/java/com/microsoft/azure/eventhubs/sendrecv/ReceiverRuntimeMetricsTest.java b/azure-eventhubs/src/test/java/com/microsoft/azure/eventhubs/sendrecv/ReceiverRuntimeMetricsTest.java index bacb54e55c4b..e86f4ed54a0f 100644 --- a/azure-eventhubs/src/test/java/com/microsoft/azure/eventhubs/sendrecv/ReceiverRuntimeMetricsTest.java +++ b/azure-eventhubs/src/test/java/com/microsoft/azure/eventhubs/sendrecv/ReceiverRuntimeMetricsTest.java @@ -70,8 +70,11 @@ public void testRuntimeMetricsReturnedWhenEnabled() throws EventHubException { LinkedList receivedEventsWithOptions = new LinkedList<>(); while (receivedEventsWithOptions.size() < sentEvents) - for (EventData eData : receiverWithOptions.receiveSync(sentEvents)) + for (EventData eData : receiverWithOptions.receiveSync(1)) { receivedEventsWithOptions.add(eData); + Assert.assertEquals((Long) eData.getSystemProperties().getSequenceNumber(), + receiverWithOptions.getEventPosition().getSequenceNumber()); + } HashSet offsets = new HashSet<>(); for (EventData eData : receivedEventsWithOptions) From 0dd058d8cb84fc5b9faa4c9574306356bfd6ec83 Mon Sep 17 00:00:00 2001 From: SJ Date: Thu, 13 Dec 2018 18:09:56 -0800 Subject: [PATCH 03/42] Support IsPartitionEmpty property for PartitionRuntimeInformation (#399) --- .../eventhubs/PartitionRuntimeInformation.java | 9 ++++++++- .../azure/eventhubs/impl/ClientConstants.java | 1 + .../azure/eventhubs/impl/EventHubClientImpl.java | 15 ++++++++------- .../eventhubs/sendrecv/RequestResponseTest.java | 2 +- 4 files changed, 18 insertions(+), 9 deletions(-) diff --git a/azure-eventhubs/src/main/java/com/microsoft/azure/eventhubs/PartitionRuntimeInformation.java b/azure-eventhubs/src/main/java/com/microsoft/azure/eventhubs/PartitionRuntimeInformation.java index 6d4695ee47bb..c086f63ca818 100644 --- a/azure-eventhubs/src/main/java/com/microsoft/azure/eventhubs/PartitionRuntimeInformation.java +++ b/azure-eventhubs/src/main/java/com/microsoft/azure/eventhubs/PartitionRuntimeInformation.java @@ -14,6 +14,7 @@ public final class PartitionRuntimeInformation { private final long lastEnqueuedSequenceNumber; private final String lastEnqueuedOffset; private final Instant lastEnqueuedTimeUtc; + private final boolean isEmpty; public PartitionRuntimeInformation( final String eventHubPath, @@ -21,7 +22,8 @@ public PartitionRuntimeInformation( final long beginSequenceNumber, final long lastEnqueuedSequenceNumber, final String lastEnqueuedOffset, - final Instant lastEnqueuedTimeUtc) { + final Instant lastEnqueuedTimeUtc, + final boolean isEmpty) { this.eventHubPath = eventHubPath; this.partitionId = partitionId; @@ -29,6 +31,7 @@ public PartitionRuntimeInformation( this.lastEnqueuedSequenceNumber = lastEnqueuedSequenceNumber; this.lastEnqueuedOffset = lastEnqueuedOffset; this.lastEnqueuedTimeUtc = lastEnqueuedTimeUtc; + this.isEmpty = isEmpty; } public String getEventHubPath() { @@ -54,4 +57,8 @@ public String getLastEnqueuedOffset() { public Instant getLastEnqueuedTimeUtc() { return this.lastEnqueuedTimeUtc; } + + public boolean getIsEmpty() { + return this.isEmpty; + } } diff --git a/azure-eventhubs/src/main/java/com/microsoft/azure/eventhubs/impl/ClientConstants.java b/azure-eventhubs/src/main/java/com/microsoft/azure/eventhubs/impl/ClientConstants.java index 507589cf6c79..e827e5ca1fab 100644 --- a/azure-eventhubs/src/main/java/com/microsoft/azure/eventhubs/impl/ClientConstants.java +++ b/azure-eventhubs/src/main/java/com/microsoft/azure/eventhubs/impl/ClientConstants.java @@ -66,6 +66,7 @@ public final class ClientConstants { public static final String MANAGEMENT_RESULT_LAST_ENQUEUED_SEQUENCE_NUMBER = "last_enqueued_sequence_number"; public static final String MANAGEMENT_RESULT_LAST_ENQUEUED_OFFSET = "last_enqueued_offset"; public static final String MANAGEMENT_RESULT_LAST_ENQUEUED_TIME_UTC = "last_enqueued_time_utc"; + public static final String MANAGEMENT_RESULT_PARTITION_IS_EMPTY = "is_partition_empty"; public static final String MANAGEMENT_STATUS_CODE_KEY = "status-code"; public static final String MANAGEMENT_STATUS_DESCRIPTION_KEY = "status-description"; public static final String MANAGEMENT_RESPONSE_ERROR_CONDITION = "error-condition"; diff --git a/azure-eventhubs/src/main/java/com/microsoft/azure/eventhubs/impl/EventHubClientImpl.java b/azure-eventhubs/src/main/java/com/microsoft/azure/eventhubs/impl/EventHubClientImpl.java index 5fbd6f62ed9e..075dfdbca9b2 100644 --- a/azure-eventhubs/src/main/java/com/microsoft/azure/eventhubs/impl/EventHubClientImpl.java +++ b/azure-eventhubs/src/main/java/com/microsoft/azure/eventhubs/impl/EventHubClientImpl.java @@ -281,15 +281,16 @@ public CompletableFuture getPartitionRuntimeInforma if (future1 == null) { future1 = managementWithRetry(request).thenComposeAsync(new Function, CompletableFuture>() { @Override - public CompletableFuture apply(Map rawdata) { + public CompletableFuture apply(Map rawData) { CompletableFuture future2 = new CompletableFuture(); future2.complete(new PartitionRuntimeInformation( - (String) rawdata.get(ClientConstants.MANAGEMENT_ENTITY_NAME_KEY), - (String) rawdata.get(ClientConstants.MANAGEMENT_PARTITION_NAME_KEY), - (long) rawdata.get(ClientConstants.MANAGEMENT_RESULT_BEGIN_SEQUENCE_NUMBER), - (long) rawdata.get(ClientConstants.MANAGEMENT_RESULT_LAST_ENQUEUED_SEQUENCE_NUMBER), - (String) rawdata.get(ClientConstants.MANAGEMENT_RESULT_LAST_ENQUEUED_OFFSET), - ((Date) rawdata.get(ClientConstants.MANAGEMENT_RESULT_LAST_ENQUEUED_TIME_UTC)).toInstant())); + (String) rawData.get(ClientConstants.MANAGEMENT_ENTITY_NAME_KEY), + (String) rawData.get(ClientConstants.MANAGEMENT_PARTITION_NAME_KEY), + (long) rawData.get(ClientConstants.MANAGEMENT_RESULT_BEGIN_SEQUENCE_NUMBER), + (long) rawData.get(ClientConstants.MANAGEMENT_RESULT_LAST_ENQUEUED_SEQUENCE_NUMBER), + (String) rawData.get(ClientConstants.MANAGEMENT_RESULT_LAST_ENQUEUED_OFFSET), + ((Date) rawData.get(ClientConstants.MANAGEMENT_RESULT_LAST_ENQUEUED_TIME_UTC)).toInstant(), + (boolean)rawData.get(ClientConstants.MANAGEMENT_RESULT_PARTITION_IS_EMPTY))); return future2; } }, this.executor); diff --git a/azure-eventhubs/src/test/java/com/microsoft/azure/eventhubs/sendrecv/RequestResponseTest.java b/azure-eventhubs/src/test/java/com/microsoft/azure/eventhubs/sendrecv/RequestResponseTest.java index b2712a6a9287..bd29b39907b6 100644 --- a/azure-eventhubs/src/test/java/com/microsoft/azure/eventhubs/sendrecv/RequestResponseTest.java +++ b/azure-eventhubs/src/test/java/com/microsoft/azure/eventhubs/sendrecv/RequestResponseTest.java @@ -204,7 +204,7 @@ public void testGetRuntimeInfos(ConnectionStringBuilder connectionString) throws Assert.assertNotNull(ehInfo); Assert.assertTrue(connectionString.getEventHubName().equalsIgnoreCase(ehInfo.getPath())); Assert.assertNotNull(ehInfo.getCreatedAt()); // creation time could be almost anything, can't really check value - Assert.assertTrue(ehInfo.getPartitionCount() >= 2); // max legal partition count is variable but 2 is hard minimum + Assert.assertTrue(ehInfo.getPartitionCount() >= 1); // max legal partition count is variable but 2 is hard minimum Assert.assertEquals(ehInfo.getPartitionIds().length, ehInfo.getPartitionCount()); /* System.out.println("Event hub name: " + ehInfo.getPath()); From 0b7ca0332294b4802962d3a47eea55dd876f982a Mon Sep 17 00:00:00 2001 From: SJ Date: Tue, 18 Dec 2018 09:47:18 -0800 Subject: [PATCH 04/42] Move setPrefetchCount API to the ReceiverOptions class from the PartitionReceiver and update the settings of Default & Max Prefetch count (#410) This pull request includes two major changes related to Prefetch API. 1) Move setPrefetchCount API to the ReceiverOptions class so that prefetch value specified by a user can be used instead of using default value when communicating to the service during link open and initializing a receiver. This change also addresses the receiver stuck issue caused by setPrefetchAPI in a race condition. 2) Change the default value and set the upper bound of the prefetch count. Note that prefetch count should be greater than or equal to maxEventCount which can be set when either a) calling receive() API or b) implementing the getMaxEventCount API of the SessionReceiverHandler interface. --- .../EventProcessorOptions.java | 14 +++++- .../eventprocessorhost/PartitionPump.java | 49 +++++++++---------- .../eventhubs/PartitionReceiveHandler.java | 1 + .../azure/eventhubs/PartitionReceiver.java | 23 ++------- .../azure/eventhubs/ReceiverOptions.java | 41 +++++++++++++++- .../azure/eventhubs/impl/MessageReceiver.java | 31 +----------- .../eventhubs/impl/PartitionReceiverImpl.java | 21 +++----- .../azure/eventhubs/impl/SessionHandler.java | 8 +-- .../eventdata/EventDataBatchTest.java | 2 +- .../SendLargeMessageTest.java | 4 +- .../WebSocketsSendLargeMessageTest.java | 9 ++-- .../proxy/ProxySendLargeMessageTest.java | 12 +++-- .../sendrecv/EventDataBatchAPITest.java | 6 +-- .../sendrecv/ReceivePumpEventHubTest.java | 4 +- .../sendrecv/SetPrefetchCountTest.java | 10 ++-- 15 files changed, 121 insertions(+), 114 deletions(-) diff --git a/azure-eventhubs-eph/src/main/java/com/microsoft/azure/eventprocessorhost/EventProcessorOptions.java b/azure-eventhubs-eph/src/main/java/com/microsoft/azure/eventprocessorhost/EventProcessorOptions.java index ece260ae84c6..e5d5ac8cce5e 100644 --- a/azure-eventhubs-eph/src/main/java/com/microsoft/azure/eventprocessorhost/EventProcessorOptions.java +++ b/azure-eventhubs-eph/src/main/java/com/microsoft/azure/eventprocessorhost/EventProcessorOptions.java @@ -6,8 +6,10 @@ package com.microsoft.azure.eventprocessorhost; import com.microsoft.azure.eventhubs.EventPosition; +import com.microsoft.azure.eventhubs.PartitionReceiver; import java.time.Duration; +import java.util.Locale; import java.util.function.Consumer; import java.util.function.Function; @@ -112,11 +114,21 @@ public int getPrefetchCount() { /*** * Sets the prefetch count for the underlying event hub client. * - * The default is 300. This controls how many events are received in advance. + * The default is 500. This controls how many events are received in advance. * * @param prefetchCount The new prefetch count. */ public void setPrefetchCount(int prefetchCount) { + if (prefetchCount < PartitionReceiver.MINIMUM_PREFETCH_COUNT) { + throw new IllegalArgumentException(String.format(Locale.US, + "PrefetchCount has to be above %s", PartitionReceiver.MINIMUM_PREFETCH_COUNT)); + } + + if (prefetchCount > PartitionReceiver.MAXIMUM_PREFETCH_COUNT) { + throw new IllegalArgumentException(String.format(Locale.US, + "PrefetchCount has to be below %s", PartitionReceiver.MAXIMUM_PREFETCH_COUNT)); + } + this.prefetchCount = prefetchCount; } diff --git a/azure-eventhubs-eph/src/main/java/com/microsoft/azure/eventprocessorhost/PartitionPump.java b/azure-eventhubs-eph/src/main/java/com/microsoft/azure/eventprocessorhost/PartitionPump.java index ecfdc4dd085e..012ec5f6996e 100644 --- a/azure-eventhubs-eph/src/main/java/com/microsoft/azure/eventprocessorhost/PartitionPump.java +++ b/azure-eventhubs-eph/src/main/java/com/microsoft/azure/eventprocessorhost/PartitionPump.java @@ -21,10 +21,10 @@ class PartitionPump extends Closable implements PartitionReceiveHandler { private static final Logger TRACE_LOGGER = LoggerFactory.getLogger(PartitionPump.class); protected final HostContext hostContext; + protected final CompleteLease lease; // protected for testability final private CompletableFuture shutdownTriggerFuture; final private CompletableFuture shutdownFinishedFuture; private final Object processingSynchronizer; - protected final CompleteLease lease; // protected for testability private final Consumer pumpManagerCallback; private EventHubClient eventHubClient = null; private PartitionReceiver partitionReceiver = null; @@ -35,8 +35,8 @@ class PartitionPump extends Closable implements PartitionReceiveHandler { private ScheduledFuture leaseRenewerFuture = null; PartitionPump(HostContext hostContext, CompleteLease lease, Closable parent, Consumer pumpManagerCallback) { - super(parent); - + super(parent); + this.hostContext = hostContext; this.lease = lease; this.pumpManagerCallback = pumpManagerCallback; @@ -44,14 +44,19 @@ class PartitionPump extends Closable implements PartitionReceiveHandler { this.partitionContext = new PartitionContext(this.hostContext, this.lease.getPartitionId()); this.partitionContext.setLease(this.lease); - + // Set up the shutdown futures. The shutdown process can be triggered just by completing this.shutdownFuture. this.shutdownTriggerFuture = new CompletableFuture(); this.shutdownFinishedFuture = this.shutdownTriggerFuture - .handleAsync((r, e) -> { this.pumpManagerCallback.accept(this.lease.getPartitionId()); return cancelPendingOperations(); }, this.hostContext.getExecutor()) + .handleAsync((r, e) -> { + this.pumpManagerCallback.accept(this.lease.getPartitionId()); + return cancelPendingOperations(); + }, this.hostContext.getExecutor()) .thenComposeAsync((empty) -> cleanUpAll(this.shutdownReason), this.hostContext.getExecutor()) .thenComposeAsync((empty) -> releaseLeaseOnShutdown(), this.hostContext.getExecutor()) - .whenCompleteAsync((empty, e) -> { setClosed(); }, this.hostContext.getExecutor()); + .whenCompleteAsync((empty, e) -> { + setClosed(); + }, this.hostContext.getExecutor()); } // The CompletableFuture returned by startPump remains uncompleted as long as the pump is running. @@ -157,11 +162,11 @@ private CompletableFuture openClientsRetryWrapper() { } protected void scheduleLeaseRenewer() { - if (!getIsClosingOrClosed()) { - int seconds = this.hostContext.getPartitionManagerOptions().getLeaseRenewIntervalInSeconds(); - this.leaseRenewerFuture = this.hostContext.getExecutor().schedule(() -> leaseRenewer(), seconds, TimeUnit.SECONDS); - TRACE_LOGGER.info(this.hostContext.withHostAndPartition(this.lease, "scheduling leaseRenewer in " + seconds)); - } + if (!getIsClosingOrClosed()) { + int seconds = this.hostContext.getPartitionManagerOptions().getLeaseRenewIntervalInSeconds(); + this.leaseRenewerFuture = this.hostContext.getExecutor().schedule(() -> leaseRenewer(), seconds, TimeUnit.SECONDS); + TRACE_LOGGER.info(this.hostContext.withHostAndPartition(this.lease, "scheduling leaseRenewer in " + seconds)); + } } private CompletableFuture openClients() { @@ -198,8 +203,6 @@ private CompletableFuture openClients() { // Stage 3: set up other receiver options, create receiver if initial offset is valid .thenComposeAsync((startAt) -> { - ReceiverOptions options = new ReceiverOptions(); - options.setReceiverRuntimeMetricEnabled(this.hostContext.getEventProcessorOptions().getReceiverRuntimeMetricEnabled()); long epoch = this.lease.getEpoch(); TRACE_LOGGER.info(this.hostContext.withHostAndPartition(this.partitionContext, @@ -208,10 +211,15 @@ private CompletableFuture openClients() { CompletableFuture receiverFuture = null; try { + ReceiverOptions options = new ReceiverOptions(); + options.setReceiverRuntimeMetricEnabled(this.hostContext.getEventProcessorOptions().getReceiverRuntimeMetricEnabled()); + options.setPrefetchCount(this.hostContext.getEventProcessorOptions().getPrefetchCount()); + receiverFuture = this.eventHubClient.createEpochReceiver(this.partitionContext.getConsumerGroupName(), this.partitionContext.getPartitionId(), startAt, epoch, options); this.internalOperationFuture = receiverFuture; } catch (EventHubException e) { + TRACE_LOGGER.error(this.hostContext.withHostAndPartition(this.partitionContext, "Opening EH receiver failed with an error "), e); receiverFuture = new CompletableFuture(); receiverFuture.completeExceptionally(e); } @@ -238,15 +246,6 @@ private CompletableFuture openClients() { // Stage 5: on success, set up the receiver .thenApplyAsync((receiver) -> { - if (this.hostContext.getEventProcessorOptions().getPrefetchCount() > PartitionReceiver.DEFAULT_PREFETCH_COUNT) - { - try { - this.partitionReceiver.setPrefetchCount(this.hostContext.getEventProcessorOptions().getPrefetchCount()); - } catch (Exception e1) { - TRACE_LOGGER.error(this.hostContext.withHostAndPartition(this.partitionContext, "PartitionReceiver failed setting prefetch count"), e1); - throw new CompletionException(e1); - } - } this.partitionReceiver.setReceiveTimeout(this.hostContext.getEventProcessorOptions().getReceiveTimeOut()); TRACE_LOGGER.info(this.hostContext.withHostAndPartition(this.partitionContext, @@ -386,8 +385,8 @@ private CompletableFuture releaseLeaseOnShutdown() // swallows all excepti } protected void internalShutdown(CloseReason reason, Throwable e) { - setClosing(); - + setClosing(); + this.shutdownReason = reason; if (e == null) { this.shutdownTriggerFuture.complete(null); @@ -412,7 +411,7 @@ private void leaseRenewer() { return; } if (getIsClosingOrClosed()) { - return; + return; } // Stage 0: renew the lease diff --git a/azure-eventhubs/src/main/java/com/microsoft/azure/eventhubs/PartitionReceiveHandler.java b/azure-eventhubs/src/main/java/com/microsoft/azure/eventhubs/PartitionReceiveHandler.java index e8028ee2af8c..e88776a8a7a9 100644 --- a/azure-eventhubs/src/main/java/com/microsoft/azure/eventhubs/PartitionReceiveHandler.java +++ b/azure-eventhubs/src/main/java/com/microsoft/azure/eventhubs/PartitionReceiveHandler.java @@ -14,6 +14,7 @@ public interface PartitionReceiveHandler { /** * Maximum number of {@link EventData} to supply while invoking {@link #onReceive(Iterable)} + *

Ensure that the value should be less than or equal to the value of {@link ReceiverOptions#getPrefetchCount()} * * @return value indicating the maximum number of {@link EventData} to supply while invoking {@link #onReceive(Iterable)} */ diff --git a/azure-eventhubs/src/main/java/com/microsoft/azure/eventhubs/PartitionReceiver.java b/azure-eventhubs/src/main/java/com/microsoft/azure/eventhubs/PartitionReceiver.java index 979382f0d8a3..83912309702a 100644 --- a/azure-eventhubs/src/main/java/com/microsoft/azure/eventhubs/PartitionReceiver.java +++ b/azure-eventhubs/src/main/java/com/microsoft/azure/eventhubs/PartitionReceiver.java @@ -24,8 +24,9 @@ */ public interface PartitionReceiver { - int MINIMUM_PREFETCH_COUNT = 10; - int DEFAULT_PREFETCH_COUNT = 999; + int MINIMUM_PREFETCH_COUNT = 1; + int DEFAULT_PREFETCH_COUNT = 500; + int MAXIMUM_PREFETCH_COUNT = 2000; long NULL_EPOCH = 0; @@ -36,23 +37,6 @@ public interface PartitionReceiver { */ String getPartitionId(); - /** - * Get Prefetch Count configured on the Receiver. - * - * @return the upper limit of events this receiver will actively receive regardless of whether a receive operation is pending. - * @see #setPrefetchCount - */ - int getPrefetchCount(); - - /** - * Set the number of events that can be pre-fetched and cached at the {@link PartitionReceiver}. - *

By default the value is 300 - * - * @param prefetchCount the number of events to pre-fetch. value must be between 10 and 999. Default is 300. - * @throws EventHubException if setting prefetchCount encounters error - */ - void setPrefetchCount(final int prefetchCount) throws EventHubException; - Duration getReceiveTimeout(); void setReceiveTimeout(Duration value); @@ -81,6 +65,7 @@ public interface PartitionReceiver { /** * Get the {@link EventPosition} that corresponds to an {@link EventData} which was returned last by the receiver. *

This value will not be populated, unless the knob {@link ReceiverOptions#setReceiverRuntimeMetricEnabled(boolean)} is set. + * Note that EventPosition object is initialized using SequenceNumber and other parameters are not set and get will return null. * * @return the EventPosition object. */ diff --git a/azure-eventhubs/src/main/java/com/microsoft/azure/eventhubs/ReceiverOptions.java b/azure-eventhubs/src/main/java/com/microsoft/azure/eventhubs/ReceiverOptions.java index b98f76a222c7..d5cdf6307137 100644 --- a/azure-eventhubs/src/main/java/com/microsoft/azure/eventhubs/ReceiverOptions.java +++ b/azure-eventhubs/src/main/java/com/microsoft/azure/eventhubs/ReceiverOptions.java @@ -6,6 +6,8 @@ import com.microsoft.azure.eventhubs.impl.ClientConstants; +import java.util.Locale; + /** * Represents various optional behaviors which can be turned on or off during the creation of a {@link PartitionReceiver}. */ @@ -13,6 +15,11 @@ public final class ReceiverOptions { private boolean receiverRuntimeMetricEnabled; private String identifier; + private int prefetchCount; + + public ReceiverOptions() { + this.prefetchCount = PartitionReceiver.DEFAULT_PREFETCH_COUNT; + } private static void validateReceiverIdentifier(final String receiverName) { @@ -37,7 +44,8 @@ public boolean getReceiverRuntimeMetricEnabled() { /** * Knob to enable/disable runtime metric of the receiver. If this is set to true and is passed to {@link EventHubClient#createReceiver}, - * after the first {@link PartitionReceiver#receive(int)} call, {@link PartitionReceiver#getRuntimeInformation()} is populated. + * after the first {@link PartitionReceiver#receive(int)} call, {@link PartitionReceiver#getRuntimeInformation()} and + * {@link PartitionReceiver#getEventPosition()} will be populated. *

* This knob facilitates for an optimization where the Consumer of Event Hub has the end of stream details at the disposal, * without making any additional {@link EventHubClient#getPartitionRuntimeInformation(String)} call to Event Hubs service. @@ -81,4 +89,35 @@ public void setIdentifier(final String value) { ReceiverOptions.validateReceiverIdentifier(value); this.identifier = value; } + + /** + * Get Prefetch Count. + * + * @return the upper limit of events this receiver will actively receive regardless of whether a receive operation is pending. + * @see #setPrefetchCount + */ + public int getPrefetchCount() { + return this.prefetchCount; + } + + /** + * Set the number of events that can be pre-fetched and cached at the {@link PartitionReceiver}. + *

By default the value is 500 + * + * @param prefetchCount the number of events to pre-fetch. value must be between 1 and 2000. + * @throws EventHubException if setting prefetchCount encounters error + */ + public void setPrefetchCount(final int prefetchCount) throws EventHubException { + if (prefetchCount < PartitionReceiver.MINIMUM_PREFETCH_COUNT) { + throw new IllegalArgumentException(String.format(Locale.US, + "PrefetchCount has to be above %s", PartitionReceiver.MINIMUM_PREFETCH_COUNT)); + } + + if (prefetchCount > PartitionReceiver.MAXIMUM_PREFETCH_COUNT) { + throw new IllegalArgumentException(String.format(Locale.US, + "PrefetchCount has to be below %s", PartitionReceiver.MAXIMUM_PREFETCH_COUNT)); + } + + this.prefetchCount = prefetchCount; + } } diff --git a/azure-eventhubs/src/main/java/com/microsoft/azure/eventhubs/impl/MessageReceiver.java b/azure-eventhubs/src/main/java/com/microsoft/azure/eventhubs/impl/MessageReceiver.java index bc5c00351455..ba78cc0fe62f 100644 --- a/azure-eventhubs/src/main/java/com/microsoft/azure/eventhubs/impl/MessageReceiver.java +++ b/azure-eventhubs/src/main/java/com/microsoft/azure/eventhubs/impl/MessageReceiver.java @@ -52,7 +52,6 @@ public final class MessageReceiver extends ClientEntity implements AmqpReceiver, private final Runnable onOperationTimedout; private final Duration operationTimeout; private final CompletableFuture linkClose; - private final Object prefetchCountSync; private final ReceiverSettingsProvider settingsProvider; private final String tokenAudience; private final ActiveClientTokenManager activeClientTokenManager; @@ -87,7 +86,6 @@ private MessageReceiver(final MessagingFactory factory, this.linkClose = new CompletableFuture<>(); this.lastKnownLinkError = null; this.receiveTimeout = factory.getOperationTimeout(); - this.prefetchCountSync = new Object(); this.settingsProvider = settingsProvider; this.linkOpen = new WorkItem<>(new CompletableFuture<>(), factory.getOperationTimeout()); this.timer = new Timer(factory); @@ -234,31 +232,6 @@ private List receiveCore(final int messageCount) { return returnMessages; } - public int getPrefetchCount() { - synchronized (this.prefetchCountSync) { - return this.prefetchCount; - } - } - - public void setPrefetchCount(final int value) throws EventHubException { - final int deltaPrefetchCount; - synchronized (this.prefetchCountSync) { - deltaPrefetchCount = value - this.prefetchCount; - this.prefetchCount = value; - } - - try { - this.underlyingFactory.scheduleOnReactorThread(new DispatchHandler() { - @Override - public void onEvent() { - sendFlow(deltaPrefetchCount); - } - }); - } catch (IOException | RejectedExecutionException schedulerException) { - throw new EventHubException(false, "Setting prefetch count failed, see cause for more details", schedulerException); - } - } - public Duration getReceiveTimeout() { return this.receiveTimeout; } @@ -274,8 +247,8 @@ public CompletableFuture> receive(final int maxMessageCount) if (maxMessageCount <= 0 || maxMessageCount > this.prefetchCount) { onReceive.completeExceptionally(new IllegalArgumentException(String.format( Locale.US, - "parameter 'maxMessageCount' should be a positive number and should be less than prefetchCount(%s)", - this.prefetchCount))); + "maxEventCount(%s) should be a positive number and should be less than prefetchCount(%s)", + maxMessageCount, this.prefetchCount))); return onReceive; } diff --git a/azure-eventhubs/src/main/java/com/microsoft/azure/eventhubs/impl/PartitionReceiverImpl.java b/azure-eventhubs/src/main/java/com/microsoft/azure/eventhubs/impl/PartitionReceiverImpl.java index ed8fcde51328..e3569534a2e5 100644 --- a/azure-eventhubs/src/main/java/com/microsoft/azure/eventhubs/impl/PartitionReceiverImpl.java +++ b/azure-eventhubs/src/main/java/com/microsoft/azure/eventhubs/impl/PartitionReceiverImpl.java @@ -71,7 +71,7 @@ static CompletableFuture create(MessagingFactory factory, final EventPosition eventPosition, final long epoch, final boolean isEpochReceiver, - final ReceiverOptions receiverOptions, + ReceiverOptions receiverOptions, final Executor executor) throws EventHubException { if (epoch < NULL_EPOCH) { @@ -82,6 +82,10 @@ static CompletableFuture create(MessagingFactory factory, throw new IllegalArgumentException("specify valid string for argument - 'consumerGroupName'"); } + if (receiverOptions == null) { + receiverOptions = new ReceiverOptions(); + } + final PartitionReceiverImpl receiver = new PartitionReceiverImpl(factory, eventHubName, consumerGroupName, partitionId, (EventPositionImpl) eventPosition, epoch, isEpochReceiver, receiverOptions, executor); return receiver.createInternalReceiver().thenApplyAsync(new Function() { public PartitionReceiver apply(Void a) { @@ -94,7 +98,7 @@ private CompletableFuture createInternalReceiver() { return MessageReceiver.create(this.underlyingFactory, StringUtil.getRandomString(), String.format("%s/ConsumerGroups/%s/Partitions/%s", this.eventHubName, this.consumerGroupName, this.partitionId), - PartitionReceiverImpl.DEFAULT_PREFETCH_COUNT, this) + this.receiverOptions.getPrefetchCount(), this) .thenAcceptAsync(new Consumer() { public void accept(MessageReceiver r) { PartitionReceiverImpl.this.internalReceiver = r; @@ -110,19 +114,6 @@ public final String getPartitionId() { return this.partitionId; } - public final int getPrefetchCount() { - return this.internalReceiver.getPrefetchCount(); - } - - public final void setPrefetchCount(final int prefetchCount) throws EventHubException { - if (prefetchCount < PartitionReceiverImpl.MINIMUM_PREFETCH_COUNT) { - throw new IllegalArgumentException(String.format(Locale.US, - "PrefetchCount has to be above %s", PartitionReceiverImpl.MINIMUM_PREFETCH_COUNT)); - } - - this.internalReceiver.setPrefetchCount(prefetchCount); - } - public final Duration getReceiveTimeout() { return this.internalReceiver.getReceiveTimeout(); } diff --git a/azure-eventhubs/src/main/java/com/microsoft/azure/eventhubs/impl/SessionHandler.java b/azure-eventhubs/src/main/java/com/microsoft/azure/eventhubs/impl/SessionHandler.java index 0e1c062bbdad..a5c65372f790 100644 --- a/azure-eventhubs/src/main/java/com/microsoft/azure/eventhubs/impl/SessionHandler.java +++ b/azure-eventhubs/src/main/java/com/microsoft/azure/eventhubs/impl/SessionHandler.java @@ -75,7 +75,7 @@ public void onSessionLocalOpen(Event e) { @Override public void onSessionRemoteOpen(Event e) { if (TRACE_LOGGER.isInfoEnabled()) { - TRACE_LOGGER.info(String.format(Locale.US, "entityName[%s], sessionIncCapacity[%s], sessionOutgoingWindow[%s]", + TRACE_LOGGER.info(String.format(Locale.US, "onSessionRemoteOpen entityName[%s], sessionIncCapacity[%s], sessionOutgoingWindow[%s]", this.entityName, e.getSession().getIncomingCapacity(), e.getSession().getOutgoingWindow())); } @@ -93,7 +93,7 @@ public void onSessionRemoteOpen(Event e) { @Override public void onSessionLocalClose(Event e) { if (TRACE_LOGGER.isInfoEnabled()) { - TRACE_LOGGER.info(String.format(Locale.US, "entityName[%s], condition[%s]", this.entityName, + TRACE_LOGGER.info(String.format(Locale.US, "onSessionLocalClose entityName[%s], condition[%s]", this.entityName, e.getSession().getCondition() == null ? "none" : e.getSession().getCondition().toString())); } } @@ -101,7 +101,7 @@ public void onSessionLocalClose(Event e) { @Override public void onSessionRemoteClose(Event e) { if (TRACE_LOGGER.isInfoEnabled()) { - TRACE_LOGGER.info(String.format(Locale.US, "entityName[%s], condition[%s]", this.entityName, + TRACE_LOGGER.info(String.format(Locale.US, "onSessionRemoteClose entityName[%s], condition[%s]", this.entityName, e.getSession().getRemoteCondition() == null ? "none" : e.getSession().getRemoteCondition().toString())); } @@ -118,7 +118,7 @@ public void onSessionRemoteClose(Event e) { @Override public void onSessionFinal(Event e) { if (TRACE_LOGGER.isInfoEnabled()) { - TRACE_LOGGER.info(String.format(Locale.US, "entityName[%s]", this.entityName)); + TRACE_LOGGER.info(String.format(Locale.US, "onSessionFinal entityName[%s]", this.entityName)); } } diff --git a/azure-eventhubs/src/test/java/com/microsoft/azure/eventhubs/eventdata/EventDataBatchTest.java b/azure-eventhubs/src/test/java/com/microsoft/azure/eventhubs/eventdata/EventDataBatchTest.java index 2c04edec6305..fcc7b71b3bab 100644 --- a/azure-eventhubs/src/test/java/com/microsoft/azure/eventhubs/eventdata/EventDataBatchTest.java +++ b/azure-eventhubs/src/test/java/com/microsoft/azure/eventhubs/eventdata/EventDataBatchTest.java @@ -25,7 +25,7 @@ public void payloadExceededException() throws EventHubException, IOException { final EventDataBatch batch = ehClient.createBatch(); final EventData within = EventData.create(new byte[1024]); - final EventData tooBig = EventData.create(new byte[1024 * 500]); + final EventData tooBig = EventData.create(new byte[1024 * 1024 * 2]); Assert.assertTrue(batch.tryAdd(within)); batch.tryAdd(tooBig); diff --git a/azure-eventhubs/src/test/java/com/microsoft/azure/eventhubs/exceptioncontracts/SendLargeMessageTest.java b/azure-eventhubs/src/test/java/com/microsoft/azure/eventhubs/exceptioncontracts/SendLargeMessageTest.java index 7dc2f4b800ff..b5cccf85c9b4 100644 --- a/azure-eventhubs/src/test/java/com/microsoft/azure/eventhubs/exceptioncontracts/SendLargeMessageTest.java +++ b/azure-eventhubs/src/test/java/com/microsoft/azure/eventhubs/exceptioncontracts/SendLargeMessageTest.java @@ -56,8 +56,8 @@ public void sendMsgLargerThan64k() throws EventHubException, InterruptedExceptio } @Test(expected = PayloadSizeExceededException.class) - public void sendMsgLargerThan256K() throws EventHubException, InterruptedException, ExecutionException, IOException { - int msgSize = 256 * 1024; + public void sendMsgLargerThan1024K() throws EventHubException, InterruptedException, ExecutionException, IOException { + int msgSize = 1024 * 1024 * 2; byte[] body = new byte[msgSize]; for (int i = 0; i < msgSize; i++) { body[i] = 1; diff --git a/azure-eventhubs/src/test/java/com/microsoft/azure/eventhubs/exceptioncontracts/WebSocketsSendLargeMessageTest.java b/azure-eventhubs/src/test/java/com/microsoft/azure/eventhubs/exceptioncontracts/WebSocketsSendLargeMessageTest.java index c0fa5edd5795..71b6b12f5969 100644 --- a/azure-eventhubs/src/test/java/com/microsoft/azure/eventhubs/exceptioncontracts/WebSocketsSendLargeMessageTest.java +++ b/azure-eventhubs/src/test/java/com/microsoft/azure/eventhubs/exceptioncontracts/WebSocketsSendLargeMessageTest.java @@ -4,7 +4,10 @@ */ package com.microsoft.azure.eventhubs.exceptioncontracts; -import com.microsoft.azure.eventhubs.*; +import com.microsoft.azure.eventhubs.ConnectionStringBuilder; +import com.microsoft.azure.eventhubs.EventHubException; +import com.microsoft.azure.eventhubs.PayloadSizeExceededException; +import com.microsoft.azure.eventhubs.TransportType; import com.microsoft.azure.eventhubs.lib.ApiTestBase; import com.microsoft.azure.eventhubs.lib.TestContext; import org.junit.AfterClass; @@ -36,8 +39,8 @@ public void sendMsgLargerThan64k() throws EventHubException, InterruptedExceptio } @Test(expected = PayloadSizeExceededException.class) - public void sendMsgLargerThan256K() throws EventHubException, InterruptedException, ExecutionException, IOException { - sendLargeMessageTest.sendMsgLargerThan256K(); + public void sendMsgLargerThan1024K() throws EventHubException, InterruptedException, ExecutionException, IOException { + sendLargeMessageTest.sendMsgLargerThan1024K(); } @Test() diff --git a/azure-eventhubs/src/test/java/com/microsoft/azure/eventhubs/proxy/ProxySendLargeMessageTest.java b/azure-eventhubs/src/test/java/com/microsoft/azure/eventhubs/proxy/ProxySendLargeMessageTest.java index 5caa1b77b9cc..ec8f94b67980 100644 --- a/azure-eventhubs/src/test/java/com/microsoft/azure/eventhubs/proxy/ProxySendLargeMessageTest.java +++ b/azure-eventhubs/src/test/java/com/microsoft/azure/eventhubs/proxy/ProxySendLargeMessageTest.java @@ -4,14 +4,17 @@ */ package com.microsoft.azure.eventhubs.proxy; -import com.microsoft.azure.eventhubs.*; +import com.microsoft.azure.eventhubs.ConnectionStringBuilder; +import com.microsoft.azure.eventhubs.EventHubException; +import com.microsoft.azure.eventhubs.PayloadSizeExceededException; +import com.microsoft.azure.eventhubs.TransportType; import com.microsoft.azure.eventhubs.exceptioncontracts.SendLargeMessageTest; import com.microsoft.azure.eventhubs.lib.ApiTestBase; import com.microsoft.azure.eventhubs.lib.TestContext; -import org.jutils.jproxy.ProxyServer; import org.junit.AfterClass; import org.junit.BeforeClass; import org.junit.Test; +import org.jutils.jproxy.ProxyServer; import java.io.IOException; import java.net.*; @@ -28,7 +31,8 @@ public class ProxySendLargeMessageTest extends ApiTestBase { @BeforeClass public static void initialize() throws Exception { proxyServer = ProxyServer.create("localhost", proxyPort); - proxyServer.start(t -> {}); + proxyServer.start(t -> { + }); defaultProxySelector = ProxySelector.getDefault(); ProxySelector.setDefault(new ProxySelector() { @@ -69,7 +73,7 @@ public void sendMsgLargerThan64k() throws EventHubException, InterruptedExceptio @Test(expected = PayloadSizeExceededException.class) public void sendMsgLargerThan256K() throws EventHubException, InterruptedException, ExecutionException, IOException { - sendLargeMessageTest.sendMsgLargerThan256K(); + sendLargeMessageTest.sendMsgLargerThan1024K(); } @Test() diff --git a/azure-eventhubs/src/test/java/com/microsoft/azure/eventhubs/sendrecv/EventDataBatchAPITest.java b/azure-eventhubs/src/test/java/com/microsoft/azure/eventhubs/sendrecv/EventDataBatchAPITest.java index e61f47abc840..cd4b94ccd262 100644 --- a/azure-eventhubs/src/test/java/com/microsoft/azure/eventhubs/sendrecv/EventDataBatchAPITest.java +++ b/azure-eventhubs/src/test/java/com/microsoft/azure/eventhubs/sendrecv/EventDataBatchAPITest.java @@ -20,8 +20,8 @@ import java.util.UUID; import java.util.concurrent.CompletableFuture; import java.util.concurrent.ExecutionException; -import java.util.concurrent.TimeoutException; import java.util.concurrent.TimeUnit; +import java.util.concurrent.TimeoutException; import java.util.concurrent.atomic.AtomicInteger; import java.util.function.Consumer; @@ -153,7 +153,7 @@ public void sendEventsFullBatchWithAppPropsTest() int count = 0; while (true) { - final EventData eventData = EventData.create(new String(new char[new Random().nextInt(50000)]).replace("\0", "a").getBytes()); + final EventData eventData = EventData.create(new String(new char[50000]).replace("\0", "a").getBytes()); for (int i = 0; i < new Random().nextInt(20); i++) eventData.getProperties().put("somekey" + i, "somevalue"); @@ -241,7 +241,7 @@ public CountValidator(final CompletableFuture validateSignal, final int ne @Override public int getMaxEventCount() { - return 999; + return PartitionReceiver.DEFAULT_PREFETCH_COUNT; } @Override diff --git a/azure-eventhubs/src/test/java/com/microsoft/azure/eventhubs/sendrecv/ReceivePumpEventHubTest.java b/azure-eventhubs/src/test/java/com/microsoft/azure/eventhubs/sendrecv/ReceivePumpEventHubTest.java index 49c94af920be..9383cfbd44ee 100644 --- a/azure-eventhubs/src/test/java/com/microsoft/azure/eventhubs/sendrecv/ReceivePumpEventHubTest.java +++ b/azure-eventhubs/src/test/java/com/microsoft/azure/eventhubs/sendrecv/ReceivePumpEventHubTest.java @@ -69,10 +69,8 @@ public void testInvokeOnTimeoutKnobTrue() throws EventHubException, InterruptedE @Test(expected = IllegalArgumentException.class) public void testInvokeWithInvalidArgs() throws Throwable { final CompletableFuture invokeSignal = new CompletableFuture(); - final int prefetchCount = 1000; receiver.setReceiveTimeout(Duration.ofSeconds(1)); - receiver.setPrefetchCount(prefetchCount); - receiver.setReceiveHandler(new InvokeOnReceiveEventValidator(invokeSignal, prefetchCount + 1), true); + receiver.setReceiveHandler(new InvokeOnReceiveEventValidator(invokeSignal, PartitionReceiver.DEFAULT_PREFETCH_COUNT + 1), true); try { invokeSignal.get(3, TimeUnit.SECONDS); } catch (ExecutionException executionException) { diff --git a/azure-eventhubs/src/test/java/com/microsoft/azure/eventhubs/sendrecv/SetPrefetchCountTest.java b/azure-eventhubs/src/test/java/com/microsoft/azure/eventhubs/sendrecv/SetPrefetchCountTest.java index e55c1d47821c..1a39f3ab353a 100644 --- a/azure-eventhubs/src/test/java/com/microsoft/azure/eventhubs/sendrecv/SetPrefetchCountTest.java +++ b/azure-eventhubs/src/test/java/com/microsoft/azure/eventhubs/sendrecv/SetPrefetchCountTest.java @@ -39,8 +39,9 @@ public static void cleanup() throws EventHubException { @Test() public void testSetPrefetchCountToLargeValue() throws EventHubException { - testReceiver = ehClient.createReceiverSync(CONSUMER_GROUP_NAME, PARTITION_ID, EventPosition.fromStartOfStream()); - testReceiver.setPrefetchCount(100000); + ReceiverOptions options = new ReceiverOptions(); + options.setPrefetchCount(2000); + testReceiver = ehClient.createReceiverSync(CONSUMER_GROUP_NAME, PARTITION_ID, EventPosition.fromStartOfStream(), options); testReceiver.setReceiveTimeout(Duration.ofSeconds(2)); int eventsReceived = 0; int retryCount = 0; @@ -58,8 +59,9 @@ public void testSetPrefetchCountToLargeValue() throws EventHubException { @Test() public void testSetPrefetchCountToSmallValue() throws EventHubException { - testReceiver = ehClient.createReceiverSync(CONSUMER_GROUP_NAME, PARTITION_ID, EventPosition.fromStartOfStream()); - testReceiver.setPrefetchCount(11); + ReceiverOptions options = new ReceiverOptions(); + options.setPrefetchCount(11); + testReceiver = ehClient.createReceiverSync(CONSUMER_GROUP_NAME, PARTITION_ID, EventPosition.fromStartOfStream(), options); testReceiver.setReceiveTimeout(Duration.ofSeconds(2)); int eventsReceived = 0; int retryCount = 0; From d1b68d18403ba47ed8c0ae726dccd44449b3d6d8 Mon Sep 17 00:00:00 2001 From: SJ Date: Fri, 21 Dec 2018 00:30:59 -0800 Subject: [PATCH 05/42] Fixes several issues in the reactor related components (#411) This pull request contains the following changes. 1) Finish pending tasks when recreating the reactor and make sure pending calls scheduled on the old reactor get complete. 2) Fix the session open timeout issue which can result in NPE in proton-J engine. 3) Make session open timeout configurable and use the value of OperationTimeout. 4) Update the message of exceptions and include an entity name in the exception message. 5) API change - use ScheduledExecutorService. 6) Improve tracing. --- ConsumingEvents.md | 4 +- Overview.md | 4 +- PublishingEvents.md | 2 +- .../eventprocessorhost/PartitionManager.java | 56 ++--- .../eventprocessorhost/PartitionPump.java | 2 +- .../eventprocessorhost/TestUtilities.java | 26 +-- .../extensions/appender/EventHubsManager.java | 8 +- .../AuthorizationFailedException.java | 4 +- .../microsoft/azure/eventhubs/EventData.java | 8 +- .../azure/eventhubs/EventHubClient.java | 23 +- .../azure/eventhubs/PartitionSender.java | 4 +- .../azure/eventhubs/impl/BaseLinkHandler.java | 18 +- .../azure/eventhubs/impl/ClientConstants.java | 1 - .../azure/eventhubs/impl/ClientEntity.java | 6 +- .../eventhubs/impl/ConnectionHandler.java | 89 +++++--- .../azure/eventhubs/impl/CustomIOHandler.java | 12 +- .../eventhubs/impl/EventHubClientImpl.java | 14 +- .../azure/eventhubs/impl/MessageReceiver.java | 71 +++--- .../azure/eventhubs/impl/MessageSender.java | 98 +++++---- .../eventhubs/impl/MessagingFactory.java | 208 +++++++++++------- .../eventhubs/impl/PartitionReceiverImpl.java | 13 +- .../eventhubs/impl/PartitionSenderImpl.java | 10 +- .../eventhubs/impl/ReactorDispatcher.java | 14 +- .../eventhubs/impl/ReceiveLinkHandler.java | 18 +- .../azure/eventhubs/impl/ReceivePump.java | 51 +++-- .../eventhubs/impl/SchedulerProvider.java | 2 +- .../azure/eventhubs/impl/SendLinkHandler.java | 21 +- .../azure/eventhubs/impl/SessionHandler.java | 57 +++-- .../microsoft/azure/eventhubs/impl/Timer.java | 2 +- .../concurrency/EventHubClientTest.java | 6 +- .../eventdata/EventDataBatchTest.java | 2 +- .../MsgFactoryOpenCloseTest.java | 44 ++-- .../exceptioncontracts/ReactorFaultTest.java | 44 ++-- .../azure/eventhubs/lib/TestContext.java | 6 +- .../eventhubs/sendrecv/ReceivePumpTest.java | 4 + .../sendrecv/RequestResponseTest.java | 2 +- 36 files changed, 557 insertions(+), 397 deletions(-) diff --git a/ConsumingEvents.md b/ConsumingEvents.md index 96a85b38370e..d1c853e86446 100644 --- a/ConsumingEvents.md +++ b/ConsumingEvents.md @@ -42,11 +42,11 @@ For a simple event consumer, you'll need to import the *com.microsoft.azure.even Event Hubs client library uses qpid proton reactor framework which exposes AMQP connection and message delivery related state transitions as reactive events. In the process, the library will need to run many asynchronous tasks while sending and receiving messages to Event Hubs. -So, `EventHubClient` requires an instance of `Executor`, where all these tasks are run. +So, `EventHubClient` requires an instance of `ScheduledExecutorService`, where all these tasks are run. ```Java - ExecutorService executor = Executors.newCachedThreadPool(); + ScheduledExecutorService executor = Executors.newScheduledThreadPool(8) ``` The receiver code creates an *EventHubClient* from a given connecting string diff --git a/Overview.md b/Overview.md index 12c18071afa3..b6ac2d2da761 100644 --- a/Overview.md +++ b/Overview.md @@ -36,11 +36,11 @@ which is quite simple in a Maven build [as we explain in the guide](PublishingEv Event Hubs client library uses qpid proton reactor framework which exposes AMQP connection and message delivery related state transitions as reactive events. In the process, the library will need to run many asynchronous tasks while sending and receiving messages to Event Hubs. -So, `EventHubClient` requires an instance of `Executor`, where all these tasks are run. +So, `EventHubClient` requires an instance of `ScheduledExecutorService`, where all these tasks are run. ```Java - ExecutorService executor = Executors.newCachedThreadPool(); + ScheduledExecutorService executor = Executors.newScheduledThreadPool(8) ``` Using an Event Hub connection string, which holds all required connection information, including an authorization key or token, diff --git a/PublishingEvents.md b/PublishingEvents.md index 36a684a5ef13..20c3bb58cd3b 100644 --- a/PublishingEvents.md +++ b/PublishingEvents.md @@ -34,7 +34,7 @@ So, `EventHubClient` requires an instance of `Executor`, where all these tasks a ```Java - ExecutorService executor = Executors.newCachedThreadPool(); + ScheduledExecutorService executor = Executors.newScheduledThreadPool(8) ``` Using an Event Hub connection string, which holds all required connection information including an authorization key or token diff --git a/azure-eventhubs-eph/src/main/java/com/microsoft/azure/eventprocessorhost/PartitionManager.java b/azure-eventhubs-eph/src/main/java/com/microsoft/azure/eventprocessorhost/PartitionManager.java index 66593349cb0a..ffad0a9de930 100644 --- a/azure-eventhubs-eph/src/main/java/com/microsoft/azure/eventprocessorhost/PartitionManager.java +++ b/azure-eventhubs-eph/src/main/java/com/microsoft/azure/eventprocessorhost/PartitionManager.java @@ -27,7 +27,7 @@ class PartitionManager extends Closable { private ScheduledFuture scanFuture = null; PartitionManager(HostContext hostContext) { - super(null); + super(null); this.hostContext = hostContext; } @@ -41,17 +41,17 @@ CompletableFuture cachePartitionIds() { // EventHubException or IOException, in addition to whatever failures may occur when the result of // the CompletableFuture is evaluated. try { - final CompletableFuture cleanupFuture = new CompletableFuture(); - + final CompletableFuture cleanupFuture = new CompletableFuture(); + // Stage 0A: get EventHubClient for the event hub retval = EventHubClient.create(this.hostContext.getEventHubConnectionString(), this.hostContext.getRetryPolicy(), this.hostContext.getExecutor()) - // Stage 0B: set up a way to close the EventHubClient when we're done - .thenApplyAsync((ehClient) -> - { - final EventHubClient saveForCleanupClient = ehClient; - cleanupFuture.thenComposeAsync((empty) -> saveForCleanupClient.close(), this.hostContext.getExecutor()); - return ehClient; - }, this.hostContext.getExecutor()) + // Stage 0B: set up a way to close the EventHubClient when we're done + .thenApplyAsync((ehClient) -> + { + final EventHubClient saveForCleanupClient = ehClient; + cleanupFuture.thenComposeAsync((empty) -> saveForCleanupClient.close(), this.hostContext.getExecutor()); + return ehClient; + }, this.hostContext.getExecutor()) // Stage 1: use the client to get runtime info for the event hub .thenComposeAsync((ehClient) -> ehClient.getRuntimeInformation(), this.hostContext.getExecutor()) // Stage 2: extract the partition ids from the runtime info or throw on null (timeout) @@ -71,7 +71,7 @@ CompletableFuture cachePartitionIds() { // Stage 3: RUN REGARDLESS OF EXCEPTIONS -- if there was an error, wrap it in IllegalEntityException and throw .handleAsync((empty, e) -> { - cleanupFuture.complete(null); // trigger client cleanup + cleanupFuture.complete(null); // trigger client cleanup if (e != null) { Throwable notifyWith = e; if (e instanceof CompletionException) { @@ -104,8 +104,8 @@ void onPartitionCheckCompleteTestHook() { } CompletableFuture stopPartitions() { - setClosing(); - + setClosing(); + // If the lease scanner is between runs, cancel so it doesn't run again. synchronized (this.scanFutureSynchronizer) { if (this.scanFuture != null) { @@ -119,20 +119,20 @@ CompletableFuture stopPartitions() { if (this.pumpManager != null) { TRACE_LOGGER.info(this.hostContext.withHost("Shutting down all pumps")); stopping = this.pumpManager.removeAllPumps(CloseReason.Shutdown) - .whenCompleteAsync((empty, e) -> { - if (e != null) { - Throwable notifyWith = LoggingUtils.unwrapException(e, null); - TRACE_LOGGER.warn(this.hostContext.withHost("Failure during shutdown"), notifyWith); - if (notifyWith instanceof Exception) { - this.hostContext.getEventProcessorOptions().notifyOfException(this.hostContext.getHostName(), (Exception) notifyWith, - EventProcessorHostActionStrings.PARTITION_MANAGER_CLEANUP); + .whenCompleteAsync((empty, e) -> { + if (e != null) { + Throwable notifyWith = LoggingUtils.unwrapException(e, null); + TRACE_LOGGER.warn(this.hostContext.withHost("Failure during shutdown"), notifyWith); + if (notifyWith instanceof Exception) { + this.hostContext.getEventProcessorOptions().notifyOfException(this.hostContext.getHostName(), (Exception) notifyWith, + EventProcessorHostActionStrings.PARTITION_MANAGER_CLEANUP); - } - } - }, this.hostContext.getExecutor()); + } + } + }, this.hostContext.getExecutor()); } // else no pumps to shut down - + stopping = stopping.whenCompleteAsync((empty, e) -> { TRACE_LOGGER.info(this.hostContext.withHost("Partition manager exiting")); setClosed(); @@ -287,14 +287,14 @@ private CompletableFuture buildRetries(CompletableFuture buildOnto, Callab // Return Void so it can be called from a lambda. // throwOnFailure is true private Void scan(boolean isFirst) { - TRACE_LOGGER.info(this.hostContext.withHost("Starting lease scan")); + TRACE_LOGGER.debug(this.hostContext.withHost("Starting lease scan")); long start = System.currentTimeMillis(); (new PartitionScanner(this.hostContext, (lease) -> this.pumpManager.addPump(lease), this)).scan(isFirst) .whenCompleteAsync((didSteal, e) -> { TRACE_LOGGER.debug(this.hostContext.withHost("Scanning took " + (System.currentTimeMillis() - start))); - + onPartitionCheckCompleteTestHook(); // Schedule the next scan unless we are shutting down. @@ -305,11 +305,11 @@ private Void scan(boolean isFirst) { seconds = this.hostContext.getPartitionManagerOptions().getStartupScanDelayInSeconds(); } synchronized (this.scanFutureSynchronizer) { - this.scanFuture = this.hostContext.getExecutor().schedule(() -> scan(false), seconds, TimeUnit.SECONDS); + this.scanFuture = this.hostContext.getExecutor().schedule(() -> scan(false), seconds, TimeUnit.SECONDS); } TRACE_LOGGER.debug(this.hostContext.withHost("Scheduling lease scanner in " + seconds)); } else { - TRACE_LOGGER.debug(this.hostContext.withHost("Not scheduling lease scanner due to shutdown")); + TRACE_LOGGER.debug(this.hostContext.withHost("Not scheduling lease scanner due to shutdown")); } }, this.hostContext.getExecutor()); diff --git a/azure-eventhubs-eph/src/main/java/com/microsoft/azure/eventprocessorhost/PartitionPump.java b/azure-eventhubs-eph/src/main/java/com/microsoft/azure/eventprocessorhost/PartitionPump.java index 012ec5f6996e..fcdbe9abd853 100644 --- a/azure-eventhubs-eph/src/main/java/com/microsoft/azure/eventprocessorhost/PartitionPump.java +++ b/azure-eventhubs-eph/src/main/java/com/microsoft/azure/eventprocessorhost/PartitionPump.java @@ -165,7 +165,7 @@ protected void scheduleLeaseRenewer() { if (!getIsClosingOrClosed()) { int seconds = this.hostContext.getPartitionManagerOptions().getLeaseRenewIntervalInSeconds(); this.leaseRenewerFuture = this.hostContext.getExecutor().schedule(() -> leaseRenewer(), seconds, TimeUnit.SECONDS); - TRACE_LOGGER.info(this.hostContext.withHostAndPartition(this.lease, "scheduling leaseRenewer in " + seconds)); + TRACE_LOGGER.debug(this.hostContext.withHostAndPartition(this.lease, "scheduling leaseRenewer in " + seconds)); } } diff --git a/azure-eventhubs-eph/src/test/java/com/microsoft/azure/eventprocessorhost/TestUtilities.java b/azure-eventhubs-eph/src/test/java/com/microsoft/azure/eventprocessorhost/TestUtilities.java index e90ef85ec644..d0466a6b4865 100644 --- a/azure-eventhubs-eph/src/test/java/com/microsoft/azure/eventprocessorhost/TestUtilities.java +++ b/azure-eventhubs-eph/src/test/java/com/microsoft/azure/eventprocessorhost/TestUtilities.java @@ -7,35 +7,35 @@ import org.junit.Assume; -import java.util.concurrent.ExecutorService; import java.util.concurrent.Executors; +import java.util.concurrent.ScheduledExecutorService; final class TestUtilities { - static final ExecutorService EXECUTOR_SERVICE = Executors.newSingleThreadExecutor(); - + static final ScheduledExecutorService EXECUTOR_SERVICE = Executors.newScheduledThreadPool(1); + static void skipIfAppveyor() { - String appveyor = System.getenv("APPVEYOR"); // Set to "true" by Appveyor - if (appveyor != null) { - TestBase.logInfo("SKIPPING - APPVEYOR DETECTED"); - } - Assume.assumeTrue(appveyor == null); + String appveyor = System.getenv("APPVEYOR"); // Set to "true" by Appveyor + if (appveyor != null) { + TestBase.logInfo("SKIPPING - APPVEYOR DETECTED"); + } + Assume.assumeTrue(appveyor == null); } static String getStorageConnectionString() { - TestUtilities.skipIfAppveyor(); - + TestUtilities.skipIfAppveyor(); + String retval = System.getenv("EPHTESTSTORAGE"); // if EPHTESTSTORAGE is not set - we cannot run integration tests if (retval == null) { - TestBase.logInfo("SKIPPING - NO STORAGE CONNECTION STRING"); + TestBase.logInfo("SKIPPING - NO STORAGE CONNECTION STRING"); } Assume.assumeTrue(retval != null); return ((retval != null) ? retval : ""); } - + static Boolean isRunningOnAzure() { - return (System.getenv("EVENT_HUB_CONNECTION_STRING") != null); + return (System.getenv("EVENT_HUB_CONNECTION_STRING") != null); } } diff --git a/azure-eventhubs-extensions/src/main/java/com/microsoft/azure/eventhubs/extensions/appender/EventHubsManager.java b/azure-eventhubs-extensions/src/main/java/com/microsoft/azure/eventhubs/extensions/appender/EventHubsManager.java index 10dbd389cb6f..aadaac89272e 100644 --- a/azure-eventhubs-extensions/src/main/java/com/microsoft/azure/eventhubs/extensions/appender/EventHubsManager.java +++ b/azure-eventhubs-extensions/src/main/java/com/microsoft/azure/eventhubs/extensions/appender/EventHubsManager.java @@ -9,13 +9,13 @@ import com.microsoft.azure.eventhubs.EventHubException; import org.apache.logging.log4j.core.appender.AbstractManager; -import java.io.*; -import java.util.*; -import java.util.concurrent.ExecutorService; +import java.io.IOException; +import java.util.LinkedList; import java.util.concurrent.Executors; +import java.util.concurrent.ScheduledExecutorService; public final class EventHubsManager extends AbstractManager { - private static final ExecutorService EXECUTOR_SERVICE = Executors.newCachedThreadPool(); + private static final ScheduledExecutorService EXECUTOR_SERVICE = Executors.newScheduledThreadPool(1); private final String eventHubConnectionString; private EventHubClient eventHubSender; diff --git a/azure-eventhubs/src/main/java/com/microsoft/azure/eventhubs/AuthorizationFailedException.java b/azure-eventhubs/src/main/java/com/microsoft/azure/eventhubs/AuthorizationFailedException.java index c45d6e39f301..fde67c966ac4 100644 --- a/azure-eventhubs/src/main/java/com/microsoft/azure/eventhubs/AuthorizationFailedException.java +++ b/azure-eventhubs/src/main/java/com/microsoft/azure/eventhubs/AuthorizationFailedException.java @@ -4,12 +4,12 @@ */ package com.microsoft.azure.eventhubs; -import java.util.concurrent.Executor; +import java.util.concurrent.ScheduledExecutorService; /** * Authorization failed exception is thrown when error is encountered during authorizing user's permission to run the intended operations. * When encountered this exception user should check whether the token/key provided in the connection string (e.g. one passed to - * {@link EventHubClient#create(String, Executor)}) is valid, and has correct execution right for the intended operations (e.g. + * {@link EventHubClient#create(String, ScheduledExecutorService)}) is valid, and has correct execution right for the intended operations (e.g. * Receive call will need Listen claim associated with the key/token). * * @see http://go.microsoft.com/fwlink/?LinkId=761101 diff --git a/azure-eventhubs/src/main/java/com/microsoft/azure/eventhubs/EventData.java b/azure-eventhubs/src/main/java/com/microsoft/azure/eventhubs/EventData.java index 97109b74ec94..f2d7ca49d680 100755 --- a/azure-eventhubs/src/main/java/com/microsoft/azure/eventhubs/EventData.java +++ b/azure-eventhubs/src/main/java/com/microsoft/azure/eventhubs/EventData.java @@ -12,7 +12,7 @@ import java.nio.ByteBuffer; import java.time.Instant; import java.util.*; -import java.util.concurrent.Executor; +import java.util.concurrent.ScheduledExecutorService; /** * The data structure encapsulating the Event being sent-to and received-from EventHubs. @@ -48,7 +48,7 @@ public interface EventData extends Serializable { * * @param data the actual payload of data in bytes to be Sent to EventHubs. * @return EventData the created {@link EventData} to send to EventHubs. - * @see EventHubClient#create(String, Executor) + * @see EventHubClient#create(String, ScheduledExecutorService) */ static EventData create(final byte[] data) { return new EventDataImpl(data); @@ -72,7 +72,7 @@ static EventData create(final byte[] data) { * @param offset Offset in the byte[] to read from ; inclusive index * @param length length of the byte[] to be read, starting from offset * @return EventData the created {@link EventData} to send to EventHubs. - * @see EventHubClient#create(String, Executor) + * @see EventHubClient#create(String, ScheduledExecutorService) */ static EventData create(final byte[] data, final int offset, final int length) { return new EventDataImpl(data, offset, length); @@ -94,7 +94,7 @@ static EventData create(final byte[] data, final int offset, final int length) { * * @param buffer ByteBuffer which references the payload of the Event to be sent to EventHubs * @return EventData the created {@link EventData} to send to EventHubs. - * @see EventHubClient#create(String, Executor) + * @see EventHubClient#create(String, ScheduledExecutorService) */ static EventData create(final ByteBuffer buffer) { return new EventDataImpl(buffer); diff --git a/azure-eventhubs/src/main/java/com/microsoft/azure/eventhubs/EventHubClient.java b/azure-eventhubs/src/main/java/com/microsoft/azure/eventhubs/EventHubClient.java index ad0fc63b034d..8fa03e6d3679 100644 --- a/azure-eventhubs/src/main/java/com/microsoft/azure/eventhubs/EventHubClient.java +++ b/azure-eventhubs/src/main/java/com/microsoft/azure/eventhubs/EventHubClient.java @@ -11,41 +11,42 @@ import java.nio.channels.UnresolvedAddressException; import java.util.concurrent.CompletableFuture; import java.util.concurrent.Executor; +import java.util.concurrent.ScheduledExecutorService; /** * Anchor class - all EventHub client operations STARTS here. * - * @see EventHubClient#create(String, Executor) + * @see EventHubClient#create(String, ScheduledExecutorService) */ public interface EventHubClient { String DEFAULT_CONSUMER_GROUP_NAME = "$Default"; /** - * Synchronous version of {@link #create(String, Executor)}. + * Synchronous version of {@link #create(String, ScheduledExecutorService)}. * * @param connectionString The connection string to be used. See {@link ConnectionStringBuilder} to construct a connectionString. - * @param executor An {@link Executor} to run all tasks performed by {@link EventHubClient}. + * @param executor An {@link ScheduledExecutorService} to run all tasks performed by {@link EventHubClient}. * @return EventHubClient which can be used to create Senders and Receivers to EventHub * @throws EventHubException If Service Bus service encountered problems during connection creation. * @throws IOException If the underlying Proton-J layer encounter network errors. */ - static EventHubClient createSync(final String connectionString, final Executor executor) + static EventHubClient createSync(final String connectionString, final ScheduledExecutorService executor) throws EventHubException, IOException { return EventHubClient.createSync(connectionString, null, executor); } /** - * Synchronous version of {@link #create(String, Executor)}. + * Synchronous version of {@link #create(String, ScheduledExecutorService)}. * * @param connectionString The connection string to be used. See {@link ConnectionStringBuilder} to construct a connectionString. * @param retryPolicy A custom {@link RetryPolicy} to be used when communicating with EventHub. - * @param executor An {@link Executor} to run all tasks performed by {@link EventHubClient}. + * @param executor An {@link ScheduledExecutorService} to run all tasks performed by {@link EventHubClient}. * @return EventHubClient which can be used to create Senders and Receivers to EventHub * @throws EventHubException If Service Bus service encountered problems during connection creation. * @throws IOException If the underlying Proton-J layer encounter network errors. */ - static EventHubClient createSync(final String connectionString, final RetryPolicy retryPolicy, final Executor executor) + static EventHubClient createSync(final String connectionString, final RetryPolicy retryPolicy, final ScheduledExecutorService executor) throws EventHubException, IOException { return ExceptionUtil.syncWithIOException(() -> create(connectionString, retryPolicy, executor).get()); } @@ -56,12 +57,12 @@ static EventHubClient createSync(final String connectionString, final RetryPolic *

The {@link EventHubClient} created from this method creates a Sender instance internally, which is used by the {@link #send(EventData)} methods. * * @param connectionString The connection string to be used. See {@link ConnectionStringBuilder} to construct a connectionString. - * @param executor An {@link Executor} to run all tasks performed by {@link EventHubClient}. + * @param executor An {@link ScheduledExecutorService} to run all tasks performed by {@link EventHubClient}. * @return CompletableFuture{@literal } which can be used to create Senders and Receivers to EventHub * @throws EventHubException If Service Bus service encountered problems during connection creation. * @throws IOException If the underlying Proton-J layer encounter network errors. */ - static CompletableFuture create(final String connectionString, final Executor executor) + static CompletableFuture create(final String connectionString, final ScheduledExecutorService executor) throws EventHubException, IOException { return EventHubClient.create(connectionString, null, executor); } @@ -73,13 +74,13 @@ static CompletableFuture create(final String connectionString, f * * @param connectionString The connection string to be used. See {@link ConnectionStringBuilder} to construct a connectionString. * @param retryPolicy A custom {@link RetryPolicy} to be used when communicating with EventHub. - * @param executor An {@link Executor} to run all tasks performed by {@link EventHubClient}. + * @param executor An {@link ScheduledExecutorService} to run all tasks performed by {@link EventHubClient}. * @return CompletableFuture{@literal } which can be used to create Senders and Receivers to EventHub * @throws EventHubException If Service Bus service encountered problems during connection creation. * @throws IOException If the underlying Proton-J layer encounter network errors. */ static CompletableFuture create( - final String connectionString, final RetryPolicy retryPolicy, final Executor executor) + final String connectionString, final RetryPolicy retryPolicy, final ScheduledExecutorService executor) throws EventHubException, IOException { return EventHubClientImpl.create(connectionString, retryPolicy, executor); } diff --git a/azure-eventhubs/src/main/java/com/microsoft/azure/eventhubs/PartitionSender.java b/azure-eventhubs/src/main/java/com/microsoft/azure/eventhubs/PartitionSender.java index 34a7292aab1d..b394714de8d4 100644 --- a/azure-eventhubs/src/main/java/com/microsoft/azure/eventhubs/PartitionSender.java +++ b/azure-eventhubs/src/main/java/com/microsoft/azure/eventhubs/PartitionSender.java @@ -7,14 +7,14 @@ import com.microsoft.azure.eventhubs.impl.ExceptionUtil; import java.util.concurrent.CompletableFuture; -import java.util.concurrent.Executor; +import java.util.concurrent.ScheduledExecutorService; /** * This sender class is a logical representation of sending events to a specific EventHub partition. Do not use this class * if you do not care about sending events to specific partitions. Instead, use {@link EventHubClient#send} method. * * @see EventHubClient#createPartitionSender(String) - * @see EventHubClient#create(String, Executor) + * @see EventHubClient#create(String, ScheduledExecutorService) */ public interface PartitionSender { diff --git a/azure-eventhubs/src/main/java/com/microsoft/azure/eventhubs/impl/BaseLinkHandler.java b/azure-eventhubs/src/main/java/com/microsoft/azure/eventhubs/impl/BaseLinkHandler.java index c2f28f112d3a..a086ee3dcc15 100644 --- a/azure-eventhubs/src/main/java/com/microsoft/azure/eventhubs/impl/BaseLinkHandler.java +++ b/azure-eventhubs/src/main/java/com/microsoft/azure/eventhubs/impl/BaseLinkHandler.java @@ -25,7 +25,7 @@ public BaseLinkHandler(final AmqpLink amqpLink) { public void onLinkLocalClose(Event event) { final Link link = event.getLink(); if (TRACE_LOGGER.isInfoEnabled()) { - TRACE_LOGGER.info(String.format("linkName[%s]", link.getName())); + TRACE_LOGGER.info(String.format("onLinkLocalClose linkName[%s]", link.getName())); } closeSession(link); @@ -33,18 +33,30 @@ public void onLinkLocalClose(Event event) { @Override public void onLinkRemoteClose(Event event) { + final Link link = event.getLink(); + if (TRACE_LOGGER.isInfoEnabled()) { + TRACE_LOGGER.info(String.format("onLinkRemoteClose linkName[%s]", link.getName())); + } + handleRemoteLinkClosed(event); } @Override public void onLinkRemoteDetach(Event event) { + final Link link = event.getLink(); + if (TRACE_LOGGER.isInfoEnabled()) { + TRACE_LOGGER.info(String.format("onLinkRemoteDetach linkName[%s]", link.getName())); + } + handleRemoteLinkClosed(event); } public void processOnClose(Link link, ErrorCondition condition) { if (TRACE_LOGGER.isInfoEnabled()) { - TRACE_LOGGER.info("linkName[" + link.getName() + - (condition != null ? "], ErrorCondition[" + condition.getCondition() + ", " + condition.getDescription() + "]" : "], condition[null]")); + TRACE_LOGGER.info(String.format("processOnClose linkName[%s], errorCondition[%s], errorDescription[%s]", + link.getName(), + condition != null ? condition.getCondition() : "n/a", + condition != null ? condition.getDescription() : "n/a")); } this.underlyingEntity.onClose(condition); diff --git a/azure-eventhubs/src/main/java/com/microsoft/azure/eventhubs/impl/ClientConstants.java b/azure-eventhubs/src/main/java/com/microsoft/azure/eventhubs/impl/ClientConstants.java index e827e5ca1fab..eac75a7e404a 100644 --- a/azure-eventhubs/src/main/java/com/microsoft/azure/eventhubs/impl/ClientConstants.java +++ b/azure-eventhubs/src/main/java/com/microsoft/azure/eventhubs/impl/ClientConstants.java @@ -31,7 +31,6 @@ public final class ClientConstants { public final static Duration TOKEN_VALIDITY = Duration.ofMinutes(20); public final static int DEFAULT_MAX_RETRY_COUNT = 10; public final static boolean DEFAULT_IS_TRANSIENT = true; - public final static int SESSION_OPEN_TIMEOUT_IN_MS = 15000; public final static int REACTOR_IO_POLL_TIMEOUT = 20; public final static int SERVER_BUSY_BASE_SLEEP_TIME_IN_SECS = 4; public final static int MGMT_CHANNEL_MIN_RETRY_IN_MILLIS = 5; diff --git a/azure-eventhubs/src/main/java/com/microsoft/azure/eventhubs/impl/ClientEntity.java b/azure-eventhubs/src/main/java/com/microsoft/azure/eventhubs/impl/ClientEntity.java index f397179f04e4..1f760fa2fc75 100644 --- a/azure-eventhubs/src/main/java/com/microsoft/azure/eventhubs/impl/ClientEntity.java +++ b/azure-eventhubs/src/main/java/com/microsoft/azure/eventhubs/impl/ClientEntity.java @@ -11,7 +11,7 @@ import java.util.Locale; import java.util.concurrent.CompletableFuture; import java.util.concurrent.ExecutionException; -import java.util.concurrent.Executor; +import java.util.concurrent.ScheduledExecutorService; /** * Contract for all client entities with Open-Close/Abort state m/c @@ -21,7 +21,7 @@ abstract class ClientEntity { private static final Logger TRACE_LOGGER = LoggerFactory.getLogger(ClientEntity.class); - protected final Executor executor; + protected final ScheduledExecutorService executor; private final String clientId; private final Object syncClose; private final ClientEntity parent; @@ -29,7 +29,7 @@ abstract class ClientEntity { private boolean isClosing; private boolean isClosed; - protected ClientEntity(final String clientId, final ClientEntity parent, final Executor executor) { + protected ClientEntity(final String clientId, final ClientEntity parent, final ScheduledExecutorService executor) { this.clientId = clientId; this.parent = parent; this.executor = executor; diff --git a/azure-eventhubs/src/main/java/com/microsoft/azure/eventhubs/impl/ConnectionHandler.java b/azure-eventhubs/src/main/java/com/microsoft/azure/eventhubs/impl/ConnectionHandler.java index 1e2c32ce6174..1e13d52c6a65 100644 --- a/azure-eventhubs/src/main/java/com/microsoft/azure/eventhubs/impl/ConnectionHandler.java +++ b/azure-eventhubs/src/main/java/com/microsoft/azure/eventhubs/impl/ConnectionHandler.java @@ -8,18 +8,14 @@ import org.apache.qpid.proton.Proton; import org.apache.qpid.proton.amqp.Symbol; import org.apache.qpid.proton.amqp.transport.ErrorCondition; -import org.apache.qpid.proton.engine.BaseHandler; -import org.apache.qpid.proton.engine.Connection; -import org.apache.qpid.proton.engine.EndpointState; -import org.apache.qpid.proton.engine.Event; -import org.apache.qpid.proton.engine.SslDomain; -import org.apache.qpid.proton.engine.Transport; +import org.apache.qpid.proton.engine.*; import org.apache.qpid.proton.engine.impl.TransportInternal; import org.apache.qpid.proton.reactor.Handshaker; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import java.util.HashMap; +import java.util.Locale; import java.util.Map; // ServiceBus <-> ProtonReactor interaction handles all @@ -50,10 +46,6 @@ static ConnectionHandler create(TransportType transportType, AmqpConnection amqp } } - protected AmqpConnection getAmqpConnection() { - return this.amqpConnection; - } - private static SslDomain makeDomain(SslDomain.Mode mode) { final SslDomain domain = Proton.sslDomain(); @@ -64,14 +56,21 @@ private static SslDomain makeDomain(SslDomain.Mode mode) { return domain; } + protected AmqpConnection getAmqpConnection() { + return this.amqpConnection; + } + @Override public void onConnectionInit(Event event) { + if (TRACE_LOGGER.isInfoEnabled()) { + TRACE_LOGGER.info(String.format(Locale.US, "onConnectionInit hostname[%s]", this.amqpConnection.getHostName())); + } final Connection connection = event.getConnection(); final String hostName = new StringBuilder(this.amqpConnection.getHostName()) - .append(":") - .append(String.valueOf(this.getProtocolPort())) - .toString(); + .append(":") + .append(String.valueOf(this.getProtocolPort())) + .toString(); connection.setHostname(hostName); connection.setContainer(StringUtil.getRandomString()); @@ -105,6 +104,7 @@ protected void notifyTransportErrors(final Event event) { /** * HostName to be used for socket creation. * for ex: in case of proxy server - this could be proxy ip address + * * @return host name */ public String getRemoteHostName() { @@ -114,6 +114,7 @@ public String getRemoteHostName() { /** * port used to create socket. * for ex: in case of talking to event hubs service via proxy - use proxy port + * * @return port */ protected int getRemotePort() { @@ -122,6 +123,7 @@ protected int getRemotePort() { /** * Port used on connection open frame + * * @return port */ protected int getProtocolPort() { @@ -134,6 +136,9 @@ protected int getMaxFrameSize() { @Override public void onConnectionBound(Event event) { + if (TRACE_LOGGER.isInfoEnabled()) { + TRACE_LOGGER.info(String.format(Locale.US, "onConnectionBound hostname[%s]", this.amqpConnection.getHostName())); + } final Transport transport = event.getTransport(); @@ -145,8 +150,8 @@ public void onConnectionUnbound(Event event) { final Connection connection = event.getConnection(); if (TRACE_LOGGER.isInfoEnabled()) { - TRACE_LOGGER.info( - "onConnectionUnbound: hostname[" + connection.getHostname() + "], state[" + connection.getLocalState() + "], remoteState[" + connection.getRemoteState() + "]"); + TRACE_LOGGER.info(String.format(Locale.US, "onConnectionUnbound: hostname[%s], state[%s], remoteState[%s]", + connection.getHostname(), connection.getLocalState(), connection.getRemoteState())); } // if failure happened while establishing transport - nothing to free up. @@ -162,7 +167,9 @@ public void onTransportError(Event event) { final ErrorCondition condition = transport.getCondition(); if (TRACE_LOGGER.isWarnEnabled()) { - TRACE_LOGGER.warn("onTransportClosed: hostname[" + (connection != null ? connection.getHostname() : "n/a") + "], error[" + (condition != null ? condition.getDescription() : "n/a") + "]"); + TRACE_LOGGER.warn(String.format(Locale.US, "onTransportError: hostname[%s], error[%s]", + connection != null ? connection.getHostname() : "n/a", + condition != null ? condition.getDescription() : "n/a")); } if (connection != null && connection.getRemoteState() != EndpointState.CLOSED) { @@ -185,7 +192,8 @@ public void onTransportClosed(Event event) { final ErrorCondition condition = transport.getCondition(); if (TRACE_LOGGER.isInfoEnabled()) { - TRACE_LOGGER.info("onTransportClosed: hostname[" + (connection != null ? connection.getHostname() : "n/a") + "], error[" + (condition != null ? condition.getDescription() : "n/a") + "]"); + TRACE_LOGGER.info(String.format(Locale.US, "onTransportClosed: hostname[%s], error[%s]", + connection != null ? connection.getHostname() : "n/a", (condition != null ? condition.getDescription() : "n/a"))); } if (connection != null && connection.getRemoteState() != EndpointState.CLOSED) { @@ -195,11 +203,25 @@ public void onTransportClosed(Event event) { } } + @Override + public void onConnectionLocalOpen(Event event) { + final Connection connection = event.getConnection(); + final ErrorCondition error = connection.getCondition(); + + if (TRACE_LOGGER.isInfoEnabled()) { + TRACE_LOGGER.info(String.format(Locale.US, "onConnectionLocalOpen: hostname[%s], errorCondition[%s], errorDescription[%s]", + connection.getHostname(), + error != null ? error.getCondition() : "n/a", + error != null ? error.getDescription() : "n/a")); + } + } + @Override public void onConnectionRemoteOpen(Event event) { if (TRACE_LOGGER.isInfoEnabled()) { - TRACE_LOGGER.info("onConnectionRemoteOpen: hostname[" + event.getConnection().getHostname() + ", " + event.getConnection().getRemoteContainer() + "]"); + TRACE_LOGGER.info(String.format(Locale.US, "onConnectionRemoteOpen: hostname[%s], remoteContainer[%s]", + event.getConnection().getHostname(), event.getConnection().getRemoteContainer())); } this.amqpConnection.onOpenComplete(null); @@ -209,13 +231,13 @@ public void onConnectionRemoteOpen(Event event) { public void onConnectionLocalClose(Event event) { final Connection connection = event.getConnection(); - final ErrorCondition error = connection.getCondition(); + if (TRACE_LOGGER.isInfoEnabled()) { - TRACE_LOGGER.info("onConnectionLocalClose: hostname[" + connection.getHostname() + - (error != null - ? "], errorCondition[" + error.getCondition() + ", " + error.getDescription() + "]" - : "]")); + TRACE_LOGGER.info(String.format(Locale.US, "onConnectionLocalClose: hostname[%s], errorCondition[%s], errorDescription[%s]", + connection.getHostname(), + error != null ? error.getCondition() : "n/a", + error != null ? error.getDescription() : "n/a")); } if (connection.getRemoteState() == EndpointState.CLOSED) { @@ -234,12 +256,25 @@ public void onConnectionRemoteClose(Event event) { final ErrorCondition error = connection.getRemoteCondition(); if (TRACE_LOGGER.isInfoEnabled()) { - TRACE_LOGGER.info("onConnectionRemoteClose: hostname[" + connection.getHostname() + - (error != null - ? "], errorCondition[" + error.getCondition() + ", " + error.getDescription() + "]" - : "]")); + TRACE_LOGGER.info(String.format(Locale.US, "onConnectionRemoteClose: hostname[%s], errorCondition[%s], errorDescription[%s]", + connection.getHostname(), + error != null ? error.getCondition() : "n/a", + error != null ? error.getDescription() : "n/a")); } this.amqpConnection.onConnectionError(error); } + + @Override + public void onConnectionFinal(Event event) { + final Connection connection = event.getConnection(); + final ErrorCondition error = connection.getCondition(); + + if (TRACE_LOGGER.isInfoEnabled()) { + TRACE_LOGGER.info(String.format(Locale.US, "onConnectionFinal: hostname[%s], errorCondition[%s], errorDescription[%s]", + connection.getHostname(), + error != null ? error.getCondition() : "n/a", + error != null ? error.getDescription() : "n/a")); + } + } } diff --git a/azure-eventhubs/src/main/java/com/microsoft/azure/eventhubs/impl/CustomIOHandler.java b/azure-eventhubs/src/main/java/com/microsoft/azure/eventhubs/impl/CustomIOHandler.java index 185c32f693bc..c091c00be1fc 100644 --- a/azure-eventhubs/src/main/java/com/microsoft/azure/eventhubs/impl/CustomIOHandler.java +++ b/azure-eventhubs/src/main/java/com/microsoft/azure/eventhubs/impl/CustomIOHandler.java @@ -4,15 +4,25 @@ import org.apache.qpid.proton.engine.Event; import org.apache.qpid.proton.engine.Transport; import org.apache.qpid.proton.reactor.impl.IOHandler; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import java.util.Locale; public class CustomIOHandler extends IOHandler { + private static final Logger TRACE_LOGGER = LoggerFactory.getLogger(CustomIOHandler.class); + @Override public void onTransportClosed(Event event) { - final Transport transport = event.getTransport(); final Connection connection = event.getConnection(); + if (TRACE_LOGGER.isInfoEnabled()) { + TRACE_LOGGER.info(String.format(Locale.US, "onTransportClosed hostname[%s]", + (connection != null ? connection.getHostname() : "n/a"))); + } + if (transport != null && connection != null && connection.getTransport() != null) { transport.unbind(); } diff --git a/azure-eventhubs/src/main/java/com/microsoft/azure/eventhubs/impl/EventHubClientImpl.java b/azure-eventhubs/src/main/java/com/microsoft/azure/eventhubs/impl/EventHubClientImpl.java index 075dfdbca9b2..4dc5e927bb7d 100644 --- a/azure-eventhubs/src/main/java/com/microsoft/azure/eventhubs/impl/EventHubClientImpl.java +++ b/azure-eventhubs/src/main/java/com/microsoft/azure/eventhubs/impl/EventHubClientImpl.java @@ -17,7 +17,7 @@ import java.util.concurrent.CompletableFuture; import java.util.concurrent.CompletionException; import java.util.concurrent.ExecutionException; -import java.util.concurrent.Executor; +import java.util.concurrent.ScheduledExecutorService; import java.util.function.Consumer; import java.util.function.Function; @@ -37,15 +37,15 @@ public final class EventHubClientImpl extends ClientEntity implements EventHubCl private CompletableFuture createSender; - private EventHubClientImpl(final ConnectionStringBuilder connectionString, final Executor executor) { - super(StringUtil.getRandomString(), null, executor); + private EventHubClientImpl(final ConnectionStringBuilder connectionString, final ScheduledExecutorService executor) { + super("EventHubClientImpl".concat(StringUtil.getRandomString()), null, executor); this.eventHubName = connectionString.getEventHubName(); this.senderCreateSync = new Object(); } public static CompletableFuture create( - final String connectionString, final RetryPolicy retryPolicy, final Executor executor) + final String connectionString, final RetryPolicy retryPolicy, final ScheduledExecutorService executor) throws EventHubException, IOException { final ConnectionStringBuilder connStr = new ConnectionStringBuilder(connectionString); final EventHubClientImpl eventHubClient = new EventHubClientImpl(connStr, executor); @@ -220,7 +220,7 @@ private CompletableFuture createInternalSender() { if (!this.isSenderCreateStarted) { synchronized (this.senderCreateSync) { if (!this.isSenderCreateStarted) { - this.createSender = MessageSender.create(this.underlyingFactory, StringUtil.getRandomString(), this.eventHubName) + this.createSender = MessageSender.create(this.underlyingFactory, this.getClientId().concat("-InternalSender"), this.eventHubName) .thenAcceptAsync(new Consumer() { public void accept(MessageSender a) { EventHubClientImpl.this.sender = a; @@ -290,7 +290,7 @@ public CompletableFuture apply(Map (long) rawData.get(ClientConstants.MANAGEMENT_RESULT_LAST_ENQUEUED_SEQUENCE_NUMBER), (String) rawData.get(ClientConstants.MANAGEMENT_RESULT_LAST_ENQUEUED_OFFSET), ((Date) rawData.get(ClientConstants.MANAGEMENT_RESULT_LAST_ENQUEUED_TIME_UTC)).toInstant(), - (boolean)rawData.get(ClientConstants.MANAGEMENT_RESULT_PARTITION_IS_EMPTY))); + (boolean) rawData.get(ClientConstants.MANAGEMENT_RESULT_PARTITION_IS_EMPTY))); return future2; } }, this.executor); @@ -349,7 +349,7 @@ private class ManagementRetry implements Runnable { public void run() { final long timeLeft = this.timeoutTracker.remaining().toMillis(); final CompletableFuture> intermediateFuture = this.mf.getManagementChannel() - .request(this.mf.getReactorScheduler(), + .request(this.mf.getReactorDispatcher(), this.request, timeLeft > 0 ? timeLeft : 0); diff --git a/azure-eventhubs/src/main/java/com/microsoft/azure/eventhubs/impl/MessageReceiver.java b/azure-eventhubs/src/main/java/com/microsoft/azure/eventhubs/impl/MessageReceiver.java index ba78cc0fe62f..73c3791f94e9 100644 --- a/azure-eventhubs/src/main/java/com/microsoft/azure/eventhubs/impl/MessageReceiver.java +++ b/azure-eventhubs/src/main/java/com/microsoft/azure/eventhubs/impl/MessageReceiver.java @@ -114,7 +114,8 @@ public void run() { if (TRACE_LOGGER.isInfoEnabled()) { TRACE_LOGGER.info( String.format(Locale.US, - "path[%s], linkName[%s] - Reschedule operation timer, current: [%s], remaining: [%s] secs", + "clientId[%s], path[%s], linkName[%s] - Reschedule operation timer, current: [%s], remaining: [%s] secs", + getClientId(), receivePath, receiveLink.getName(), Instant.now(), @@ -142,7 +143,7 @@ public void run() { public void run() { try { underlyingFactory.getCBSChannel().sendToken( - underlyingFactory.getReactorScheduler(), + underlyingFactory.getReactorDispatcher(), underlyingFactory.getTokenProvider().getToken(tokenAudience, ClientConstants.TOKEN_VALIDITY), tokenAudience, new OperationResult() { @@ -151,7 +152,8 @@ public void onComplete(Void result) { if (TRACE_LOGGER.isDebugEnabled()) { TRACE_LOGGER.debug( String.format(Locale.US, - "path[%s], linkName[%s] - token renewed", receivePath, receiveLink.getName())); + "clientId[%s], path[%s], linkName[%s] - token renewed", + getClientId(), receivePath, receiveLink.getName())); } } @@ -160,7 +162,8 @@ public void onError(Exception error) { if (TRACE_LOGGER.isInfoEnabled()) { TRACE_LOGGER.info( String.format(Locale.US, - "path[%s], linkName[%s], tokenRenewalFailure[%s]", receivePath, receiveLink.getName(), error.getMessage())); + "clientId[%s], path[%s], linkName[%s], tokenRenewalFailure[%s]", + getClientId(), receivePath, receiveLink.getName(), error.getMessage())); } } }); @@ -168,7 +171,8 @@ public void onError(Exception error) { if (TRACE_LOGGER.isInfoEnabled()) { TRACE_LOGGER.info( String.format(Locale.US, - "path[%s], linkName[%s], tokenRenewalScheduleFailure[%s]", receivePath, receiveLink.getName(), exception.getMessage())); + "clientId[%s], path[%s], linkName[%s], tokenRenewalScheduleFailure[%s]", + getClientId(), receivePath, receiveLink.getName(), exception.getMessage())); } } } @@ -247,8 +251,8 @@ public CompletableFuture> receive(final int maxMessageCount) if (maxMessageCount <= 0 || maxMessageCount > this.prefetchCount) { onReceive.completeExceptionally(new IllegalArgumentException(String.format( Locale.US, - "maxEventCount(%s) should be a positive number and should be less than prefetchCount(%s)", - maxMessageCount, this.prefetchCount))); + "Entity(%s): maxEventCount(%s) should be a positive number and should be less than prefetchCount(%s)", + this.receivePath, maxMessageCount, this.prefetchCount))); return onReceive; } @@ -256,9 +260,10 @@ public CompletableFuture> receive(final int maxMessageCount) if (TRACE_LOGGER.isInfoEnabled()) { TRACE_LOGGER.info( String.format(Locale.US, - "path[%s], linkName[%s] - schedule operation timer, current: [%s], remaining: [%s] secs", - receivePath, - receiveLink.getName(), + "clientId[%s], path[%s], linkName[%s] - schedule operation timer, current: [%s], remaining: [%s] secs", + this.getClientId(), + this.receivePath, + this.receiveLink.getName(), Instant.now(), this.receiveTimeout.getSeconds())); } @@ -282,17 +287,16 @@ public void onOpenComplete(Exception exception) { this.creatingLink = false; if (exception == null) { - if (this.getIsClosingOrClosed()) { - this.receiveLink.close(); - return; - } - if (this.linkOpen != null && !this.linkOpen.getWork().isDone()) { this.linkOpen.getWork().complete(this); if (this.openTimer != null) this.openTimer.cancel(false); } + if (this.getIsClosingOrClosed()) { + return; + } + synchronized (this.errorConditionLock) { this.lastKnownLinkError = null; } @@ -303,8 +307,8 @@ public void onOpenComplete(Exception exception) { this.sendFlow(this.prefetchCount - this.prefetchedMessages.size()); if (TRACE_LOGGER.isInfoEnabled()) { - TRACE_LOGGER.info(String.format("receiverPath[%s], linkname[%s], updated-link-credit[%s], sentCredits[%s]", - this.receivePath, this.receiveLink.getName(), this.receiveLink.getCredit(), this.prefetchCount)); + TRACE_LOGGER.info(String.format("clientId[%s], receiverPath[%s], linkName[%s], updated-link-credit[%s], sentCredits[%s]", + this.getClientId(), this.receivePath, this.receiveLink.getName(), this.receiveLink.getCredit(), this.prefetchCount)); } } else { synchronized (this.errorConditionLock) { @@ -333,8 +337,8 @@ public void onEvent() { } catch (IOException | RejectedExecutionException schedulerException) { if (TRACE_LOGGER.isWarnEnabled()) { TRACE_LOGGER.warn( - String.format(Locale.US, "receiverPath[%s], scheduling createLink encountered error: %s", - this.receivePath, schedulerException.getLocalizedMessage())); + String.format(Locale.US, "clientId[%s], receiverPath[%s], scheduling createLink encountered error: %s", + this.getClientId(), this.receivePath, schedulerException.getLocalizedMessage())); } this.cancelOpen(schedulerException); @@ -388,7 +392,8 @@ public void onError(final Exception exception) { } final Exception completionException = exception == null - ? new EventHubException(true, "Client encountered transient error for unknown reasons, please retry the operation.") + ? new EventHubException(true, String.format(Locale.US, + "Entity(%s): client encountered transient error for unknown reasons, please retry the operation.", this.receivePath)) : exception; this.onOpenComplete(completionException); @@ -415,8 +420,9 @@ public void onEvent() { recreateScheduled = false; if (TRACE_LOGGER.isWarnEnabled()) { TRACE_LOGGER.warn( - String.format(Locale.US, "receiverPath[%s], linkName[%s], scheduling createLink encountered error: %s", - MessageReceiver.this.receivePath, + String.format(Locale.US, "clientId[%s], receiverPath[%s], linkName[%s], scheduling createLink encountered error: %s", + this.getClientId(), + this.receivePath, this.receiveLink.getName(), ignore.getLocalizedMessage())); } } @@ -515,7 +521,7 @@ else if (u != null) try { this.underlyingFactory.getCBSChannel().sendToken( - this.underlyingFactory.getReactorScheduler(), + this.underlyingFactory.getReactorDispatcher(), this.underlyingFactory.getTokenProvider().getToken(tokenAudience, ClientConstants.TOKEN_VALIDITY), tokenAudience, new OperationResult() { @@ -571,8 +577,8 @@ private void sendFlow(final int credits) { this.nextCreditToFlow = 0; if (TRACE_LOGGER.isDebugEnabled()) { - TRACE_LOGGER.debug(String.format("receiverPath[%s], linkname[%s], updated-link-credit[%s], sentCredits[%s], ThreadId[%s]", - this.receivePath, this.receiveLink.getName(), this.receiveLink.getCredit(), tempFlow, Thread.currentThread().getId())); + TRACE_LOGGER.debug(String.format("clientId[%s], receiverPath[%s], linkName[%s], updated-link-credit[%s], sentCredits[%s], ThreadId[%s]", + this.getClientId(), this.receivePath, this.receiveLink.getName(), this.receiveLink.getCredit(), tempFlow, Thread.currentThread().getId())); } } } @@ -594,10 +600,11 @@ public void run() { String.format(Locale.US, "Open operation on entity(%s) timed out at %s.", MessageReceiver.this.receivePath, ZonedDateTime.now()), lastReportedLinkError); + if (TRACE_LOGGER.isWarnEnabled()) { TRACE_LOGGER.warn( - String.format(Locale.US, "receiverPath[%s], Open call timedout", MessageReceiver.this.receivePath), - operationTimedout); + String.format(Locale.US, "clientId[%s], receiverPath[%s], Open call timed out", + MessageReceiver.this.getClientId(), MessageReceiver.this.receivePath), operationTimedout); } ExceptionUtil.completeExceptionally(linkOpen.getWork(), operationTimedout, MessageReceiver.this); @@ -630,10 +637,13 @@ public void run() { link = MessageReceiver.this.receiveLink; } - final Exception operationTimedout = new TimeoutException(String.format(Locale.US, "%s operation on Receive Link(%s) timed out at %s", "Close", link.getName(), ZonedDateTime.now())); + final Exception operationTimedout = new TimeoutException(String.format(Locale.US, "Close operation on Receive Link(%s) timed out at %s", + link.getName(), ZonedDateTime.now())); + if (TRACE_LOGGER.isInfoEnabled()) { TRACE_LOGGER.info( - String.format(Locale.US, "receiverPath[%s], linkName[%s], %s call timedout", MessageReceiver.this.receivePath, link.getName(), "Close"), + String.format(Locale.US, "clientId[%s], receiverPath[%s], linkName[%s], Close call timed out", + MessageReceiver.this.getClientId(), MessageReceiver.this.receivePath, link.getName()), operationTimedout); } @@ -708,8 +718,9 @@ public void onEvent() { if (receiveLink != null && receiveLink.getLocalState() != EndpointState.CLOSED) { receiveLink.close(); } else if (receiveLink == null || receiveLink.getRemoteState() == EndpointState.CLOSED) { - if (closeTimer != null) + if (closeTimer != null && !closeTimer.isCancelled()) { closeTimer.cancel(false); + } linkClose.complete(null); } diff --git a/azure-eventhubs/src/main/java/com/microsoft/azure/eventhubs/impl/MessageSender.java b/azure-eventhubs/src/main/java/com/microsoft/azure/eventhubs/impl/MessageSender.java index 2e6d6b7872df..81972c664b5b 100644 --- a/azure-eventhubs/src/main/java/com/microsoft/azure/eventhubs/impl/MessageSender.java +++ b/azure-eventhubs/src/main/java/com/microsoft/azure/eventhubs/impl/MessageSender.java @@ -40,7 +40,8 @@ public final class MessageSender extends ClientEntity implements AmqpSender, ErrorContextProvider { private static final Logger TRACE_LOGGER = LoggerFactory.getLogger(MessageSender.class); private static final String SEND_TIMED_OUT = "Send operation timed out"; - + // TestHooks for code injection + private static volatile Consumer onOpenRetry = null; private final MessagingFactory underlyingFactory; private final String sendPath; private final Duration operationTimeout; @@ -54,7 +55,6 @@ public final class MessageSender extends ClientEntity implements AmqpSender, Err private final String tokenAudience; private final Object errorConditionLock; private final Timer timer; - private volatile int maxMessageSize; private volatile Sender sendLink; private volatile CompletableFuture linkFirstOpen; @@ -62,13 +62,9 @@ public final class MessageSender extends ClientEntity implements AmqpSender, Err private volatile boolean creatingLink; private volatile CompletableFuture closeTimer; private volatile CompletableFuture openTimer; - private Exception lastKnownLinkError; private Instant lastKnownErrorReportedAt; - // TestHooks for code injection - private static volatile Consumer onOpenRetry = null; - private MessageSender(final MessagingFactory factory, final String sendLinkName, final String senderPath) { super(sendLinkName, factory, factory.executor); @@ -106,7 +102,7 @@ public void onEvent() { public void run() { try { underlyingFactory.getCBSChannel().sendToken( - underlyingFactory.getReactorScheduler(), + underlyingFactory.getReactorDispatcher(), underlyingFactory.getTokenProvider().getToken(tokenAudience, ClientConstants.TOKEN_VALIDITY), tokenAudience, new OperationResult() { @@ -114,7 +110,8 @@ public void run() { public void onComplete(Void result) { if (TRACE_LOGGER.isDebugEnabled()) { TRACE_LOGGER.debug(String.format(Locale.US, - "path[%s], linkName[%s] - token renewed", sendPath, sendLink.getName())); + "clientId[%s], path[%s], linkName[%s] - token renewed", + getClientId(), sendPath, sendLink.getName())); } } @@ -122,14 +119,16 @@ public void onComplete(Void result) { public void onError(Exception error) { if (TRACE_LOGGER.isInfoEnabled()) { TRACE_LOGGER.info(String.format(Locale.US, - "path[%s], linkName[%s] - tokenRenewalFailure[%s]", sendPath, sendLink.getName(), error.getMessage())); + "clientId[%s], path[%s], linkName[%s] - tokenRenewalFailure[%s]", + getClientId(), sendPath, sendLink.getName(), error.getMessage())); } } }); } catch (IOException | NoSuchAlgorithmException | InvalidKeyException | RuntimeException exception) { if (TRACE_LOGGER.isWarnEnabled()) { TRACE_LOGGER.warn(String.format(Locale.US, - "path[%s], linkName[%s] - tokenRenewalScheduleFailure[%s]", sendPath, sendLink.getName(), exception.getMessage())); + "clientId[%s], path[%s], linkName[%s] - tokenRenewalScheduleFailure[%s]", + getClientId(), sendPath, sendLink.getName(), exception.getMessage())); } } } @@ -210,8 +209,9 @@ private CompletableFuture sendCore( (unUsed, exception) -> { if (exception != null && !(exception instanceof CancellationException)) onSendFuture.completeExceptionally( - new OperationCancelledException("Send failed while dispatching to Reactor, see cause for more details.", - exception)); + new OperationCancelledException(String.format(Locale.US, + "Entity(%s): send failed while dispatching to Reactor, see cause for more details.", + this.sendPath), exception)); return null; }, this.executor); @@ -230,7 +230,9 @@ private CompletableFuture sendCore( this.underlyingFactory.scheduleOnReactorThread(this.sendWork); } catch (IOException | RejectedExecutionException schedulerException) { onSendFuture.completeExceptionally( - new OperationCancelledException("Send failed while dispatching to Reactor, see cause for more details.", schedulerException)); + new OperationCancelledException(String.format(Locale.US, + "Entity(%s): send failed while dispatching to Reactor, see cause for more details.", + this.sendPath), schedulerException)); } return onSendFuture; @@ -247,7 +249,8 @@ private CompletableFuture send( public CompletableFuture send(final Iterable messages) { if (messages == null || IteratorUtil.sizeEquals(messages, 0)) { - throw new IllegalArgumentException("Sending Empty batch of messages is not allowed."); + throw new IllegalArgumentException(String.format(Locale.US, + "Entity[%s}: sending Empty batch of messages is not allowed.", this.sendPath)); } final Message firstMessage = messages.iterator().next(); @@ -280,7 +283,9 @@ public CompletableFuture send(final Iterable messages) { encodedSize = messageWrappedByData.encode(bytes, byteArrayOffset, maxMessageSizeTemp - byteArrayOffset - 1); } catch (BufferOverflowException exception) { final CompletableFuture sendTask = new CompletableFuture<>(); - sendTask.completeExceptionally(new PayloadSizeExceededException(String.format("Size of the payload exceeded Maximum message size: %s kb", maxMessageSizeTemp / 1024), exception)); + sendTask.completeExceptionally(new PayloadSizeExceededException(String.format(Locale.US, + "Entity(%s): size of the payload exceeded Maximum message size: %s kb", + this.sendPath, maxMessageSizeTemp / 1024), exception)); return sendTask; } @@ -302,7 +307,9 @@ public CompletableFuture send(Message msg) { encodedSize = msg.encode(bytes, 0, allocationSize); } catch (BufferOverflowException exception) { final CompletableFuture sendTask = new CompletableFuture(); - sendTask.completeExceptionally(new PayloadSizeExceededException(String.format("Size of the payload exceeded Maximum message size: %s kb", maxMessageSizeTemp / 1024), exception)); + sendTask.completeExceptionally(new PayloadSizeExceededException(String.format(Locale.US, + "Entity(%s): size of the payload exceeded Maximum message size: %s kb", + this.sendPath, maxMessageSizeTemp / 1024), exception)); return sendTask; } @@ -380,14 +387,14 @@ public void onEvent() { } catch (IOException | RejectedExecutionException schedulerException) { if (TRACE_LOGGER.isWarnEnabled()) { TRACE_LOGGER.warn( - String.format(Locale.US, "senderPath[%s], scheduling createLink encountered error: %s", - this.sendPath, schedulerException.getLocalizedMessage())); + String.format(Locale.US, "clientId[%s], senderPath[%s], scheduling createLink encountered error: %s", + this.getClientId(), this.sendPath, schedulerException.getLocalizedMessage())); } this.cancelOpen(schedulerException); } } else if (completionException instanceof EventHubException - && !((EventHubException) completionException).getIsTransient()){ + && !((EventHubException) completionException).getIsTransient()) { this.cancelOpen(completionException); } } @@ -419,7 +426,9 @@ public void onError(final Exception completionException) { for (Map.Entry> pendingSend : this.pendingSendsData.entrySet()) { ExceptionUtil.completeExceptionally(pendingSend.getValue().getWork(), completionException == null - ? new OperationCancelledException("Send cancelled as the Sender instance is Closed before the sendOperation completed.") + ? new OperationCancelledException(String.format(Locale.US, + "Entity(%s): send cancelled as the Sender instance is Closed before the sendOperation completed.", + this.sendPath)) : completionException, this); } @@ -438,7 +447,9 @@ public void onError(final Exception completionException) { } final Exception finalCompletionException = completionException == null - ? new EventHubException(true, "Client encountered transient error for unknown reasons, please retry the operation.") : completionException; + ? new EventHubException(true, String.format(Locale.US, + "Entity(%s): client encountered transient error for unknown reasons, please retry the operation.", + this.sendPath)) : completionException; this.onOpenComplete(finalCompletionException); @@ -489,7 +500,8 @@ public void onSendComplete(final Delivery delivery) { TRACE_LOGGER.trace( String.format( Locale.US, - "path[%s], linkName[%s], deliveryTag[%s]", MessageSender.this.sendPath, this.sendLink.getName(), deliveryTag)); + "clientId[%s], path[%s], linkName[%s], deliveryTag[%s]", + this.getClientId(), this.sendPath, this.sendLink.getName(), deliveryTag)); final ReplayableWorkItem pendingSendWorkItem = this.pendingSendsData.remove(deliveryTag); @@ -542,7 +554,10 @@ public void onEvent() { exception.initCause(schedulerException); this.cleanupFailedSend( pendingSendWorkItem, - new EventHubException(false, "Send operation failed while scheduling a retry on Reactor, see cause for more details.", schedulerException)); + new EventHubException(false, String.format(Locale.US, + "Entity(%s): send operation failed while scheduling a retry on Reactor, see cause for more details.", + this.sendPath), + schedulerException)); } } } else if (outcome instanceof Released) { @@ -553,7 +568,8 @@ public void onEvent() { } else { if (TRACE_LOGGER.isDebugEnabled()) TRACE_LOGGER.debug( - String.format(Locale.US, "path[%s], linkName[%s], delivery[%s] - mismatch (or send timedout)", this.sendPath, this.sendLink.getName(), deliveryTag)); + String.format(Locale.US, "clientId[%s]. path[%s], linkName[%s], delivery[%s] - mismatch (or send timed out)", + this.getClientId(), this.sendPath, this.sendLink.getName(), deliveryTag)); } } @@ -613,7 +629,7 @@ else if (u != null) try { this.underlyingFactory.getCBSChannel().sendToken( - this.underlyingFactory.getReactorScheduler(), + this.underlyingFactory.getReactorDispatcher(), this.underlyingFactory.getTokenProvider().getToken(tokenAudience, ClientConstants.TOKEN_VALIDITY), tokenAudience, new OperationResult() { @@ -670,7 +686,8 @@ public void run() { if (TRACE_LOGGER.isWarnEnabled()) { TRACE_LOGGER.warn( - String.format(Locale.US, "path[%s], open call timedout", MessageSender.this.sendPath), + String.format(Locale.US, "clientId[%s], path[%s], open call timed out", + MessageSender.this.getClientId(), MessageSender.this.sendPath), operationTimedout); } @@ -724,8 +741,9 @@ public void onFlow(final int creditIssued) { if (TRACE_LOGGER.isDebugEnabled()) { int numberOfSendsWaitingforCredit = this.pendingSends.size(); - TRACE_LOGGER.debug(String.format(Locale.US, "path[%s], linkName[%s], remoteLinkCredit[%s], pendingSendsWaitingForCredit[%s], pendingSendsWaitingDelivery[%s]", - this.sendPath, this.sendLink.getName(), creditIssued, numberOfSendsWaitingforCredit, this.pendingSendsData.size() - numberOfSendsWaitingforCredit)); + TRACE_LOGGER.debug(String.format(Locale.US, + "clientId[%s], path[%s], linkName[%s], remoteLinkCredit[%s], pendingSendsWaitingForCredit[%s], pendingSendsWaitingDelivery[%s]", + this.getClientId(), this.sendPath, this.sendLink.getName(), creditIssued, numberOfSendsWaitingforCredit, this.pendingSendsData.size() - numberOfSendsWaitingforCredit)); } this.sendWork.onEvent(); @@ -791,8 +809,8 @@ private void processSendWork() { } else { if (TRACE_LOGGER.isDebugEnabled()) { TRACE_LOGGER.debug( - String.format(Locale.US, "path[%s], linkName[%s], deliveryTag[%s], sentMessageSize[%s], payloadActualSize[%s] - sendlink advance failed", - this.sendPath, this.sendLink.getName(), deliveryTag, sentMsgSize, sendData.getEncodedMessageSize())); + String.format(Locale.US, "clientId[%s], path[%s], linkName[%s], deliveryTag[%s], sentMessageSize[%s], payloadActualSize[%s] - sendlink advance failed", + this.getClientId(), this.sendPath, this.sendLink.getName(), deliveryTag, sentMsgSize, sendData.getEncodedMessageSize())); } if (delivery != null) { @@ -800,16 +818,17 @@ private void processSendWork() { } sendData.getWork().completeExceptionally(sendException != null - ? new OperationCancelledException("Send operation failed. Please see cause for more details", sendException) + ? new OperationCancelledException(String.format(Locale.US, + "Entity(%s): send operation failed. Please see cause for more details", this.sendPath), sendException) : new OperationCancelledException( - String.format(Locale.US, "Send operation failed while advancing delivery(tag: %s) on SendLink(path: %s).", this.sendPath, deliveryTag))); + String.format(Locale.US, "Entity(%s): send operation failed while advancing delivery(tag: %s).", this.sendPath, deliveryTag))); } } else { if (deliveryTag != null) { if (TRACE_LOGGER.isDebugEnabled()) { TRACE_LOGGER.debug( - String.format(Locale.US, "path[%s], linkName[%s], deliveryTag[%s] - sendData not found for this delivery.", - this.sendPath, this.sendLink.getName(), deliveryTag)); + String.format(Locale.US, "clientId[%s], path[%s], linkName[%s], deliveryTag[%s] - sendData not found for this delivery.", + this.getClientId(), this.sendPath, this.sendLink.getName(), deliveryTag)); } } @@ -840,7 +859,8 @@ private void throwSenderTimeout(final CompletableFuture pendingSendWork, f final boolean isClientSideTimeout = (cause == null || !(cause instanceof EventHubException)); final EventHubException exception = isClientSideTimeout - ? new TimeoutException(String.format(Locale.US, "%s %s %s.", MessageSender.SEND_TIMED_OUT, " at ", ZonedDateTime.now()), cause) + ? new TimeoutException(String.format(Locale.US, "Entity(%s): %s at %s.", + this.sendPath, MessageSender.SEND_TIMED_OUT, ZonedDateTime.now()), cause) : (EventHubException) cause; ExceptionUtil.completeExceptionally(pendingSendWork, exception, this); @@ -858,10 +878,11 @@ public void run() { } final Exception operationTimedout = new TimeoutException(String.format(Locale.US, - "%s operation on Sender Link(%s) timed out at %s", "Close", link.getName(), ZonedDateTime.now())); + "Entity(%s): close operation timed out at %s", MessageSender.this.sendPath, ZonedDateTime.now())); if (TRACE_LOGGER.isInfoEnabled()) { TRACE_LOGGER.info( - String.format(Locale.US, "message sender(linkName: %s, path: %s) %s call timedout", link.getName(), MessageSender.this.sendPath, "Close"), + String.format(Locale.US, "clientId[%s], message sender(linkName: %s, path: %s) close call timed out", + MessageSender.this.getClientId(), link.getName(), MessageSender.this.sendPath), operationTimedout); } @@ -894,8 +915,9 @@ public void onEvent() { if (sendLink != null && sendLink.getLocalState() != EndpointState.CLOSED) { sendLink.close(); } else if (sendLink == null || sendLink.getRemoteState() == EndpointState.CLOSED) { - if (closeTimer != null) + if (closeTimer != null && !closeTimer.isCancelled()) { closeTimer.cancel(false); + } linkClose.complete(null); } diff --git a/azure-eventhubs/src/main/java/com/microsoft/azure/eventhubs/impl/MessagingFactory.java b/azure-eventhubs/src/main/java/com/microsoft/azure/eventhubs/impl/MessagingFactory.java index 52745ba89e88..c69bdbec8ed7 100644 --- a/azure-eventhubs/src/main/java/com/microsoft/azure/eventhubs/impl/MessagingFactory.java +++ b/azure-eventhubs/src/main/java/com/microsoft/azure/eventhubs/impl/MessagingFactory.java @@ -5,16 +5,11 @@ package com.microsoft.azure.eventhubs.impl; +import com.microsoft.azure.eventhubs.*; +import com.microsoft.azure.eventhubs.TimeoutException; import org.apache.qpid.proton.amqp.transport.ErrorCondition; -import org.apache.qpid.proton.engine.BaseHandler; -import org.apache.qpid.proton.engine.Connection; -import org.apache.qpid.proton.engine.Event; -import org.apache.qpid.proton.engine.EndpointState; -import org.apache.qpid.proton.engine.Handler; -import org.apache.qpid.proton.engine.HandlerException; -import org.apache.qpid.proton.engine.Link; +import org.apache.qpid.proton.engine.*; import org.apache.qpid.proton.reactor.Reactor; -import org.apache.qpid.proton.engine.Session; import org.slf4j.Logger; import org.slf4j.LoggerFactory; @@ -24,20 +19,10 @@ import java.util.LinkedList; import java.util.List; import java.util.Locale; -import java.util.concurrent.CancellationException; -import java.util.concurrent.CompletableFuture; -import java.util.concurrent.Executor; -import java.util.concurrent.RejectedExecutionException; +import java.util.concurrent.*; import java.util.function.BiConsumer; import java.util.function.Consumer; -import com.microsoft.azure.eventhubs.ConnectionStringBuilder; -import com.microsoft.azure.eventhubs.CommunicationException; -import com.microsoft.azure.eventhubs.EventHubException; -import com.microsoft.azure.eventhubs.OperationCancelledException; -import com.microsoft.azure.eventhubs.RetryPolicy; -import com.microsoft.azure.eventhubs.TimeoutException; - /** * Abstracts all amqp related details and exposes AmqpConnection object * Manages connection life-cycle @@ -57,11 +42,10 @@ public final class MessagingFactory extends ClientEntity implements AmqpConnecti private final ReactorFactory reactorFactory; private Reactor reactor; - private ReactorDispatcher reactorScheduler; + private ReactorDispatcher reactorDispatcher; private Connection connection; private CBSChannel cbsChannel; private ManagementChannel mgmtChannel; - private Duration operationTimeout; private RetryPolicy retryPolicy; private CompletableFuture open; @@ -70,13 +54,12 @@ public final class MessagingFactory extends ClientEntity implements AmqpConnecti MessagingFactory(final ConnectionStringBuilder builder, final RetryPolicy retryPolicy, - final Executor executor, + final ScheduledExecutorService executor, final ReactorFactory reactorFactory) { super("MessagingFactory".concat(StringUtil.getRandomString()), null, executor); this.hostName = builder.getEndpoint().getHost(); this.reactorFactory = reactorFactory; - this.operationTimeout = builder.getOperationTimeout(); this.retryPolicy = retryPolicy; this.registeredLinks = new LinkedList<>(); @@ -91,21 +74,21 @@ public final class MessagingFactory extends ClientEntity implements AmqpConnecti this.closeTask = new CompletableFuture<>(); } - public static CompletableFuture createFromConnectionString(final String connectionString, final Executor executor) throws IOException { + public static CompletableFuture createFromConnectionString(final String connectionString, final ScheduledExecutorService executor) throws IOException { return createFromConnectionString(connectionString, RetryPolicy.getDefault(), executor); } public static CompletableFuture createFromConnectionString( final String connectionString, final RetryPolicy retryPolicy, - final Executor executor) throws IOException { + final ScheduledExecutorService executor) throws IOException { return createFromConnectionString(connectionString, retryPolicy, executor, new ReactorFactory()); } public static CompletableFuture createFromConnectionString( final String connectionString, final RetryPolicy retryPolicy, - final Executor executor, + final ScheduledExecutorService executor, final ReactorFactory reactorFactory) throws IOException { final ConnectionStringBuilder builder = new ConnectionStringBuilder(connectionString); final MessagingFactory messagingFactory = new MessagingFactory(builder, @@ -153,9 +136,9 @@ private Reactor getReactor() { } } - public ReactorDispatcher getReactorScheduler() { + public ReactorDispatcher getReactorDispatcher() { synchronized (this.reactorLock) { - return this.reactorScheduler; + return this.reactorDispatcher; } } @@ -165,26 +148,15 @@ public SharedAccessSignatureTokenProvider getTokenProvider() { private void createConnection() throws IOException { this.open = new CompletableFuture<>(); - this.startReactor(new ReactorHandler() { - @Override - public void onReactorInit(Event e) { - super.onReactorInit(e); - - final Reactor r = e.getReactor(); - connection = r.connectionToHost( - connectionHandler.getRemoteHostName(), - connectionHandler.getRemotePort(), - connectionHandler); - } - }); + this.startReactor(new ReactorHandlerWithConnection()); } private void startReactor(final ReactorHandler reactorHandler) throws IOException { final Reactor newReactor = this.reactorFactory.create(reactorHandler, this.connectionHandler.getMaxFrameSize()); synchronized (this.reactorLock) { this.reactor = newReactor; - this.reactorScheduler = new ReactorDispatcher(newReactor); - reactorHandler.unsafeSetReactorDispatcher(this.reactorScheduler); + this.reactorDispatcher = new ReactorDispatcher(newReactor); + reactorHandler.unsafeSetReactorDispatcher(this.reactorDispatcher); } executor.execute(new RunReactor(newReactor, executor)); @@ -226,7 +198,7 @@ public Session getSession(final String path, final Consumer onRemoteSes } final Session session = this.connection.session(); - BaseHandler.setHandler(session, new SessionHandler(path, onRemoteSessionOpen, onRemoteSessionOpenError)); + BaseHandler.setHandler(session, new SessionHandler(path, onRemoteSessionOpen, onRemoteSessionOpenError, this.operationTimeout)); session.open(); return session; @@ -258,16 +230,35 @@ public void onOpenComplete(Exception exception) { @Override public void onConnectionError(ErrorCondition error) { + if (TRACE_LOGGER.isWarnEnabled()) { + TRACE_LOGGER.warn(String.format(Locale.US, "onConnectionError: messagingFactory[%s], hostname[%s], error[%s]", + this.getClientId(), + this.hostName, + error != null ? error.getDescription() : "n/a")); + } if (!this.open.isDone()) { + if (TRACE_LOGGER.isWarnEnabled()) { + TRACE_LOGGER.warn(String.format(Locale.US, "onConnectionError: messagingFactory[%s], hostname[%s], open hasn't complete, stopping the reactor", + this.getClientId(), + this.hostName)); + } + this.getReactor().stop(); this.onOpenComplete(ExceptionUtil.toException(error)); } else { - final Connection currentConnection = this.connection; - final List registeredLinksCopy = new LinkedList<>(this.registeredLinks); + final Connection oldConnection = this.connection; + final List oldRegisteredLinksCopy = new LinkedList<>(this.registeredLinks); final List closedLinks = new LinkedList<>(); - for (Link link : registeredLinksCopy) { + + for (Link link : oldRegisteredLinksCopy) { if (link.getLocalState() != EndpointState.CLOSED && link.getRemoteState() != EndpointState.CLOSED) { + if (TRACE_LOGGER.isWarnEnabled()) { + TRACE_LOGGER.warn(String.format(Locale.US, "onConnectionError: messagingFactory[%s], hostname[%s], closing link [%s]", + this.getClientId(), + this.hostName, link.getName())); + } + link.close(); closedLinks.add(link); } @@ -275,11 +266,18 @@ public void onConnectionError(ErrorCondition error) { // if proton-j detects transport error - onConnectionError is invoked, but, the connection state is not set to closed // in connection recreation we depend on currentConnection state to evaluate need for recreation - if (currentConnection.getLocalState() != EndpointState.CLOSED) { + if (oldConnection.getLocalState() != EndpointState.CLOSED) { + if (TRACE_LOGGER.isWarnEnabled()) { + TRACE_LOGGER.warn(String.format(Locale.US, "onConnectionError: messagingFactory[%s], hostname[%s], closing current connection", + this.getClientId(), + this.hostName)); + } + // this should ideally be done in Connectionhandler // - but, since proton doesn't automatically emit close events // for all child objects (links & sessions) we are doing it here - currentConnection.close(); + oldConnection.setCondition(error); + oldConnection.close(); } for (Link link : closedLinks) { @@ -300,19 +298,29 @@ private void onReactorError(Exception cause) { if (!this.open.isDone()) { this.onOpenComplete(cause); } else { - final Connection currentConnection = this.connection; + if (this.getIsClosingOrClosed()) { + return; + } + + TRACE_LOGGER.warn(String.format(Locale.US, "onReactorError messagingFactory[%s], hostName[%s], error[%s]", + this.getClientId(), this.getHostName(), + cause.getMessage())); + + final Connection oldConnection = this.connection; + final List oldRegisteredLinksCopy = new LinkedList<>(this.registeredLinks); try { - if (this.getIsClosingOrClosed()) { - return; - } else { - this.startReactor(new ReactorHandler()); - } + TRACE_LOGGER.info(String.format(Locale.US, "onReactorError messagingFactory[%s], hostName[%s], message[%s]", + this.getClientId(), this.getHostName(), + "starting new reactor")); + + this.startReactor(new ReactorHandlerWithConnection()); } catch (IOException e) { TRACE_LOGGER.error(String.format(Locale.US, "messagingFactory[%s], hostName[%s], error[%s]", this.getClientId(), this.getHostName(), ExceptionUtil.toStackTraceString(e, "Re-starting reactor failed with error"))); + // TODO - stop retrying on the error after multiple attempts. this.onReactorError(cause); } @@ -320,12 +328,11 @@ private void onReactorError(Exception cause) { // below .close() calls (local closes). // But, we still need to change the states of these to Closed - so that subsequent retries - will // treat the links and connection as closed and re-establish them and continue running on new Reactor instance. - if (currentConnection.getLocalState() != EndpointState.CLOSED && currentConnection.getRemoteState() != EndpointState.CLOSED) { - currentConnection.close(); + if (oldConnection.getLocalState() != EndpointState.CLOSED && oldConnection.getRemoteState() != EndpointState.CLOSED) { + oldConnection.close(); } - final List registeredLinksCopy = new LinkedList<>(this.registeredLinks); - for (final Link link : registeredLinksCopy) { + for (final Link link : oldRegisteredLinksCopy) { if (link.getLocalState() != EndpointState.CLOSED && link.getRemoteState() != EndpointState.CLOSED) { link.close(); } @@ -379,11 +386,11 @@ public void deregisterForConnectionError(Link link) { } public void scheduleOnReactorThread(final DispatchHandler handler) throws IOException, RejectedExecutionException { - this.getReactorScheduler().invoke(handler); + this.getReactorDispatcher().invoke(handler); } public void scheduleOnReactorThread(final int delay, final DispatchHandler handler) throws IOException, RejectedExecutionException { - this.getReactorScheduler().invoke(delay, handler); + this.getReactorDispatcher().invoke(delay, handler); } public static class ReactorFactory { @@ -396,15 +403,12 @@ public Reactor create(final ReactorHandler reactorHandler, final int maxFrameSiz private class CloseWork extends DispatchHandler { @Override public void onEvent() { - final ReactorDispatcher dispatcher = getReactorScheduler(); + final ReactorDispatcher dispatcher = getReactorDispatcher(); synchronized (cbsChannelCreateLock) { - if (cbsChannel != null) { - cbsChannel.close( dispatcher, new OperationResult() { - @Override public void onComplete(Void result) { if (TRACE_LOGGER.isInfoEnabled()) { @@ -416,7 +420,6 @@ public void onComplete(Void result) { @Override public void onError(Exception error) { - if (TRACE_LOGGER.isWarnEnabled()) { TRACE_LOGGER.warn(String.format(Locale.US, "messagingFactory[%s], hostName[%s], cbsChannelCloseError[%s]", @@ -428,12 +431,10 @@ public void onError(Exception error) { } synchronized (mgmtChannelCreateLock) { - if (mgmtChannel != null) { mgmtChannel.close( dispatcher, new OperationResult() { - @Override public void onComplete(Void result) { if (TRACE_LOGGER.isInfoEnabled()) { @@ -456,33 +457,34 @@ public void onError(Exception error) { } } - if (connection != null && connection.getRemoteState() != EndpointState.CLOSED && connection.getLocalState() != EndpointState.CLOSED) + if (connection != null && connection.getRemoteState() != EndpointState.CLOSED && connection.getLocalState() != EndpointState.CLOSED) { connection.close(); + } } } private class RunReactor implements Runnable { final private Reactor rctr; - final private Executor executor; + final private ScheduledExecutorService executor; volatile boolean hasStarted; - public RunReactor(final Reactor reactor, final Executor executor) { + public RunReactor(final Reactor reactor, final ScheduledExecutorService executor) { this.rctr = reactor; this.executor = executor; this.hasStarted = false; } public void run() { - if (TRACE_LOGGER.isInfoEnabled() && !this.hasStarted) { - TRACE_LOGGER.info(String.format(Locale.US, "messagingFactory[%s], hostName[%s], info[%s]", - getClientId(), getHostName(), "starting reactor instance.")); - } - boolean reScheduledReactor = false; try { if (!this.hasStarted) { + if (TRACE_LOGGER.isInfoEnabled()) { + TRACE_LOGGER.info(String.format(Locale.US, "messagingFactory[%s], hostName[%s], info[%s]", + getClientId(), getHostName(), "starting reactor instance.")); + } + this.rctr.start(); this.hasStarted = true; } @@ -495,7 +497,7 @@ public void run() { if (TRACE_LOGGER.isWarnEnabled()) { TRACE_LOGGER.warn(String.format(Locale.US, "messagingFactory[%s], hostName[%s], error[%s]", getClientId(), getHostName(), - ExceptionUtil.toStackTraceString(exception, "scheduling reactor failed"))); + ExceptionUtil.toStackTraceString(exception, "scheduling reactor failed because the executor has been shut down"))); } this.rctr.attachments().set(RejectedExecutionException.class, RejectedExecutionException.class, exception); @@ -504,6 +506,12 @@ public void run() { return; } + if (TRACE_LOGGER.isWarnEnabled()) { + TRACE_LOGGER.warn(String.format(Locale.US, "messagingFactory[%s], hostName[%s], message[%s]", + getClientId(), getHostName(), + "stopping the reactor because thread was interrupted or the reactor has no more events to process.")); + } + this.rctr.stop(); } catch (HandlerException handlerException) { Throwable cause = handlerException.getCause(); @@ -543,15 +551,55 @@ public void run() { return; } - this.rctr.free(); - if (getIsClosingOrClosed() && !closeTask.isDone()) { + this.rctr.free(); closeTask.complete(null); - - if (closeTimer != null) + if (closeTimer != null) { closeTimer.cancel(false); + } + } else { + scheduleCompletePendingTasks(); } } } + + private void scheduleCompletePendingTasks() { + this.executor.schedule(new Runnable() { + @Override + public void run() { + if (TRACE_LOGGER.isWarnEnabled()) { + TRACE_LOGGER.warn(String.format(Locale.US, "messagingFactory[%s], hostName[%s], message[%s]", + getClientId(), getHostName(), + "Processing all pending tasks and closing old reactor.")); + } + + try { + rctr.stop(); + rctr.process(); + } catch (HandlerException e) { + if (TRACE_LOGGER.isWarnEnabled()) { + TRACE_LOGGER.warn(String.format(Locale.US, "messagingFactory[%s], hostName[%s], error[%s]", + getClientId(), getHostName(), ExceptionUtil.toStackTraceString(e, + "scheduleCompletePendingTasks - exception occurred while processing events."))); + } + } finally { + rctr.free(); + } + } + }, MessagingFactory.this.getOperationTimeout().getSeconds(), TimeUnit.SECONDS); + } + } + + private class ReactorHandlerWithConnection extends ReactorHandler { + @Override + public void onReactorInit(Event e) { + super.onReactorInit(e); + + final Reactor r = e.getReactor(); + connection = r.connectionToHost( + connectionHandler.getRemoteHostName(), + connectionHandler.getRemotePort(), + connectionHandler); + } } } diff --git a/azure-eventhubs/src/main/java/com/microsoft/azure/eventhubs/impl/PartitionReceiverImpl.java b/azure-eventhubs/src/main/java/com/microsoft/azure/eventhubs/impl/PartitionReceiverImpl.java index e3569534a2e5..3e06503835f8 100644 --- a/azure-eventhubs/src/main/java/com/microsoft/azure/eventhubs/impl/PartitionReceiverImpl.java +++ b/azure-eventhubs/src/main/java/com/microsoft/azure/eventhubs/impl/PartitionReceiverImpl.java @@ -15,7 +15,7 @@ import java.time.Duration; import java.util.*; import java.util.concurrent.CompletableFuture; -import java.util.concurrent.Executor; +import java.util.concurrent.ScheduledExecutorService; import java.util.function.Consumer; import java.util.function.Function; @@ -46,8 +46,8 @@ private PartitionReceiverImpl(MessagingFactory factory, final Long epoch, final boolean isEpochReceiver, final ReceiverOptions receiverOptions, - final Executor executor) { - super(null, null, executor); + final ScheduledExecutorService executor) { + super("PartitionReceiverImpl".concat(StringUtil.getRandomString()), null, executor); this.underlyingFactory = factory; this.eventHubName = eventHubName; @@ -72,8 +72,7 @@ static CompletableFuture create(MessagingFactory factory, final long epoch, final boolean isEpochReceiver, ReceiverOptions receiverOptions, - final Executor executor) - throws EventHubException { + final ScheduledExecutorService executor) { if (epoch < NULL_EPOCH) { throw new IllegalArgumentException("epoch cannot be a negative value. Please specify a zero or positive long value."); } @@ -96,7 +95,7 @@ public PartitionReceiver apply(Void a) { private CompletableFuture createInternalReceiver() { return MessageReceiver.create(this.underlyingFactory, - StringUtil.getRandomString(), + this.getClientId().concat("-InternalReceiver"), String.format("%s/ConsumerGroups/%s/Partitions/%s", this.eventHubName, this.consumerGroupName, this.partitionId), this.receiverOptions.getPrefetchCount(), this) .thenAcceptAsync(new Consumer() { @@ -179,6 +178,8 @@ public CompletableFuture setReceiveHandler(final PartitionReceiveHandler r "Unexpected value for parameter 'receiveHandler'. PartitionReceiver was already registered with a PartitionReceiveHandler instance. Only 1 instance can be registered."); this.receivePump = new ReceivePump( + this.eventHubName, + this.consumerGroupName, new ReceivePump.IPartitionReceiver() { @Override public CompletableFuture> receive(int maxBatchSize) { diff --git a/azure-eventhubs/src/main/java/com/microsoft/azure/eventhubs/impl/PartitionSenderImpl.java b/azure-eventhubs/src/main/java/com/microsoft/azure/eventhubs/impl/PartitionSenderImpl.java index 9719c2afdce7..8acdc2a27d05 100644 --- a/azure-eventhubs/src/main/java/com/microsoft/azure/eventhubs/impl/PartitionSenderImpl.java +++ b/azure-eventhubs/src/main/java/com/microsoft/azure/eventhubs/impl/PartitionSenderImpl.java @@ -7,7 +7,7 @@ import com.microsoft.azure.eventhubs.*; import java.util.concurrent.CompletableFuture; -import java.util.concurrent.Executor; +import java.util.concurrent.ScheduledExecutorService; import java.util.function.Consumer; import java.util.function.Function; @@ -18,8 +18,8 @@ final class PartitionSenderImpl extends ClientEntity implements PartitionSender private volatile MessageSender internalSender; - private PartitionSenderImpl(final MessagingFactory factory, final String eventHubName, final String partitionId, final Executor executor) { - super(null, null, executor); + private PartitionSenderImpl(final MessagingFactory factory, final String eventHubName, final String partitionId, final ScheduledExecutorService executor) { + super("PartitionSenderImpl".concat(StringUtil.getRandomString()), null, executor); this.partitionId = partitionId; this.eventHubName = eventHubName; @@ -29,7 +29,7 @@ private PartitionSenderImpl(final MessagingFactory factory, final String eventHu static CompletableFuture Create(final MessagingFactory factory, final String eventHubName, final String partitionId, - final Executor executor) throws EventHubException { + final ScheduledExecutorService executor) throws EventHubException { final PartitionSenderImpl sender = new PartitionSenderImpl(factory, eventHubName, partitionId, executor); return sender.createInternalSender() .thenApplyAsync(new Function() { @@ -40,7 +40,7 @@ public PartitionSender apply(Void a) { } private CompletableFuture createInternalSender() throws EventHubException { - return MessageSender.create(this.factory, StringUtil.getRandomString(), + return MessageSender.create(this.factory, this.getClientId().concat("-InternalSender"), String.format("%s/Partitions/%s", this.eventHubName, this.partitionId)) .thenAcceptAsync(new Consumer() { public void accept(MessageSender a) { diff --git a/azure-eventhubs/src/main/java/com/microsoft/azure/eventhubs/impl/ReactorDispatcher.java b/azure-eventhubs/src/main/java/com/microsoft/azure/eventhubs/impl/ReactorDispatcher.java index 5c99b69d0970..6aad0e296670 100644 --- a/azure-eventhubs/src/main/java/com/microsoft/azure/eventhubs/impl/ReactorDispatcher.java +++ b/azure-eventhubs/src/main/java/com/microsoft/azure/eventhubs/impl/ReactorDispatcher.java @@ -80,7 +80,7 @@ private void throwIfSchedulerError() { // throw when the pipe is in closed state - in which case, // signalling the new event-dispatch will fail - if (!this.ioSignal.source().isOpen() || !this.ioSignal.sink().isOpen()) { + if (!this.ioSignal.sink().isOpen()) { throw new RejectedExecutionException("ReactorDispatcher instance is closed."); } } @@ -121,7 +121,7 @@ public void run(Selectable selectable) { } catch (ClosedChannelException ignorePipeClosedDuringReactorShutdown) { TRACE_LOGGER.info("ScheduleHandler.run() failed with an error", ignorePipeClosedDuringReactorShutdown); } catch (IOException ioException) { - TRACE_LOGGER.info("ScheduleHandler.run() failed with an error", ioException); + TRACE_LOGGER.warn("ScheduleHandler.run() failed with an error", ioException); throw new RuntimeException(ioException); } @@ -135,17 +135,11 @@ public void run(Selectable selectable) { private final class CloseHandler implements Callback { @Override public void run(Selectable selectable) { - try { - selectable.getChannel().close(); - } catch (IOException ioException) { - TRACE_LOGGER.info("CloseHandler.run() failed with an error", ioException); - } - try { if (ioSignal.sink().isOpen()) ioSignal.sink().close(); } catch (IOException ioException) { - TRACE_LOGGER.info("CloseHandler.run() failed with an error", ioException); + TRACE_LOGGER.info("CloseHandler.run() sink().close() failed with an error", ioException); } workScheduler.run(null); @@ -154,7 +148,7 @@ public void run(Selectable selectable) { if (ioSignal.source().isOpen()) ioSignal.source().close(); } catch (IOException ioException) { - TRACE_LOGGER.info("CloseHandler.run() failed with an error", ioException); + TRACE_LOGGER.info("CloseHandler.run() source().close() failed with an error", ioException); } } } diff --git a/azure-eventhubs/src/main/java/com/microsoft/azure/eventhubs/impl/ReceiveLinkHandler.java b/azure-eventhubs/src/main/java/com/microsoft/azure/eventhubs/impl/ReceiveLinkHandler.java index e482a4f8f6f3..db32fe36d881 100644 --- a/azure-eventhubs/src/main/java/com/microsoft/azure/eventhubs/impl/ReceiveLinkHandler.java +++ b/azure-eventhubs/src/main/java/com/microsoft/azure/eventhubs/impl/ReceiveLinkHandler.java @@ -37,7 +37,7 @@ public void onLinkLocalOpen(Event evt) { if (TRACE_LOGGER.isInfoEnabled()) { TRACE_LOGGER.info( - String.format("linkName[%s], localSource[%s]", receiver.getName(), receiver.getSource())); + String.format("onLinkLocalOpen linkName[%s], localSource[%s]", receiver.getName(), receiver.getSource())); } } } @@ -45,11 +45,12 @@ public void onLinkLocalOpen(Event evt) { @Override public void onLinkRemoteOpen(Event event) { Link link = event.getLink(); - if (link != null && link instanceof Receiver) { + if (link instanceof Receiver) { Receiver receiver = (Receiver) link; if (link.getRemoteSource() != null) { if (TRACE_LOGGER.isInfoEnabled()) { - TRACE_LOGGER.info(String.format(Locale.US, "linkName[%s], remoteSource[%s]", receiver.getName(), link.getRemoteSource())); + TRACE_LOGGER.info(String.format(Locale.US, "onLinkRemoteOpen linkName[%s], remoteSource[%s]", + receiver.getName(), link.getRemoteSource())); } synchronized (this.firstResponse) { @@ -59,7 +60,8 @@ public void onLinkRemoteOpen(Event event) { } else { if (TRACE_LOGGER.isInfoEnabled()) { TRACE_LOGGER.info( - String.format(Locale.US, "linkName[%s], remoteTarget[null], remoteSource[null], action[waitingForError]", receiver.getName())); + String.format(Locale.US, "onLinkRemoteOpen linkName[%s], remoteTarget[null], " + + "remoteSource[null], action[waitingForError]", receiver.getName())); } } } @@ -89,8 +91,9 @@ public void onDelivery(Event event) { if (TRACE_LOGGER.isWarnEnabled()) { TRACE_LOGGER.warn( receiveLink != null - ? String.format(Locale.US, "linkName[%s], updatedLinkCredit[%s], remoteCredit[%s], remoteCondition[%s], delivery.isSettled[%s]", - receiveLink.getName(), receiveLink.getCredit(), receiveLink.getRemoteCredit(), receiveLink.getRemoteCondition(), delivery.isSettled()) + ? String.format(Locale.US, "onDelivery linkName[%s], updatedLinkCredit[%s], remoteCredit[%s], " + + "remoteCondition[%s], delivery.isSettled[%s]", + receiveLink.getName(), receiveLink.getCredit(), receiveLink.getRemoteCredit(), receiveLink.getRemoteCondition(), delivery.isSettled()) : String.format(Locale.US, "delivery.isSettled[%s]", delivery.isSettled())); } } else { @@ -100,7 +103,8 @@ public void onDelivery(Event event) { if (TRACE_LOGGER.isTraceEnabled() && receiveLink != null) { TRACE_LOGGER.trace( - String.format(Locale.US, "linkName[%s], updatedLinkCredit[%s], remoteCredit[%s], remoteCondition[%s], delivery.isPartial[%s]", + String.format(Locale.US, "onDelivery linkName[%s], updatedLinkCredit[%s], remoteCredit[%s], " + + "remoteCondition[%s], delivery.isPartial[%s]", receiveLink.getName(), receiveLink.getCredit(), receiveLink.getRemoteCredit(), receiveLink.getRemoteCondition(), delivery.isPartial())); } } diff --git a/azure-eventhubs/src/main/java/com/microsoft/azure/eventhubs/impl/ReceivePump.java b/azure-eventhubs/src/main/java/com/microsoft/azure/eventhubs/impl/ReceivePump.java index a48545410f16..b60e67db0462 100644 --- a/azure-eventhubs/src/main/java/com/microsoft/azure/eventhubs/impl/ReceivePump.java +++ b/azure-eventhubs/src/main/java/com/microsoft/azure/eventhubs/impl/ReceivePump.java @@ -6,7 +6,6 @@ import com.microsoft.azure.eventhubs.EventData; import com.microsoft.azure.eventhubs.PartitionReceiveHandler; - import org.slf4j.Logger; import org.slf4j.LoggerFactory; @@ -25,15 +24,21 @@ public class ReceivePump implements Runnable { private final CompletableFuture stopPump; private final Executor executor; private final ProcessAndReschedule processAndReschedule; + private final String eventHubName; + private final String consumerGroupName; private AtomicBoolean stopPumpRaised; private volatile boolean isPumpHealthy = true; public ReceivePump( + final String eventHubName, + final String consumerGroupName, final IPartitionReceiver receiver, final PartitionReceiveHandler receiveHandler, final boolean invokeOnReceiveWithNoEvents, final Executor executor) { + this.eventHubName = eventHubName; + this.consumerGroupName = consumerGroupName; this.receiver = receiver; this.onReceiveHandler = receiveHandler; this.invokeOnTimeout = invokeOnReceiveWithNoEvents; @@ -51,8 +56,9 @@ public void run() { } catch (final Exception exception) { if (TRACE_LOGGER.isErrorEnabled()) { TRACE_LOGGER.error( - String.format("Receive pump for partition (%s) encountered unrecoverable error and exited with exception %s.", - ReceivePump.this.receiver.getPartitionId(), exception.toString())); + String.format("Receive pump for eventHub (%s), consumerGroup (%s), partition (%s) " + + "encountered unrecoverable error and exited with exception %s.", + this.eventHubName, this.consumerGroupName, this.receiver.getPartitionId(), exception.toString())); } throw exception; @@ -63,11 +69,11 @@ public void run() { public void receiveAndProcess() { if (this.shouldContinue()) { this.receiver.receive(this.onReceiveHandler.getMaxEventCount()) - .handleAsync(this.processAndReschedule, this.executor); + .handleAsync(this.processAndReschedule, this.executor); } else { if (TRACE_LOGGER.isInfoEnabled()) { - TRACE_LOGGER.info(String.format("Stopping receive pump for partition (%s) as %s", - ReceivePump.this.receiver.getPartitionId(), + TRACE_LOGGER.info(String.format("Stopping receive pump for eventHub (%s), consumerGroup (%s), partition (%s) as %s", + this.eventHubName, this.consumerGroupName, this.receiver.getPartitionId(), this.stopPumpRaised.get() ? "per the request." : "pump ran into errors.")); } @@ -84,13 +90,6 @@ public boolean isRunning() { return !this.stopPump.isDone(); } - // partition receiver contract against which this pump works - public interface IPartitionReceiver { - String getPartitionId(); - - CompletableFuture> receive(final int maxBatchSize); - } - private boolean shouldContinue() { return this.isPumpHealthy && !this.stopPumpRaised.get(); } @@ -101,8 +100,8 @@ private void handleClientExceptions(final Throwable clientException) { if (TRACE_LOGGER.isWarnEnabled()) { TRACE_LOGGER.warn(String.format( - "Receive pump for partition (%s) exiting after receive exception %s", - this.receiver.getPartitionId(), clientException.toString())); + "Receive pump for eventHub (%s), consumerGroup (%s), partition (%s) exiting after receive exception %s", + this.eventHubName, this.consumerGroupName, this.receiver.getPartitionId(), clientException.toString())); } this.onReceiveHandler.onError(clientException); @@ -113,16 +112,17 @@ private void handleUserCodeExceptions(final Throwable userCodeException) { this.isPumpHealthy = false; if (TRACE_LOGGER.isErrorEnabled()) { TRACE_LOGGER.error( - String.format("Receive pump for partition (%s) exiting after user-code exception %s", - this.receiver.getPartitionId(), userCodeException.toString())); + String.format("Receive pump for eventHub (%s), consumerGroup (%s), partition (%s) " + + "exiting after user-code exception %s", + this.eventHubName, this.consumerGroupName, this.receiver.getPartitionId(), userCodeException.toString())); } this.onReceiveHandler.onError(userCodeException); if (userCodeException instanceof InterruptedException) { if (TRACE_LOGGER.isInfoEnabled()) { - TRACE_LOGGER.info(String.format("Interrupting receive pump for partition (%s)", - this.receiver.getPartitionId())); + TRACE_LOGGER.info(String.format("Interrupting receive pump for eventHub (%s), consumerGroup (%s), partition (%s)", + this.eventHubName, this.consumerGroupName, this.receiver.getPartitionId())); } Thread.currentThread().interrupt(); @@ -137,14 +137,21 @@ private void schedulePump() { if (TRACE_LOGGER.isWarnEnabled()) { TRACE_LOGGER.warn(String.format( - "Receive pump for partition (%s) exiting with error: %s", - ReceivePump.this.receiver.getPartitionId(), rejectedException.toString())); + "Receive pump for eventHub (%s), consumerGroup (%s), partition (%s) exiting with error: %s", + this.eventHubName, this.consumerGroupName, ReceivePump.this.receiver.getPartitionId(), rejectedException.toString())); } this.onReceiveHandler.onError(rejectedException); } } + // partition receiver contract against which this pump works + public interface IPartitionReceiver { + String getPartitionId(); + + CompletableFuture> receive(final int maxBatchSize); + } + private final class ProcessAndReschedule implements BiFunction, Throwable, Void> { @Override @@ -156,7 +163,7 @@ public Void apply(final Iterable receivedEvents, final Throwable clie // don't invoke user call back - if stop is already raised / pump is unhealthy if (ReceivePump.this.shouldContinue() && (receivedEvents != null - || (receivedEvents == null && ReceivePump.this.invokeOnTimeout))) { + || (receivedEvents == null && ReceivePump.this.invokeOnTimeout))) { ReceivePump.this.onReceiveHandler.onReceive(receivedEvents); } } catch (final Throwable userCodeError) { diff --git a/azure-eventhubs/src/main/java/com/microsoft/azure/eventhubs/impl/SchedulerProvider.java b/azure-eventhubs/src/main/java/com/microsoft/azure/eventhubs/impl/SchedulerProvider.java index 14d1bbcbabc3..03e6d91c9d8c 100644 --- a/azure-eventhubs/src/main/java/com/microsoft/azure/eventhubs/impl/SchedulerProvider.java +++ b/azure-eventhubs/src/main/java/com/microsoft/azure/eventhubs/impl/SchedulerProvider.java @@ -2,5 +2,5 @@ interface SchedulerProvider { - ReactorDispatcher getReactorScheduler(); + ReactorDispatcher getReactorDispatcher(); } diff --git a/azure-eventhubs/src/main/java/com/microsoft/azure/eventhubs/impl/SendLinkHandler.java b/azure-eventhubs/src/main/java/com/microsoft/azure/eventhubs/impl/SendLinkHandler.java index 2a4b66117f14..8a9df26a626c 100644 --- a/azure-eventhubs/src/main/java/com/microsoft/azure/eventhubs/impl/SendLinkHandler.java +++ b/azure-eventhubs/src/main/java/com/microsoft/azure/eventhubs/impl/SendLinkHandler.java @@ -27,14 +27,25 @@ public SendLinkHandler(final AmqpSender sender) { this.isFirstFlow = true; } + @Override + public void onLinkLocalOpen(Event event) { + Link link = event.getLink(); + if (link instanceof Sender) { + Sender sender = (Sender) link; + if (TRACE_LOGGER.isInfoEnabled()) { + TRACE_LOGGER.info(String.format("onLinkLocalOpen linkName[%s], localTarget[%s]", sender.getName(), sender.getTarget())); + } + } + } + @Override public void onLinkRemoteOpen(Event event) { Link link = event.getLink(); - if (link != null && link instanceof Sender) { + if (link instanceof Sender) { Sender sender = (Sender) link; if (link.getRemoteTarget() != null) { if (TRACE_LOGGER.isInfoEnabled()) { - TRACE_LOGGER.info(String.format(Locale.US, "linkName[%s], remoteTarget[%s]", sender.getName(), link.getRemoteTarget())); + TRACE_LOGGER.info(String.format(Locale.US, "onLinkRemoteOpen linkName[%s], remoteTarget[%s]", sender.getName(), link.getRemoteTarget())); } synchronized (this.firstFlow) { @@ -44,7 +55,7 @@ public void onLinkRemoteOpen(Event event) { } else { if (TRACE_LOGGER.isInfoEnabled()) { TRACE_LOGGER.info( - String.format(Locale.US, "linkName[%s], remoteTarget[null], remoteSource[null], action[waitingForError]", sender.getName())); + String.format(Locale.US, "onLinkRemoteOpen linkName[%s], remoteTarget[null], remoteSource[null], action[waitingForError]", sender.getName())); } } } @@ -59,7 +70,7 @@ public void onDelivery(Event event) { if (TRACE_LOGGER.isTraceEnabled()) { TRACE_LOGGER.trace( - "linkName[" + sender.getName() + + "onDelivery linkName[" + sender.getName() + "], unsettled[" + sender.getUnsettled() + "], credit[" + sender.getRemoteCredit() + "], deliveryState[" + delivery.getRemoteState() + "], delivery.isBuffered[" + delivery.isBuffered() + "], delivery.id[" + new String(delivery.getTag()) + "]"); } @@ -86,7 +97,7 @@ public void onLinkFlow(Event event) { this.msgSender.onFlow(sender.getRemoteCredit()); if (TRACE_LOGGER.isDebugEnabled()) { - TRACE_LOGGER.debug("linkName[" + sender.getName() + "], unsettled[" + sender.getUnsettled() + "], credit[" + sender.getCredit() + "]"); + TRACE_LOGGER.debug("onLinkFlow linkName[" + sender.getName() + "], unsettled[" + sender.getUnsettled() + "], credit[" + sender.getCredit() + "]"); } } } diff --git a/azure-eventhubs/src/main/java/com/microsoft/azure/eventhubs/impl/SessionHandler.java b/azure-eventhubs/src/main/java/com/microsoft/azure/eventhubs/impl/SessionHandler.java index a5c65372f790..d766012e6ee8 100644 --- a/azure-eventhubs/src/main/java/com/microsoft/azure/eventhubs/impl/SessionHandler.java +++ b/azure-eventhubs/src/main/java/com/microsoft/azure/eventhubs/impl/SessionHandler.java @@ -5,7 +5,6 @@ package com.microsoft.azure.eventhubs.impl; import com.microsoft.azure.eventhubs.EventHubException; -import com.microsoft.azure.eventhubs.TimeoutException; import org.apache.qpid.proton.amqp.transport.ErrorCondition; import org.apache.qpid.proton.engine.*; import org.apache.qpid.proton.reactor.Reactor; @@ -13,6 +12,7 @@ import org.slf4j.LoggerFactory; import java.io.IOException; +import java.time.Duration; import java.util.Iterator; import java.util.Locale; import java.util.function.BiConsumer; @@ -24,18 +24,28 @@ public class SessionHandler extends BaseHandler { private final String entityName; private final Consumer onRemoteSessionOpen; private final BiConsumer onRemoteSessionOpenError; + private final Duration openTimeout; private boolean sessionCreated = false; private boolean sessionOpenErrorDispatched = false; - public SessionHandler(final String entityName, final Consumer onRemoteSessionOpen, final BiConsumer onRemoteSessionOpenError) { + public SessionHandler(final String entityName, + final Consumer onRemoteSessionOpen, + final BiConsumer onRemoteSessionOpenError, + final Duration openTimeout) { this.entityName = entityName; this.onRemoteSessionOpenError = onRemoteSessionOpenError; this.onRemoteSessionOpen = onRemoteSessionOpen; + this.openTimeout = openTimeout; } @Override public void onSessionLocalOpen(Event e) { + if (TRACE_LOGGER.isInfoEnabled()) { + TRACE_LOGGER.info(String.format(Locale.US, "onSessionLocalOpen entityName[%s], condition[%s]", this.entityName, + e.getSession().getCondition() == null ? "none" : e.getSession().getCondition().toString())); + } + if (this.onRemoteSessionOpenError != null) { ReactorHandler reactorHandler = null; @@ -53,12 +63,11 @@ public void onSessionLocalOpen(Event e) { final Session session = e.getSession(); try { - - reactorDispatcher.invoke(ClientConstants.SESSION_OPEN_TIMEOUT_IN_MS, new SessionTimeoutHandler(session)); + reactorDispatcher.invoke((int) this.openTimeout.toMillis(), new SessionTimeoutHandler(session)); } catch (IOException ignore) { - if (TRACE_LOGGER.isWarnEnabled()) { - TRACE_LOGGER.warn(String.format(Locale.US, "entityName[%s], reactorDispatcherError[%s]", this.entityName, ignore.getMessage())); + TRACE_LOGGER.warn(String.format(Locale.US, "onSessionLocalOpen entityName[%s], reactorDispatcherError[%s]", + this.entityName, ignore.getMessage())); } session.close(); @@ -66,8 +75,8 @@ public void onSessionLocalOpen(Event e) { null, new EventHubException( false, - String.format("underlying IO of reactorDispatcher faulted with error: %s", ignore.getMessage()), - ignore)); + String.format("onSessionLocalOpen entityName[%s], underlying IO of reactorDispatcher faulted with error: %s", + this.entityName, ignore.getMessage()), ignore)); } } } @@ -89,7 +98,6 @@ public void onSessionRemoteOpen(Event e) { this.onRemoteSessionOpen.accept(session); } - @Override public void onSessionLocalClose(Event e) { if (TRACE_LOGGER.isInfoEnabled()) { @@ -132,32 +140,17 @@ public SessionTimeoutHandler(final Session session) { @Override public void onEvent() { + // It is supposed to close a local session to handle timeout exception. + // However, closing the session can result in NPE because of proton-j bug (https://issues.apache.org/jira/browse/PROTON-1939). + // And the bug will cause the reactor thread to stop processing pending tasks scheduled on the reactor and + // as a result task won't be completed at all. - // notify - if connection or transport error'ed out before even session open completed - if (!sessionCreated && !sessionOpenErrorDispatched) { - - final Connection connection = session.getConnection(); + // TODO: handle timeout error once the proton-j bug is fixed. - if (connection != null) { - - if (connection.getRemoteCondition() != null && connection.getRemoteCondition().getCondition() != null) { - - session.close(); - onRemoteSessionOpenError.accept(connection.getRemoteCondition(), null); - return; - } - - final Transport transport = connection.getTransport(); - if (transport != null && transport.getCondition() != null && transport.getCondition().getCondition() != null) { - - session.close(); - onRemoteSessionOpenError.accept(transport.getCondition(), null); - return; - } + if (!sessionCreated && !sessionOpenErrorDispatched) { + if (TRACE_LOGGER.isWarnEnabled()) { + TRACE_LOGGER.warn(String.format(Locale.US, "SessionTimeoutHandler.onEvent - session open timed out.")); } - - session.close(); - onRemoteSessionOpenError.accept(null, new TimeoutException("session creation timedout.")); } } } diff --git a/azure-eventhubs/src/main/java/com/microsoft/azure/eventhubs/impl/Timer.java b/azure-eventhubs/src/main/java/com/microsoft/azure/eventhubs/impl/Timer.java index 65f05d3c5b19..a1cf86553732 100644 --- a/azure-eventhubs/src/main/java/com/microsoft/azure/eventhubs/impl/Timer.java +++ b/azure-eventhubs/src/main/java/com/microsoft/azure/eventhubs/impl/Timer.java @@ -24,7 +24,7 @@ public CompletableFuture schedule( final ScheduledTask scheduledTask = new ScheduledTask(runnable); final CompletableFuture taskHandle = scheduledTask.getScheduledFuture(); try { - this.schedulerProvider.getReactorScheduler().invoke((int) runAfter.toMillis(), scheduledTask); + this.schedulerProvider.getReactorDispatcher().invoke((int) runAfter.toMillis(), scheduledTask); } catch (IOException | RejectedExecutionException e) { taskHandle.completeExceptionally(e); } diff --git a/azure-eventhubs/src/test/java/com/microsoft/azure/eventhubs/concurrency/EventHubClientTest.java b/azure-eventhubs/src/test/java/com/microsoft/azure/eventhubs/concurrency/EventHubClientTest.java index dd3c59c4f02b..c292d6a51ee9 100644 --- a/azure-eventhubs/src/test/java/com/microsoft/azure/eventhubs/concurrency/EventHubClientTest.java +++ b/azure-eventhubs/src/test/java/com/microsoft/azure/eventhubs/concurrency/EventHubClientTest.java @@ -14,7 +14,9 @@ import org.junit.Assert; import org.junit.Test; -import java.util.concurrent.*; +import java.util.concurrent.CompletableFuture; +import java.util.concurrent.Executors; +import java.util.concurrent.ScheduledExecutorService; public class EventHubClientTest extends ApiTestBase { @@ -24,7 +26,7 @@ public void testParallelEventHubClients() throws Exception { final String consumerGroupName = TestContext.getConsumerGroupName(); final String partitionId = "0"; final int noOfClients = 4; - final ExecutorService executorService = Executors.newSingleThreadExecutor(); + final ScheduledExecutorService executorService = Executors.newScheduledThreadPool(1); @SuppressWarnings("unchecked") CompletableFuture[] createFutures = new CompletableFuture[noOfClients]; diff --git a/azure-eventhubs/src/test/java/com/microsoft/azure/eventhubs/eventdata/EventDataBatchTest.java b/azure-eventhubs/src/test/java/com/microsoft/azure/eventhubs/eventdata/EventDataBatchTest.java index fcc7b71b3bab..744ed427359e 100644 --- a/azure-eventhubs/src/test/java/com/microsoft/azure/eventhubs/eventdata/EventDataBatchTest.java +++ b/azure-eventhubs/src/test/java/com/microsoft/azure/eventhubs/eventdata/EventDataBatchTest.java @@ -20,7 +20,7 @@ public class EventDataBatchTest extends ApiTestBase { @Test(expected = PayloadSizeExceededException.class) public void payloadExceededException() throws EventHubException, IOException { final ConnectionStringBuilder connStrBuilder = TestContext.getConnectionString(); - ehClient = EventHubClient.createSync(connStrBuilder.toString(), Executors.newSingleThreadExecutor()); + ehClient = EventHubClient.createSync(connStrBuilder.toString(), Executors.newScheduledThreadPool(1)); final EventDataBatch batch = ehClient.createBatch(); diff --git a/azure-eventhubs/src/test/java/com/microsoft/azure/eventhubs/exceptioncontracts/MsgFactoryOpenCloseTest.java b/azure-eventhubs/src/test/java/com/microsoft/azure/eventhubs/exceptioncontracts/MsgFactoryOpenCloseTest.java index 17571b15f974..4ae37ffe71a2 100644 --- a/azure-eventhubs/src/test/java/com/microsoft/azure/eventhubs/exceptioncontracts/MsgFactoryOpenCloseTest.java +++ b/azure-eventhubs/src/test/java/com/microsoft/azure/eventhubs/exceptioncontracts/MsgFactoryOpenCloseTest.java @@ -22,16 +22,14 @@ public class MsgFactoryOpenCloseTest extends ApiTestBase { static ConnectionStringBuilder connStr; @BeforeClass - public static void initialize() throws Exception { + public static void initialize() { connStr = TestContext.getConnectionString(); } @Test() public void VerifyTaskQueueEmptyOnMsgFactoryGracefulClose() throws Exception { - final LinkedBlockingQueue blockingQueue = new LinkedBlockingQueue<>(); - final ThreadPoolExecutor executor = new ThreadPoolExecutor( - 1, 1, 1, TimeUnit.MINUTES, blockingQueue); + final ScheduledExecutorService executor = Executors.newScheduledThreadPool(1); try { final EventHubClient ehClient = EventHubClient.createSync( TestContext.getConnectionString().toString(), @@ -49,8 +47,7 @@ public void VerifyTaskQueueEmptyOnMsgFactoryGracefulClose() throws Exception { ehClient.closeSync(); - Assert.assertEquals(blockingQueue.size(), 0); - Assert.assertEquals(executor.getTaskCount(), executor.getCompletedTaskCount()); + Assert.assertEquals(((ScheduledThreadPoolExecutor) executor).getQueue().size(), 0); } finally { executor.shutdown(); } @@ -59,9 +56,8 @@ public void VerifyTaskQueueEmptyOnMsgFactoryGracefulClose() throws Exception { @Test() public void VerifyTaskQueueEmptyOnMsgFactoryWithPumpGracefulClose() throws Exception { - final LinkedBlockingQueue blockingQueue = new LinkedBlockingQueue<>(); - final ThreadPoolExecutor executor = new ThreadPoolExecutor( - 1, 1, 1, TimeUnit.MINUTES, blockingQueue); + final ScheduledExecutorService executor = new ScheduledThreadPoolExecutor(1); + try { final EventHubClient ehClient = EventHubClient.createSync( TestContext.getConnectionString().toString(), @@ -100,8 +96,7 @@ public void onError(Throwable error) { ehClient.closeSync(); - Assert.assertEquals(blockingQueue.size(), 0); - Assert.assertEquals(executor.getTaskCount(), executor.getCompletedTaskCount()); + Assert.assertEquals(((ScheduledThreadPoolExecutor) executor).getQueue().size(), 0); } finally { executor.shutdown(); } @@ -113,9 +108,7 @@ public void VerifyThreadReleaseOnMsgFactoryOpenError() throws Exception { final FaultInjectingReactorFactory networkOutageSimulator = new FaultInjectingReactorFactory(); networkOutageSimulator.setFaultType(FaultInjectingReactorFactory.FaultType.NetworkOutage); - final LinkedBlockingQueue blockingQueue = new LinkedBlockingQueue<>(); - final ThreadPoolExecutor executor = new ThreadPoolExecutor( - 1, 1, 1, TimeUnit.MINUTES, blockingQueue); + final ScheduledExecutorService executor = Executors.newScheduledThreadPool(1); try { final CompletableFuture openFuture = MessagingFactory.createFromConnectionString( @@ -131,8 +124,7 @@ public void VerifyThreadReleaseOnMsgFactoryOpenError() throws Exception { Thread.sleep(1000); // for reactor to transition from cleanup to complete-stop - Assert.assertEquals(0, blockingQueue.size()); - Assert.assertEquals(executor.getTaskCount(), executor.getCompletedTaskCount()); + Assert.assertEquals(((ScheduledThreadPoolExecutor) executor).getQueue().size(), 0); } finally { executor.shutdown(); } @@ -140,7 +132,7 @@ public void VerifyThreadReleaseOnMsgFactoryOpenError() throws Exception { @Test(expected = RejectedExecutionException.class) public void SupplyClosedExecutorServiceToEventHubClient() throws Exception { - final ExecutorService testClosed = Executors.newWorkStealingPool(); + final ScheduledExecutorService testClosed = new ScheduledThreadPoolExecutor(1); testClosed.shutdown(); EventHubClient.createSync( @@ -150,7 +142,7 @@ public void SupplyClosedExecutorServiceToEventHubClient() throws Exception { @Test(expected = RejectedExecutionException.class) public void SupplyClosedExecutorServiceToSendOperation() throws Exception { - final ExecutorService testClosed = Executors.newWorkStealingPool(); + final ScheduledExecutorService testClosed = Executors.newScheduledThreadPool(1); final EventHubClient temp = EventHubClient.createSync( TestContext.getConnectionString().toString(), @@ -165,7 +157,7 @@ public void SupplyClosedExecutorServiceToSendOperation() throws Exception { @Test(expected = RejectedExecutionException.class) public void SupplyClosedExecutorServiceToReceiveOperation() throws Exception { - final ExecutorService testClosed = Executors.newWorkStealingPool(); + final ScheduledExecutorService testClosed = new ScheduledThreadPoolExecutor(1); final PartitionReceiver temp = EventHubClient.createSync( TestContext.getConnectionString().toString(), @@ -180,7 +172,7 @@ public void SupplyClosedExecutorServiceToReceiveOperation() throws Exception { @Test(expected = RejectedExecutionException.class) public void SupplyClosedExecutorServiceToCreateLinkOperation() throws Exception { - final ExecutorService testClosed = Executors.newWorkStealingPool(); + final ScheduledExecutorService testClosed = Executors.newScheduledThreadPool(1); final EventHubClient temp = EventHubClient.createSync( TestContext.getConnectionString().toString(), @@ -195,7 +187,7 @@ public void SupplyClosedExecutorServiceToCreateLinkOperation() throws Exception @Test(expected = RejectedExecutionException.class) public void SupplyClosedExecutorServiceToCreateSenderOperation() throws Exception { - final ExecutorService testClosed = Executors.newWorkStealingPool(); + final ScheduledExecutorService testClosed = new ScheduledThreadPoolExecutor(1); final EventHubClient temp = EventHubClient.createSync( TestContext.getConnectionString().toString(), @@ -209,7 +201,7 @@ public void SupplyClosedExecutorServiceToCreateSenderOperation() throws Exceptio @Test(expected = RejectedExecutionException.class) public void SupplyClosedExecutorServiceToCreateReceiverOperation() throws Exception { - final ExecutorService testClosed = Executors.newWorkStealingPool(); + final ScheduledExecutorService testClosed = Executors.newScheduledThreadPool(1); final EventHubClient temp = EventHubClient.createSync( TestContext.getConnectionString().toString(), @@ -223,7 +215,7 @@ public void SupplyClosedExecutorServiceToCreateReceiverOperation() throws Except @Test(expected = RejectedExecutionException.class) public void SupplyClosedExecutorServiceThenMgmtOperation() throws Throwable { - final ExecutorService testClosed = Executors.newWorkStealingPool(); + final ScheduledThreadPoolExecutor testClosed = new ScheduledThreadPoolExecutor(1); final EventHubClient temp = EventHubClient.createSync( TestContext.getConnectionString().toString(), @@ -241,7 +233,7 @@ public void SupplyClosedExecutorServiceThenMgmtOperation() throws Throwable { @Test(expected = RejectedExecutionException.class) public void SupplyClosedExecutorServiceThenFactoryCloseOperation() throws Exception { - final ExecutorService testClosed = Executors.newWorkStealingPool(); + final ScheduledExecutorService testClosed = Executors.newScheduledThreadPool(1); final EventHubClient temp = EventHubClient.createSync( TestContext.getConnectionString().toString(), @@ -255,7 +247,7 @@ public void SupplyClosedExecutorServiceThenFactoryCloseOperation() throws Except @Test(expected = RejectedExecutionException.class) public void SupplyClosedExecutorServiceThenSenderCloseOperation() throws Exception { - final ExecutorService testClosed = Executors.newWorkStealingPool(); + final ScheduledThreadPoolExecutor testClosed = new ScheduledThreadPoolExecutor(1); final PartitionSender temp = EventHubClient.createSync( TestContext.getConnectionString().toString(), @@ -269,7 +261,7 @@ public void SupplyClosedExecutorServiceThenSenderCloseOperation() throws Excepti @Test(expected = RejectedExecutionException.class) public void SupplyClosedExecutorServiceThenReceiverCloseOperation() throws Exception { - final ExecutorService testClosed = Executors.newWorkStealingPool(); + final ScheduledExecutorService testClosed = Executors.newScheduledThreadPool(1); final PartitionReceiver temp = EventHubClient.createSync( TestContext.getConnectionString().toString(), diff --git a/azure-eventhubs/src/test/java/com/microsoft/azure/eventhubs/exceptioncontracts/ReactorFaultTest.java b/azure-eventhubs/src/test/java/com/microsoft/azure/eventhubs/exceptioncontracts/ReactorFaultTest.java index 8f7402666acf..b2466f99e3e6 100644 --- a/azure-eventhubs/src/test/java/com/microsoft/azure/eventhubs/exceptioncontracts/ReactorFaultTest.java +++ b/azure-eventhubs/src/test/java/com/microsoft/azure/eventhubs/exceptioncontracts/ReactorFaultTest.java @@ -12,6 +12,7 @@ import org.junit.Test; import java.lang.reflect.Field; +import java.util.concurrent.Executors; import java.util.concurrent.TimeUnit; public class ReactorFaultTest extends ApiTestBase { @@ -26,27 +27,38 @@ public static void initialize() throws Exception { @Test() public void VerifyReactorRestartsOnProtonBugs() throws Exception { final EventHubClient eventHubClient = EventHubClient.createSync(connStr.toString(), TestContext.EXECUTOR_SERVICE); - try { final PartitionReceiver partitionReceiver = eventHubClient.createEpochReceiverSync( "$default", "0", EventPosition.fromStartOfStream(), System.currentTimeMillis()); + partitionReceiver.receiveSync(100); - try { - final Field factoryField = EventHubClientImpl.class.getDeclaredField("underlyingFactory"); - factoryField.setAccessible(true); - final MessagingFactory underlyingFactory = (MessagingFactory) factoryField.get(eventHubClient); - - final Field reactorField = MessagingFactory.class.getDeclaredField("reactor"); - reactorField.setAccessible(true); - final Reactor reactor = (Reactor) reactorField.get(underlyingFactory); - - org.apache.qpid.proton.engine.Handler handler = reactor.getHandler(); - handler.add(new BaseHandler() { - @Override - public void handle(org.apache.qpid.proton.engine.Event e) { - throw new NullPointerException(); + Executors.newScheduledThreadPool(1).schedule(new Runnable() { + @Override + public void run() { + try { + final Field factoryField = EventHubClientImpl.class.getDeclaredField("underlyingFactory"); + factoryField.setAccessible(true); + final MessagingFactory underlyingFactory = (MessagingFactory) factoryField.get(eventHubClient); + + final Field reactorField = MessagingFactory.class.getDeclaredField("reactor"); + reactorField.setAccessible(true); + final Reactor reactor = (Reactor) reactorField.get(underlyingFactory); + + org.apache.qpid.proton.engine.Handler handler = reactor.getHandler(); + handler.add(new BaseHandler() { + @Override + public void handle(org.apache.qpid.proton.engine.Event e) { + throw new NullPointerException(); + } + }); + } catch (Exception e) { + Assert.fail(e.getMessage()); } - }); + } + }, 2, TimeUnit.SECONDS); + + try { + Thread.sleep(4000); final Iterable events = partitionReceiver.receiveSync(100); Assert.assertTrue(events != null && events.iterator().hasNext()); diff --git a/azure-eventhubs/src/test/java/com/microsoft/azure/eventhubs/lib/TestContext.java b/azure-eventhubs/src/test/java/com/microsoft/azure/eventhubs/lib/TestContext.java index 6a7fa12d7cc1..fa5215a34212 100644 --- a/azure-eventhubs/src/test/java/com/microsoft/azure/eventhubs/lib/TestContext.java +++ b/azure-eventhubs/src/test/java/com/microsoft/azure/eventhubs/lib/TestContext.java @@ -6,11 +6,13 @@ import com.microsoft.azure.eventhubs.ConnectionStringBuilder; -import java.util.concurrent.ExecutorService; import java.util.concurrent.Executors; +import java.util.concurrent.ScheduledExecutorService; +import java.util.concurrent.ScheduledThreadPoolExecutor; public final class TestContext { - public final static ExecutorService EXECUTOR_SERVICE = Executors.newSingleThreadExecutor(); + + public final static ScheduledExecutorService EXECUTOR_SERVICE = Executors.newScheduledThreadPool(1); final static String EVENT_HUB_CONNECTION_STRING_ENV_NAME = "EVENT_HUB_CONNECTION_STRING"; diff --git a/azure-eventhubs/src/test/java/com/microsoft/azure/eventhubs/sendrecv/ReceivePumpTest.java b/azure-eventhubs/src/test/java/com/microsoft/azure/eventhubs/sendrecv/ReceivePumpTest.java index a7798a830e70..878fdbdd39c8 100644 --- a/azure-eventhubs/src/test/java/com/microsoft/azure/eventhubs/sendrecv/ReceivePumpTest.java +++ b/azure-eventhubs/src/test/java/com/microsoft/azure/eventhubs/sendrecv/ReceivePumpTest.java @@ -32,6 +32,7 @@ public void initializeValidation() { public void testPumpOnReceiveEventFlow() throws Exception { final CompletableFuture pumpRun = new CompletableFuture<>(); final ReceivePump receivePump = new ReceivePump( + "eventhub1", "consumerGroup1", new ReceivePump.IPartitionReceiver() { @Override public CompletableFuture> receive(int maxBatchSize) { @@ -82,6 +83,7 @@ public void onError(Throwable error) { public void testPumpReceiveTransientErrorsPropagated() throws Exception { final CompletableFuture pumpRun = new CompletableFuture<>(); final ReceivePump receivePump = new ReceivePump( + "eventhub1", "consumerGroup1", new ReceivePump.IPartitionReceiver() { @Override public CompletableFuture> receive(int maxBatchSize) { @@ -128,6 +130,7 @@ public void onError(Throwable error) { public void testPumpReceiveExceptionsPropagated() throws Exception { final CompletableFuture pumpRun = new CompletableFuture<>(); final ReceivePump receivePump = new ReceivePump( + "eventhub1", "consumerGroup1", new ReceivePump.IPartitionReceiver() { @Override public CompletableFuture> receive(int maxBatchSize) { @@ -175,6 +178,7 @@ public void testPumpOnReceiveExceptionsPropagated() throws EventHubException, In final String runtimeExceptionMsg = "random exception"; final CompletableFuture pumpRun = new CompletableFuture<>(); final ReceivePump receivePump = new ReceivePump( + "eventhub1", "consumerGroup1", new ReceivePump.IPartitionReceiver() { @Override public CompletableFuture> receive(int maxBatchSize) { diff --git a/azure-eventhubs/src/test/java/com/microsoft/azure/eventhubs/sendrecv/RequestResponseTest.java b/azure-eventhubs/src/test/java/com/microsoft/azure/eventhubs/sendrecv/RequestResponseTest.java index bd29b39907b6..c95643f9c2c2 100644 --- a/azure-eventhubs/src/test/java/com/microsoft/azure/eventhubs/sendrecv/RequestResponseTest.java +++ b/azure-eventhubs/src/test/java/com/microsoft/azure/eventhubs/sendrecv/RequestResponseTest.java @@ -50,7 +50,7 @@ public static void cleanup() throws EventHubException { @Test() public void testRequestResponse() throws Exception { - final ReactorDispatcher dispatcher = factory.getReactorScheduler(); + final ReactorDispatcher dispatcher = factory.getReactorDispatcher(); final RequestResponseChannel requestResponseChannel = new RequestResponseChannel( "reqresp", ClientConstants.MANAGEMENT_ADDRESS, From 9d04a9816b24eb935b060f24561d6e8007bbc82e Mon Sep 17 00:00:00 2001 From: Fokko Driesprong Date: Fri, 21 Dec 2018 09:40:25 +0100 Subject: [PATCH 06/42] Implement comparable on EventData (#395) --- .../microsoft/azure/eventhubs/EventData.java | 2 +- .../azure/eventhubs/impl/EventDataImpl.java | 8 +++ .../eventdata/InteropEventBodyTest.java | 1 - .../eventhubs/impl/EventDataOrderTest.java | 52 +++++++++++++++++++ 4 files changed, 61 insertions(+), 2 deletions(-) create mode 100644 azure-eventhubs/src/test/java/com/microsoft/azure/eventhubs/impl/EventDataOrderTest.java diff --git a/azure-eventhubs/src/main/java/com/microsoft/azure/eventhubs/EventData.java b/azure-eventhubs/src/main/java/com/microsoft/azure/eventhubs/EventData.java index f2d7ca49d680..d9884bf248c5 100755 --- a/azure-eventhubs/src/main/java/com/microsoft/azure/eventhubs/EventData.java +++ b/azure-eventhubs/src/main/java/com/microsoft/azure/eventhubs/EventData.java @@ -30,7 +30,7 @@ * Section (iii) is used for advanced scenarios, where the sending application uses third-party AMQP library to send the message to EventHubs and the receiving application * uses this client library to receive {@link EventData}. */ -public interface EventData extends Serializable { +public interface EventData extends Serializable, Comparable { /** * Construct EventData to Send to EventHubs. diff --git a/azure-eventhubs/src/main/java/com/microsoft/azure/eventhubs/impl/EventDataImpl.java b/azure-eventhubs/src/main/java/com/microsoft/azure/eventhubs/impl/EventDataImpl.java index 940ca8aa9f3f..69986268623c 100755 --- a/azure-eventhubs/src/main/java/com/microsoft/azure/eventhubs/impl/EventDataImpl.java +++ b/azure-eventhubs/src/main/java/com/microsoft/azure/eventhubs/impl/EventDataImpl.java @@ -258,4 +258,12 @@ private void readObject(ObjectInputStream in) throws IOException, ClassNotFoundE this.bodyData = new Binary(data, 0, length); } } + + @Override + public int compareTo(EventData other) { + return Long.compare( + this.getSystemProperties().getSequenceNumber(), + other.getSystemProperties().getSequenceNumber() + ); + } } diff --git a/azure-eventhubs/src/test/java/com/microsoft/azure/eventhubs/eventdata/InteropEventBodyTest.java b/azure-eventhubs/src/test/java/com/microsoft/azure/eventhubs/eventdata/InteropEventBodyTest.java index f1f2e2c9beaa..42c012cbf6af 100644 --- a/azure-eventhubs/src/test/java/com/microsoft/azure/eventhubs/eventdata/InteropEventBodyTest.java +++ b/azure-eventhubs/src/test/java/com/microsoft/azure/eventhubs/eventdata/InteropEventBodyTest.java @@ -37,7 +37,6 @@ public class InteropEventBodyTest extends ApiTestBase { static PartitionSender partitionSender; static EventData receivedEvent; static EventData reSentAndReceivedEvent; - static Message reSendAndReceivedMessage; @BeforeClass public static void initialize() throws EventHubException, IOException, InterruptedException, ExecutionException { diff --git a/azure-eventhubs/src/test/java/com/microsoft/azure/eventhubs/impl/EventDataOrderTest.java b/azure-eventhubs/src/test/java/com/microsoft/azure/eventhubs/impl/EventDataOrderTest.java new file mode 100644 index 000000000000..f36066a1fee1 --- /dev/null +++ b/azure-eventhubs/src/test/java/com/microsoft/azure/eventhubs/impl/EventDataOrderTest.java @@ -0,0 +1,52 @@ +/* + * Copyright (c) Microsoft. All rights reserved. + * Licensed under the MIT license. See LICENSE file in the project root for full license information. + */ +package com.microsoft.azure.eventhubs.impl; + +import java.util.ArrayList; +import java.util.Collections; +import java.util.HashMap; + +import com.microsoft.azure.eventhubs.EventData; +import org.apache.qpid.proton.amqp.Symbol; +import org.apache.qpid.proton.amqp.messaging.MessageAnnotations; +import org.apache.qpid.proton.message.Message; +import org.junit.Assert; +import org.junit.Test; + +public class EventDataOrderTest { + + private EventData constructMessage(long seqNumber) { + HashMap properties = new HashMap<>(); + properties.put(AmqpConstants.SEQUENCE_NUMBER, seqNumber); + + Message message = Message.Factory.create(); + + message.setMessageAnnotations(new MessageAnnotations(properties)); + + return new EventDataImpl(message); + } + + @Test + public void eventDataEmptyByteArray() { + ArrayList messages = new ArrayList<>(); + + EventData first = constructMessage(19); + EventData second = constructMessage(22); + EventData third = constructMessage(25); + EventData last = constructMessage(88); + + messages.add(second); + messages.add(first); + messages.add(last); + messages.add(third); + + Collections.sort(messages); + + Assert.assertEquals(messages.get(0), first); + Assert.assertEquals(messages.get(1), second); + Assert.assertEquals(messages.get(2), third); + Assert.assertEquals(messages.get(3), last); + } +} From c37c848cdacfb83af7ed7197f0cc60f56fc43a98 Mon Sep 17 00:00:00 2001 From: SJ Date: Wed, 2 Jan 2019 10:47:24 -0800 Subject: [PATCH 07/42] Update receive/send link creation logic and improve tracing (#414) --- .../azure/eventhubs/impl/BaseLinkHandler.java | 51 +++++++++---- .../eventhubs/impl/FaultTolerantObject.java | 62 ++++++++-------- .../azure/eventhubs/impl/MessageReceiver.java | 72 ++++++++++++++----- .../azure/eventhubs/impl/MessageSender.java | 69 ++++++++++++------ .../eventhubs/impl/MessagingFactory.java | 5 ++ .../azure/eventhubs/impl/SessionHandler.java | 36 +++++++--- .../exceptioncontracts/ReactorFaultTest.java | 60 ++++++++++++++++ 7 files changed, 265 insertions(+), 90 deletions(-) diff --git a/azure-eventhubs/src/main/java/com/microsoft/azure/eventhubs/impl/BaseLinkHandler.java b/azure-eventhubs/src/main/java/com/microsoft/azure/eventhubs/impl/BaseLinkHandler.java index a086ee3dcc15..4386bd3ad831 100644 --- a/azure-eventhubs/src/main/java/com/microsoft/azure/eventhubs/impl/BaseLinkHandler.java +++ b/azure-eventhubs/src/main/java/com/microsoft/azure/eventhubs/impl/BaseLinkHandler.java @@ -5,10 +5,7 @@ package com.microsoft.azure.eventhubs.impl; import org.apache.qpid.proton.amqp.transport.ErrorCondition; -import org.apache.qpid.proton.engine.BaseHandler; -import org.apache.qpid.proton.engine.EndpointState; -import org.apache.qpid.proton.engine.Event; -import org.apache.qpid.proton.engine.Link; +import org.apache.qpid.proton.engine.*; import org.slf4j.Logger; import org.slf4j.LoggerFactory; @@ -24,18 +21,28 @@ public BaseLinkHandler(final AmqpLink amqpLink) { @Override public void onLinkLocalClose(Event event) { final Link link = event.getLink(); + final ErrorCondition condition = link.getCondition(); + if (TRACE_LOGGER.isInfoEnabled()) { - TRACE_LOGGER.info(String.format("onLinkLocalClose linkName[%s]", link.getName())); + TRACE_LOGGER.info(String.format("onLinkLocalClose linkName[%s], errorCondition[%s], errorDescription[%s]", + link.getName(), + condition != null ? condition.getCondition() : "n/a", + condition != null ? condition.getDescription() : "n/a")); } - closeSession(link); + closeSession(link, link.getCondition()); } @Override public void onLinkRemoteClose(Event event) { final Link link = event.getLink(); + final ErrorCondition condition = link.getCondition(); + if (TRACE_LOGGER.isInfoEnabled()) { - TRACE_LOGGER.info(String.format("onLinkRemoteClose linkName[%s]", link.getName())); + TRACE_LOGGER.info(String.format("onLinkRemoteClose linkName[%s], errorCondition[%s], errorDescription[%s]", + link.getName(), + condition != null ? condition.getCondition() : "n/a", + condition != null ? condition.getDescription() : "n/a")); } handleRemoteLinkClosed(event); @@ -44,8 +51,13 @@ public void onLinkRemoteClose(Event event) { @Override public void onLinkRemoteDetach(Event event) { final Link link = event.getLink(); + final ErrorCondition condition = link.getCondition(); + if (TRACE_LOGGER.isInfoEnabled()) { - TRACE_LOGGER.info(String.format("onLinkRemoteDetach linkName[%s]", link.getName())); + TRACE_LOGGER.info(String.format("onLinkRemoteDetach linkName[%s], errorCondition[%s], errorDescription[%s]", + link.getName(), + condition != null ? condition.getCondition() : "n/a", + condition != null ? condition.getDescription() : "n/a")); } handleRemoteLinkClosed(event); @@ -66,21 +78,34 @@ public void processOnClose(Link link, Exception exception) { this.underlyingEntity.onError(exception); } - private void closeSession(Link link) { - if (link.getSession() != null && link.getSession().getLocalState() != EndpointState.CLOSED) - link.getSession().close(); + private void closeSession(Link link, ErrorCondition condition) { + final Session session = link.getSession(); + + if (session != null && session.getLocalState() != EndpointState.CLOSED) { + if (TRACE_LOGGER.isInfoEnabled()) { + TRACE_LOGGER.info(String.format("closeSession for linkName[%s], errorCondition[%s], errorDescription[%s]", + link.getName(), + condition != null ? condition.getCondition() : "n/a", + condition != null ? condition.getDescription() : "n/a")); + } + + session.setCondition(condition); + session.close(); + } } private void handleRemoteLinkClosed(final Event event) { final Link link = event.getLink(); + final ErrorCondition condition = link.getRemoteCondition(); + if (link.getLocalState() != EndpointState.CLOSED) { + link.setCondition(condition); link.close(); } - final ErrorCondition condition = link.getRemoteCondition(); this.processOnClose(link, condition); - closeSession(link); + this.closeSession(link, condition); } } diff --git a/azure-eventhubs/src/main/java/com/microsoft/azure/eventhubs/impl/FaultTolerantObject.java b/azure-eventhubs/src/main/java/com/microsoft/azure/eventhubs/impl/FaultTolerantObject.java index 4da5db7510ca..9aefd3889b46 100644 --- a/azure-eventhubs/src/main/java/com/microsoft/azure/eventhubs/impl/FaultTolerantObject.java +++ b/azure-eventhubs/src/main/java/com/microsoft/azure/eventhubs/impl/FaultTolerantObject.java @@ -10,14 +10,14 @@ public class FaultTolerantObject { - final Operation openTask; - final Operation closeTask; - final Queue> openCallbacks; - final Queue> closeCallbacks; + private final Operation openTask; + private final Operation closeTask; + private final Queue> openCallbacks; + private final Queue> closeCallbacks; - T innerObject; - boolean creatingNewInnerObject; - boolean closingInnerObject; + private T innerObject; + private boolean creatingNewInnerObject; + private boolean closingInnerObject; public FaultTolerantObject( final Operation openAsync, @@ -30,7 +30,7 @@ public FaultTolerantObject( } // should be invoked from reactor thread - public T unsafeGetIfOpened() { + T unsafeGetIfOpened() { if (innerObject != null && innerObject.getState() == IOObject.IOObjectState.OPENED) return innerObject; @@ -47,29 +47,33 @@ public void runOnOpenedObject( @Override public void onEvent() { if (!creatingNewInnerObject - && (innerObject == null || innerObject.getState() == IOObject.IOObjectState.CLOSED || innerObject.getState() == IOObject.IOObjectState.CLOSING)) { + && (innerObject == null || innerObject.getState() == IOObject.IOObjectState.CLOSED || + innerObject.getState() == IOObject.IOObjectState.CLOSING)) { creatingNewInnerObject = true; - openCallbacks.offer(openCallback); - openTask.run(new OperationResult() { - @Override - public void onComplete(T result) { - creatingNewInnerObject = false; - innerObject = result; - for (OperationResult callback : openCallbacks) - callback.onComplete(result); - openCallbacks.clear(); - } - - @Override - public void onError(Exception error) { - creatingNewInnerObject = false; - for (OperationResult callback : openCallbacks) - callback.onError(error); - - openCallbacks.clear(); - } - }); + try { + openCallbacks.offer(openCallback); + openTask.run(new OperationResult() { + @Override + public void onComplete(T result) { + innerObject = result; + for (OperationResult callback : openCallbacks) + callback.onComplete(result); + + openCallbacks.clear(); + } + + @Override + public void onError(Exception error) { + for (OperationResult callback : openCallbacks) + callback.onError(error); + + openCallbacks.clear(); + } + }); + } finally { + creatingNewInnerObject = false; + } } else if (innerObject != null && innerObject.getState() == IOObject.IOObjectState.OPENED) { openCallback.onComplete(innerObject); } else { diff --git a/azure-eventhubs/src/main/java/com/microsoft/azure/eventhubs/impl/MessageReceiver.java b/azure-eventhubs/src/main/java/com/microsoft/azure/eventhubs/impl/MessageReceiver.java index 73c3791f94e9..7b43796e6256 100644 --- a/azure-eventhubs/src/main/java/com/microsoft/azure/eventhubs/impl/MessageReceiver.java +++ b/azure-eventhubs/src/main/java/com/microsoft/azure/eventhubs/impl/MessageReceiver.java @@ -70,6 +70,7 @@ public final class MessageReceiver extends ClientEntity implements AmqpReceiver, private volatile CompletableFuture closeTimer; private int prefetchCount; private Exception lastKnownLinkError; + private String linkCreationTime; private MessageReceiver(final MessagingFactory factory, final String name, @@ -111,8 +112,8 @@ public void run() { if (MessageReceiver.this.shouldScheduleOperationTimeoutTimer()) { TimeoutTracker timeoutTracker = topWorkItem.getTimeoutTracker(); - if (TRACE_LOGGER.isInfoEnabled()) { - TRACE_LOGGER.info( + if (TRACE_LOGGER.isDebugEnabled()) { + TRACE_LOGGER.debug( String.format(Locale.US, "clientId[%s], path[%s], linkName[%s] - Reschedule operation timer, current: [%s], remaining: [%s] secs", getClientId(), @@ -203,7 +204,6 @@ public String getReceivePath() { } private CompletableFuture createLink() { - this.scheduleLinkOpenTimeout(this.linkOpen.getTimeoutTracker()); try { this.underlyingFactory.scheduleOnReactorThread(new DispatchHandler() { @Override @@ -257,8 +257,8 @@ public CompletableFuture> receive(final int maxMessageCount) } if (this.shouldScheduleOperationTimeoutTimer()) { - if (TRACE_LOGGER.isInfoEnabled()) { - TRACE_LOGGER.info( + if (TRACE_LOGGER.isDebugEnabled()) { + TRACE_LOGGER.debug( String.format(Locale.US, "clientId[%s], path[%s], linkName[%s] - schedule operation timer, current: [%s], remaining: [%s] secs", this.getClientId(), @@ -289,10 +289,10 @@ public void onOpenComplete(Exception exception) { if (exception == null) { if (this.linkOpen != null && !this.linkOpen.getWork().isDone()) { this.linkOpen.getWork().complete(this); - if (this.openTimer != null) - this.openTimer.cancel(false); } + this.cancelOpenTimer(); + if (this.getIsClosingOrClosed()) { return; } @@ -307,7 +307,7 @@ public void onOpenComplete(Exception exception) { this.sendFlow(this.prefetchCount - this.prefetchedMessages.size()); if (TRACE_LOGGER.isInfoEnabled()) { - TRACE_LOGGER.info(String.format("clientId[%s], receiverPath[%s], linkName[%s], updated-link-credit[%s], sentCredits[%s]", + TRACE_LOGGER.info(String.format("onOpenComplete - clientId[%s], receiverPath[%s], linkName[%s], updated-link-credit[%s], sentCredits[%s]", this.getClientId(), this.receivePath, this.receiveLink.getName(), this.receiveLink.getCredit(), this.prefetchCount)); } } else { @@ -346,6 +346,8 @@ public void onEvent() { } else if (exception instanceof EventHubException && !((EventHubException) exception).getIsTransient()) { this.cancelOpen(exception); } + } else { + this.cancelOpenTimer(); } } } @@ -353,8 +355,13 @@ public void onEvent() { private void cancelOpen(final Exception completionException) { this.setClosed(); ExceptionUtil.completeExceptionally(this.linkOpen.getWork(), completionException, this); - if (this.openTimer != null) + this.cancelOpenTimer(); + } + + private void cancelOpenTimer() { + if (this.openTimer != null && !this.openTimer.isCancelled()) { this.openTimer.cancel(false); + } } @Override @@ -378,7 +385,6 @@ public void onReceiveComplete(Delivery delivery) { @Override public void onError(final Exception exception) { this.prefetchedMessages.clear(); - this.underlyingFactory.deregisterForConnectionError(this.receiveLink); if (this.getIsClosingOrClosed()) { if (this.closeTimer != null) @@ -396,6 +402,15 @@ public void onError(final Exception exception) { "Entity(%s): client encountered transient error for unknown reasons, please retry the operation.", this.receivePath)) : exception; + if (TRACE_LOGGER.isWarnEnabled()) { + TRACE_LOGGER.warn( + String.format(Locale.US, "clientId[%s], receiverPath[%s], linkName[%s], onError: %s", + this.getClientId(), + this.receivePath, + this.receiveLink.getName(), + completionException)); + } + this.onOpenComplete(completionException); final WorkItem> workItem = this.pendingReceives.peek(); @@ -456,10 +471,24 @@ private void scheduleOperationTimer(final TimeoutTracker tracker) { } private void createReceiveLink() { - if (creatingLink) - return; + synchronized (this.errorConditionLock) { + if (this.creatingLink) { + return; + } + + this.creatingLink = true; + } - this.creatingLink = true; + if (TRACE_LOGGER.isInfoEnabled()) { + TRACE_LOGGER.info( + String.format(Locale.US, + "clientId[%s], path[%s], operationTimeout[%s], creating a receive link", + this.getClientId(), this.receivePath, this.operationTimeout)); + } + + this.linkCreationTime = Instant.now().toString(); + + this.scheduleLinkOpenTimeout(TimeoutTracker.create(this.operationTimeout)); final Consumer onSessionOpen = new Consumer() { @Override @@ -499,6 +528,11 @@ public void accept(Session session) { final ReceiveLinkHandler handler = new ReceiveLinkHandler(MessageReceiver.this); BaseHandler.setHandler(receiver, handler); + + if (MessageReceiver.this.receiveLink != null) { + MessageReceiver.this.underlyingFactory.deregisterForConnectionError(MessageReceiver.this.receiveLink); + } + MessageReceiver.this.underlyingFactory.registerForConnectionError(receiver); receiver.open(); @@ -512,10 +546,11 @@ public void accept(Session session) { final BiConsumer onSessionOpenFailed = new BiConsumer() { @Override public void accept(ErrorCondition t, Exception u) { - if (t != null) + if (t != null) { onError((t.getCondition() != null) ? ExceptionUtil.toException(t) : null); - else if (u != null) + } else if (u != null) { onError(u); + } } }; @@ -588,6 +623,8 @@ private void scheduleLinkOpenTimeout(final TimeoutTracker timeout) { this.openTimer = timer.schedule( new Runnable() { public void run() { + creatingLink = false; + if (!linkOpen.getWork().isDone()) { final Receiver link; final Exception lastReportedLinkError; @@ -679,6 +716,10 @@ private void operationTimeoutTimerFired() { @Override public void onClose(ErrorCondition condition) { + if (this.receiveLink != null) { + this.underlyingFactory.deregisterForConnectionError(MessageReceiver.this.receiveLink); + } + final Exception completionException = (condition != null && condition.getCondition() != null) ? ExceptionUtil.toException(condition) : null; this.onError(completionException); } @@ -769,7 +810,6 @@ private final class CreateAndReceive extends DispatchHandler { @Override public void onEvent() { - receiveWork.onEvent(); if (!MessageReceiver.this.getIsClosingOrClosed() diff --git a/azure-eventhubs/src/main/java/com/microsoft/azure/eventhubs/impl/MessageSender.java b/azure-eventhubs/src/main/java/com/microsoft/azure/eventhubs/impl/MessageSender.java index 81972c664b5b..6f67323ce997 100644 --- a/azure-eventhubs/src/main/java/com/microsoft/azure/eventhubs/impl/MessageSender.java +++ b/azure-eventhubs/src/main/java/com/microsoft/azure/eventhubs/impl/MessageSender.java @@ -64,6 +64,7 @@ public final class MessageSender extends ClientEntity implements AmqpSender, Err private volatile CompletableFuture openTimer; private Exception lastKnownLinkError; private Instant lastKnownErrorReportedAt; + private String linkCreationTime; private MessageSender(final MessagingFactory factory, final String sendLinkName, final String senderPath) { super(sendLinkName, factory, factory.executor); @@ -72,28 +73,23 @@ private MessageSender(final MessagingFactory factory, final String sendLinkName, this.underlyingFactory = factory; this.operationTimeout = factory.getOperationTimeout(); this.timer = new Timer(factory); - this.lastKnownLinkError = null; this.lastKnownErrorReportedAt = Instant.EPOCH; - this.retryPolicy = factory.getRetryPolicy(); this.maxMessageSize = ClientConstants.MAX_MESSAGE_LENGTH_BYTES; - this.errorConditionLock = new Object(); - this.pendingSendLock = new Object(); this.pendingSendsData = new ConcurrentHashMap<>(); this.pendingSends = new PriorityQueue<>(1000, new DeliveryTagComparator()); - this.linkClose = new CompletableFuture<>(); - + this.linkFirstOpen = new CompletableFuture<>(); + this.openLinkTracker = TimeoutTracker.create(factory.getOperationTimeout()); this.sendWork = new DispatchHandler() { @Override public void onEvent() { MessageSender.this.processSendWork(); } }; - this.tokenAudience = String.format(ClientConstants.TOKEN_AUDIENCE_FORMAT, underlyingFactory.getHostName(), sendPath); this.activeClientTokenManager = new ActiveClientTokenManager( this, @@ -142,8 +138,6 @@ public static CompletableFuture create( final String sendLinkName, final String senderPath) { final MessageSender msgSender = new MessageSender(factory, sendLinkName, senderPath); - msgSender.openLinkTracker = TimeoutTracker.create(factory.getOperationTimeout()); - msgSender.initializeLinkOpen(msgSender.openLinkTracker); try { msgSender.underlyingFactory.scheduleOnReactorThread(new DispatchHandler() { @@ -322,13 +316,10 @@ public void onOpenComplete(Exception completionException) { if (completionException == null) { if (this.getIsClosingOrClosed()) { - this.sendLink.close(); return; } - this.openLinkTracker = null; - synchronized (this.errorConditionLock) { this.lastKnownLinkError = null; } @@ -340,10 +331,15 @@ public void onOpenComplete(Exception completionException) { this.maxMessageSize = remoteMaxMessageSize.intValue(); } + this.cancelOpenTimer(); + + if (TRACE_LOGGER.isInfoEnabled()) { + TRACE_LOGGER.info(String.format("onOpenComplete - clientId[%s], sendPath[%s], linkName[%s]", + this.getClientId(), this.sendPath, this.sendLink.getName())); + } + if (!this.linkFirstOpen.isDone()) { this.linkFirstOpen.complete(this); - if (this.openTimer != null) - this.openTimer.cancel(false); } else { synchronized (this.pendingSendLock) { if (!this.pendingSendsData.isEmpty()) { @@ -397,6 +393,8 @@ public void onEvent() { && !((EventHubException) completionException).getIsTransient()) { this.cancelOpen(completionException); } + } else { + this.cancelOpenTimer(); } } } @@ -404,20 +402,27 @@ public void onEvent() { private void cancelOpen(final Exception completionException) { this.setClosed(); ExceptionUtil.completeExceptionally(this.linkFirstOpen, completionException, this); - if (this.openTimer != null) + this.cancelOpenTimer(); + } + + private void cancelOpenTimer() { + if (this.openTimer != null && !this.openTimer.isCancelled()) { this.openTimer.cancel(false); + } } @Override public void onClose(final ErrorCondition condition) { + if (this.sendLink != null) { + this.underlyingFactory.deregisterForConnectionError(this.sendLink); + } + final Exception completionException = (condition != null && condition.getCondition() != null) ? ExceptionUtil.toException(condition) : null; this.onError(completionException); } @Override public void onError(final Exception completionException) { - this.underlyingFactory.deregisterForConnectionError(this.sendLink); - if (this.getIsClosingOrClosed()) { if (this.closeTimer != null && !this.closeTimer.isDone()) this.closeTimer.cancel(false); @@ -581,10 +586,24 @@ private void cleanupFailedSend(final ReplayableWorkItem failedSend, final } private void createSendLink() { - if (this.creatingLink) - return; + synchronized (this.errorConditionLock) { + if (this.creatingLink) { + return; + } - this.creatingLink = true; + this.creatingLink = true; + } + + if (TRACE_LOGGER.isInfoEnabled()) { + TRACE_LOGGER.info( + String.format(Locale.US, + "clientId[%s], path[%s], operationTimeout[%s], creating a send link", + this.getClientId(), this.sendPath, this.operationTimeout)); + } + + this.linkCreationTime = Instant.now().toString(); + + this.scheduleLinkOpenTimeout(TimeoutTracker.create(this.operationTimeout)); final Consumer onSessionOpen = new Consumer() { @Override @@ -608,6 +627,10 @@ public void accept(Session session) { final SendLinkHandler handler = new SendLinkHandler(MessageSender.this); BaseHandler.setHandler(sender, handler); + if (MessageSender.this.sendLink != null) { + MessageSender.this.underlyingFactory.deregisterForConnectionError(MessageSender.this.sendLink); + } + MessageSender.this.underlyingFactory.registerForConnectionError(sender); sender.open(); @@ -664,13 +687,13 @@ public void onError(Exception error) { } } - private void initializeLinkOpen(TimeoutTracker timeout) { - this.linkFirstOpen = new CompletableFuture<>(); - + private void scheduleLinkOpenTimeout(TimeoutTracker timeout) { // timer to signal a timeout if exceeds the operationTimeout on MessagingFactory this.openTimer = this.timer.schedule( new Runnable() { public void run() { + creatingLink = false; + if (!MessageSender.this.linkFirstOpen.isDone()) { final Exception lastReportedError; final Sender link; diff --git a/azure-eventhubs/src/main/java/com/microsoft/azure/eventhubs/impl/MessagingFactory.java b/azure-eventhubs/src/main/java/com/microsoft/azure/eventhubs/impl/MessagingFactory.java index c69bdbec8ed7..24031a7c74ca 100644 --- a/azure-eventhubs/src/main/java/com/microsoft/azure/eventhubs/impl/MessagingFactory.java +++ b/azure-eventhubs/src/main/java/com/microsoft/azure/eventhubs/impl/MessagingFactory.java @@ -16,6 +16,7 @@ import java.io.IOException; import java.nio.channels.UnresolvedAddressException; import java.time.Duration; +import java.time.Instant; import java.util.LinkedList; import java.util.List; import java.util.Locale; @@ -51,6 +52,7 @@ public final class MessagingFactory extends ClientEntity implements AmqpConnecti private CompletableFuture open; private CompletableFuture openTimer; private CompletableFuture closeTimer; + private String reactorCreationTime; MessagingFactory(final ConnectionStringBuilder builder, final RetryPolicy retryPolicy, @@ -159,6 +161,8 @@ private void startReactor(final ReactorHandler reactorHandler) throws IOExceptio reactorHandler.unsafeSetReactorDispatcher(this.reactorDispatcher); } + this.reactorCreationTime = Instant.now().toString(); + executor.execute(new RunReactor(newReactor, executor)); } @@ -259,6 +263,7 @@ public void onConnectionError(ErrorCondition error) { this.hostName, link.getName())); } + link.setCondition(error); link.close(); closedLinks.add(link); } diff --git a/azure-eventhubs/src/main/java/com/microsoft/azure/eventhubs/impl/SessionHandler.java b/azure-eventhubs/src/main/java/com/microsoft/azure/eventhubs/impl/SessionHandler.java index d766012e6ee8..65714d2e57c5 100644 --- a/azure-eventhubs/src/main/java/com/microsoft/azure/eventhubs/impl/SessionHandler.java +++ b/azure-eventhubs/src/main/java/com/microsoft/azure/eventhubs/impl/SessionHandler.java @@ -47,7 +47,6 @@ public void onSessionLocalOpen(Event e) { } if (this.onRemoteSessionOpenError != null) { - ReactorHandler reactorHandler = null; final Reactor reactor = e.getReactor(); final Iterator reactorEventHandlers = reactor.getHandler().children(); @@ -63,11 +62,11 @@ public void onSessionLocalOpen(Event e) { final Session session = e.getSession(); try { - reactorDispatcher.invoke((int) this.openTimeout.toMillis(), new SessionTimeoutHandler(session)); - } catch (IOException ignore) { + reactorDispatcher.invoke((int) this.openTimeout.toMillis(), new SessionTimeoutHandler(session, entityName)); + } catch (IOException ioException) { if (TRACE_LOGGER.isWarnEnabled()) { TRACE_LOGGER.warn(String.format(Locale.US, "onSessionLocalOpen entityName[%s], reactorDispatcherError[%s]", - this.entityName, ignore.getMessage())); + this.entityName, ioException.getMessage())); } session.close(); @@ -76,7 +75,7 @@ public void onSessionLocalOpen(Event e) { new EventHubException( false, String.format("onSessionLocalOpen entityName[%s], underlying IO of reactorDispatcher faulted with error: %s", - this.entityName, ignore.getMessage()), ignore)); + this.entityName, ioException.getMessage()), ioException)); } } } @@ -114,28 +113,46 @@ public void onSessionRemoteClose(Event e) { } final Session session = e.getSession(); + ErrorCondition condition = session != null ? session.getRemoteCondition() : null; + if (session != null && session.getLocalState() != EndpointState.CLOSED) { + if (TRACE_LOGGER.isInfoEnabled()) { + TRACE_LOGGER.info(String.format(Locale.US, "onSessionRemoteClose closing a local session for entityName[%s], condition[%s], description[%s]", + this.entityName, + condition != null ? condition.getCondition() : "n/a", + condition != null ? condition.getDescription() : "n/a")); + } + + session.setCondition(session.getRemoteCondition()); session.close(); } this.sessionOpenErrorDispatched = true; if (!sessionCreated && this.onRemoteSessionOpenError != null) - this.onRemoteSessionOpenError.accept(session.getRemoteCondition(), null); + this.onRemoteSessionOpenError.accept(condition, null); } @Override public void onSessionFinal(Event e) { if (TRACE_LOGGER.isInfoEnabled()) { - TRACE_LOGGER.info(String.format(Locale.US, "onSessionFinal entityName[%s]", this.entityName)); + final Session session = e.getSession(); + ErrorCondition condition = session != null ? session.getCondition() : null; + + TRACE_LOGGER.info(String.format(Locale.US, "onSessionFinal entityName[%s], condition[%s], description[%s]", + this.entityName, + condition != null ? condition.getCondition() : "n/a", + condition != null ? condition.getDescription() : "n/a")); } } private class SessionTimeoutHandler extends DispatchHandler { private final Session session; + private final String entityName; - public SessionTimeoutHandler(final Session session) { + SessionTimeoutHandler(final Session session, final String entityName) { this.session = session; + this.entityName = entityName; } @Override @@ -149,7 +166,8 @@ public void onEvent() { if (!sessionCreated && !sessionOpenErrorDispatched) { if (TRACE_LOGGER.isWarnEnabled()) { - TRACE_LOGGER.warn(String.format(Locale.US, "SessionTimeoutHandler.onEvent - session open timed out.")); + TRACE_LOGGER.warn(String.format(Locale.US, "SessionTimeoutHandler.onEvent - entityName[%s], session open timed out.", + this.entityName)); } } } diff --git a/azure-eventhubs/src/test/java/com/microsoft/azure/eventhubs/exceptioncontracts/ReactorFaultTest.java b/azure-eventhubs/src/test/java/com/microsoft/azure/eventhubs/exceptioncontracts/ReactorFaultTest.java index b2466f99e3e6..56786c4019a9 100644 --- a/azure-eventhubs/src/test/java/com/microsoft/azure/eventhubs/exceptioncontracts/ReactorFaultTest.java +++ b/azure-eventhubs/src/test/java/com/microsoft/azure/eventhubs/exceptioncontracts/ReactorFaultTest.java @@ -6,12 +6,16 @@ import com.microsoft.azure.eventhubs.lib.ApiTestBase; import com.microsoft.azure.eventhubs.lib.TestContext; import org.apache.qpid.proton.engine.BaseHandler; +import org.apache.qpid.proton.engine.Event; +import org.apache.qpid.proton.engine.impl.CollectorImpl; +import org.apache.qpid.proton.engine.impl.ConnectionImpl; import org.apache.qpid.proton.reactor.Reactor; import org.junit.Assert; import org.junit.BeforeClass; import org.junit.Test; import java.lang.reflect.Field; +import java.util.Iterator; import java.util.concurrent.Executors; import java.util.concurrent.TimeUnit; @@ -69,4 +73,60 @@ public void handle(org.apache.qpid.proton.engine.Event e) { eventHubClient.closeSync(); } } + + @Test() + public void VerifyTransportAbort() throws Exception { + final EventHubClient eventHubClient = EventHubClient.createSync(connStr.toString(), TestContext.EXECUTOR_SERVICE); + try { + final PartitionReceiver partitionReceiver = eventHubClient.createEpochReceiverSync( + "$default", "0", EventPosition.fromStartOfStream(), System.currentTimeMillis()); + final Iterable firstBatch = partitionReceiver.receiveSync(100); + Assert.assertTrue(firstBatch != null); + + long sequenceNumber = -1; + final Iterator iterator = firstBatch.iterator(); + while (iterator.hasNext()) { + sequenceNumber = iterator.next().getSystemProperties().getSequenceNumber(); + } + + Assert.assertTrue(sequenceNumber > -1); + + Executors.newScheduledThreadPool(1).schedule(new Runnable() { + @Override + public void run() { + try { + final Field factoryField = EventHubClientImpl.class.getDeclaredField("underlyingFactory"); + factoryField.setAccessible(true); + final MessagingFactory underlyingFactory = (MessagingFactory) factoryField.get(eventHubClient); + + final Field reactorField = MessagingFactory.class.getDeclaredField("reactor"); + reactorField.setAccessible(true); + final Reactor reactor = (Reactor) reactorField.get(underlyingFactory); + + final Field connectionField = MessagingFactory.class.getDeclaredField("connection"); + connectionField.setAccessible(true); + final ConnectionImpl connection = (ConnectionImpl) connectionField.get(underlyingFactory); + + ((CollectorImpl) reactor.collector()).put(Event.Type.TRANSPORT_ERROR, connection.getTransport()); + } catch (Exception e) { + Assert.fail(e.getMessage()); + } + } + }, 5, TimeUnit.SECONDS); + + try { + Thread.sleep(10000); + + final Iterable events = partitionReceiver.receiveSync(100); + Assert.assertTrue(events != null && events.iterator().hasNext()); + Assert.assertEquals(sequenceNumber + 1, events.iterator().next().getSystemProperties().getSequenceNumber()); + } catch (Exception e) { + Assert.fail(e.getMessage()); + } finally { + partitionReceiver.closeSync(); + } + } finally { + eventHubClient.closeSync(); + } + } } From fec5a031ec21c28209d24078738ea7eaf1df5913 Mon Sep 17 00:00:00 2001 From: SJ Date: Wed, 2 Jan 2019 12:42:08 -0800 Subject: [PATCH 08/42] Prep for releasing client 2.0.0 and EPH 2.2.0 (#415) --- ConsumingEvents.md | 2 +- PublishingEvents.md | 2 +- azure-eventhubs-eph/pom.xml | 4 ++-- azure-eventhubs-extensions/pom.xml | 2 +- azure-eventhubs/pom.xml | 2 +- .../com/microsoft/azure/eventhubs/impl/ClientConstants.java | 2 +- pom.xml | 2 +- readme.md | 4 ++-- 8 files changed, 10 insertions(+), 10 deletions(-) diff --git a/ConsumingEvents.md b/ConsumingEvents.md index d1c853e86446..cff94be57c9e 100644 --- a/ConsumingEvents.md +++ b/ConsumingEvents.md @@ -26,7 +26,7 @@ following dependency declaration inside of your Maven project file: com.microsoft.azure azure-eventhubs - 1.3.0 + 2.0.0 ``` diff --git a/PublishingEvents.md b/PublishingEvents.md index 20c3bb58cd3b..5a9eb428e531 100644 --- a/PublishingEvents.md +++ b/PublishingEvents.md @@ -12,7 +12,7 @@ following dependency declaration inside of your Maven project file: com.microsoft.azure azure-eventhubs - 1.3.0 + 2.0.0 ``` diff --git a/azure-eventhubs-eph/pom.xml b/azure-eventhubs-eph/pom.xml index bcd18922bd35..f0d357b38d90 100644 --- a/azure-eventhubs-eph/pom.xml +++ b/azure-eventhubs-eph/pom.xml @@ -4,10 +4,10 @@ com.microsoft.azure azure-eventhubs-clients - 1.3.0 + 2.0.0 - 2.1.0 + 2.2.0 4.0.0 diff --git a/azure-eventhubs-extensions/pom.xml b/azure-eventhubs-extensions/pom.xml index 8dc460003a8a..5dc33296bbba 100644 --- a/azure-eventhubs-extensions/pom.xml +++ b/azure-eventhubs-extensions/pom.xml @@ -7,7 +7,7 @@ com.microsoft.azure azure-eventhubs-clients - 1.3.0 + 2.0.0 4.0.0 diff --git a/azure-eventhubs/pom.xml b/azure-eventhubs/pom.xml index d502a5139d45..786b4ea51688 100644 --- a/azure-eventhubs/pom.xml +++ b/azure-eventhubs/pom.xml @@ -4,7 +4,7 @@ com.microsoft.azure azure-eventhubs-clients - 1.3.0 + 2.0.0 4.0.0 diff --git a/azure-eventhubs/src/main/java/com/microsoft/azure/eventhubs/impl/ClientConstants.java b/azure-eventhubs/src/main/java/com/microsoft/azure/eventhubs/impl/ClientConstants.java index eac75a7e404a..80ab06af36d0 100644 --- a/azure-eventhubs/src/main/java/com/microsoft/azure/eventhubs/impl/ClientConstants.java +++ b/azure-eventhubs/src/main/java/com/microsoft/azure/eventhubs/impl/ClientConstants.java @@ -37,7 +37,7 @@ public final class ClientConstants { public final static String NO_RETRY = "NoRetry"; public final static String DEFAULT_RETRY = "Default"; public final static String PRODUCT_NAME = "MSJavaClient"; - public final static String CURRENT_JAVACLIENT_VERSION = "1.3.0"; + public final static String CURRENT_JAVACLIENT_VERSION = "2.0.0"; public static final String PLATFORM_INFO = getPlatformInfo(); public static final String FRAMEWORK_INFO = getFrameworkInfo(); public static final String CBS_ADDRESS = "$cbs"; diff --git a/pom.xml b/pom.xml index 867a20c7f54e..c99ba2231242 100644 --- a/pom.xml +++ b/pom.xml @@ -6,7 +6,7 @@ com.microsoft.azure azure-eventhubs-clients - 1.3.0 + 2.0.0 pom https://github.com/Azure/azure-event-hubs diff --git a/readme.md b/readme.md index 2eff6bb2f17e..ea52c6191cd0 100644 --- a/readme.md +++ b/readme.md @@ -44,7 +44,7 @@ the required versions of Apache Qpid Proton-J, and the cryptography library BCPK com.microsoft.azure azure-eventhubs - 1.3.0 + 2.0.0 ``` @@ -61,7 +61,7 @@ It pulls the required versions of Event Hubs, Azure Storage and GSon libraries. com.microsoft.azure azure-eventhubs-eph - 2.1.0 + 2.2.0 ``` From 9305f06c411540a51ce552179b18b22618a4d77a Mon Sep 17 00:00:00 2001 From: SJ Date: Fri, 4 Jan 2019 16:59:37 -0800 Subject: [PATCH 09/42] Ensure that links are closed when transport error occurrs (#417) * ensure links are recreated on transport/connection failure * update API document for EventProcessorOptions class * add traces for link create/close case --- .../EventProcessorOptions.java | 2 +- .../azure/eventhubs/impl/BaseLinkHandler.java | 6 ++++++ .../azure/eventhubs/impl/MessageReceiver.java | 7 +++++++ .../azure/eventhubs/impl/MessageSender.java | 7 +++++++ .../eventhubs/impl/MessagingFactory.java | 20 ++++++++++++++----- 5 files changed, 36 insertions(+), 6 deletions(-) diff --git a/azure-eventhubs-eph/src/main/java/com/microsoft/azure/eventprocessorhost/EventProcessorOptions.java b/azure-eventhubs-eph/src/main/java/com/microsoft/azure/eventprocessorhost/EventProcessorOptions.java index e5d5ac8cce5e..b1f73fe348a7 100644 --- a/azure-eventhubs-eph/src/main/java/com/microsoft/azure/eventprocessorhost/EventProcessorOptions.java +++ b/azure-eventhubs-eph/src/main/java/com/microsoft/azure/eventprocessorhost/EventProcessorOptions.java @@ -114,7 +114,7 @@ public int getPrefetchCount() { /*** * Sets the prefetch count for the underlying event hub client. * - * The default is 500. This controls how many events are received in advance. + * The default is 300. This controls how many events are received in advance. * * @param prefetchCount The new prefetch count. */ diff --git a/azure-eventhubs/src/main/java/com/microsoft/azure/eventhubs/impl/BaseLinkHandler.java b/azure-eventhubs/src/main/java/com/microsoft/azure/eventhubs/impl/BaseLinkHandler.java index 4386bd3ad831..592a5a96538c 100644 --- a/azure-eventhubs/src/main/java/com/microsoft/azure/eventhubs/impl/BaseLinkHandler.java +++ b/azure-eventhubs/src/main/java/com/microsoft/azure/eventhubs/impl/BaseLinkHandler.java @@ -75,6 +75,12 @@ public void processOnClose(Link link, ErrorCondition condition) { } public void processOnClose(Link link, Exception exception) { + if (TRACE_LOGGER.isInfoEnabled()) { + TRACE_LOGGER.info(String.format("processOnClose linkName[%s], exception[%s]", + link.getName(), + exception != null ? exception.getMessage() : "n/a")); + } + this.underlyingEntity.onError(exception); } diff --git a/azure-eventhubs/src/main/java/com/microsoft/azure/eventhubs/impl/MessageReceiver.java b/azure-eventhubs/src/main/java/com/microsoft/azure/eventhubs/impl/MessageReceiver.java index 7b43796e6256..8ed5cbc82cc3 100644 --- a/azure-eventhubs/src/main/java/com/microsoft/azure/eventhubs/impl/MessageReceiver.java +++ b/azure-eventhubs/src/main/java/com/microsoft/azure/eventhubs/impl/MessageReceiver.java @@ -473,6 +473,13 @@ private void scheduleOperationTimer(final TimeoutTracker tracker) { private void createReceiveLink() { synchronized (this.errorConditionLock) { if (this.creatingLink) { + if (TRACE_LOGGER.isInfoEnabled()) { + TRACE_LOGGER.info( + String.format(Locale.US, + "clientId[%s], path[%s], operationTimeout[%s], creating a receive link is already in progress", + this.getClientId(), this.receivePath, this.operationTimeout)); + } + return; } diff --git a/azure-eventhubs/src/main/java/com/microsoft/azure/eventhubs/impl/MessageSender.java b/azure-eventhubs/src/main/java/com/microsoft/azure/eventhubs/impl/MessageSender.java index 6f67323ce997..5db1765d5668 100644 --- a/azure-eventhubs/src/main/java/com/microsoft/azure/eventhubs/impl/MessageSender.java +++ b/azure-eventhubs/src/main/java/com/microsoft/azure/eventhubs/impl/MessageSender.java @@ -588,6 +588,13 @@ private void cleanupFailedSend(final ReplayableWorkItem failedSend, final private void createSendLink() { synchronized (this.errorConditionLock) { if (this.creatingLink) { + if (TRACE_LOGGER.isInfoEnabled()) { + TRACE_LOGGER.info( + String.format(Locale.US, + "clientId[%s], path[%s], operationTimeout[%s], creating a send link is already in progress", + this.getClientId(), this.sendPath, this.operationTimeout)); + } + return; } diff --git a/azure-eventhubs/src/main/java/com/microsoft/azure/eventhubs/impl/MessagingFactory.java b/azure-eventhubs/src/main/java/com/microsoft/azure/eventhubs/impl/MessagingFactory.java index 24031a7c74ca..a87802275945 100644 --- a/azure-eventhubs/src/main/java/com/microsoft/azure/eventhubs/impl/MessagingFactory.java +++ b/azure-eventhubs/src/main/java/com/microsoft/azure/eventhubs/impl/MessagingFactory.java @@ -7,6 +7,7 @@ import com.microsoft.azure.eventhubs.*; import com.microsoft.azure.eventhubs.TimeoutException; +import org.apache.qpid.proton.amqp.Symbol; import org.apache.qpid.proton.amqp.transport.ErrorCondition; import org.apache.qpid.proton.engine.*; import org.apache.qpid.proton.reactor.Reactor; @@ -256,7 +257,7 @@ public void onConnectionError(ErrorCondition error) { final List closedLinks = new LinkedList<>(); for (Link link : oldRegisteredLinksCopy) { - if (link.getLocalState() != EndpointState.CLOSED && link.getRemoteState() != EndpointState.CLOSED) { + if (link.getLocalState() != EndpointState.CLOSED) { if (TRACE_LOGGER.isWarnEnabled()) { TRACE_LOGGER.warn(String.format(Locale.US, "onConnectionError: messagingFactory[%s], hostname[%s], closing link [%s]", this.getClientId(), @@ -287,7 +288,7 @@ public void onConnectionError(ErrorCondition error) { for (Link link : closedLinks) { final Handler handler = BaseHandler.getHandler(link); - if (handler != null && handler instanceof BaseLinkHandler) { + if (handler instanceof BaseLinkHandler) { final BaseLinkHandler linkHandler = (BaseLinkHandler) handler; linkHandler.processOnClose(link, error); } @@ -333,17 +334,26 @@ private void onReactorError(Exception cause) { // below .close() calls (local closes). // But, we still need to change the states of these to Closed - so that subsequent retries - will // treat the links and connection as closed and re-establish them and continue running on new Reactor instance. - if (oldConnection.getLocalState() != EndpointState.CLOSED && oldConnection.getRemoteState() != EndpointState.CLOSED) { + ErrorCondition errorCondition = new ErrorCondition(Symbol.getSymbol("messagingfactory.onreactorerror"), cause.getMessage()); + if (oldConnection.getLocalState() != EndpointState.CLOSED) { + if (TRACE_LOGGER.isWarnEnabled()) { + TRACE_LOGGER.warn(String.format(Locale.US, "onReactorError: messagingFactory[%s], hostname[%s], closing current connection", + this.getClientId(), + this.hostName)); + } + + oldConnection.setCondition(errorCondition); oldConnection.close(); } for (final Link link : oldRegisteredLinksCopy) { - if (link.getLocalState() != EndpointState.CLOSED && link.getRemoteState() != EndpointState.CLOSED) { + if (link.getLocalState() != EndpointState.CLOSED) { + link.setCondition(errorCondition); link.close(); } final Handler handler = BaseHandler.getHandler(link); - if (handler != null && handler instanceof BaseLinkHandler) { + if (handler instanceof BaseLinkHandler) { final BaseLinkHandler linkHandler = (BaseLinkHandler) handler; linkHandler.processOnClose(link, cause); } From e6ef7f089d9e976f40a9e9e02b9394021d134a3d Mon Sep 17 00:00:00 2001 From: SJ Date: Wed, 9 Jan 2019 18:28:53 -0800 Subject: [PATCH 10/42] Prep for releasing client 2.1.0 and EPH 2.3.0 (#418) --- ConsumingEvents.md | 2 +- PublishingEvents.md | 2 +- azure-eventhubs-eph/pom.xml | 4 ++-- azure-eventhubs-extensions/pom.xml | 2 +- azure-eventhubs/pom.xml | 2 +- .../com/microsoft/azure/eventhubs/impl/ClientConstants.java | 2 +- pom.xml | 2 +- readme.md | 4 ++-- 8 files changed, 10 insertions(+), 10 deletions(-) diff --git a/ConsumingEvents.md b/ConsumingEvents.md index cff94be57c9e..5f1da1740d92 100644 --- a/ConsumingEvents.md +++ b/ConsumingEvents.md @@ -26,7 +26,7 @@ following dependency declaration inside of your Maven project file: com.microsoft.azure azure-eventhubs - 2.0.0 + 2.1.0 ``` diff --git a/PublishingEvents.md b/PublishingEvents.md index 5a9eb428e531..f4254366e3b6 100644 --- a/PublishingEvents.md +++ b/PublishingEvents.md @@ -12,7 +12,7 @@ following dependency declaration inside of your Maven project file: com.microsoft.azure azure-eventhubs - 2.0.0 + 2.1.0 ``` diff --git a/azure-eventhubs-eph/pom.xml b/azure-eventhubs-eph/pom.xml index f0d357b38d90..c7ba9a77e6c2 100644 --- a/azure-eventhubs-eph/pom.xml +++ b/azure-eventhubs-eph/pom.xml @@ -4,10 +4,10 @@ com.microsoft.azure azure-eventhubs-clients - 2.0.0 + 2.1.0 - 2.2.0 + 2.3.0 4.0.0 diff --git a/azure-eventhubs-extensions/pom.xml b/azure-eventhubs-extensions/pom.xml index 5dc33296bbba..c632875a814b 100644 --- a/azure-eventhubs-extensions/pom.xml +++ b/azure-eventhubs-extensions/pom.xml @@ -7,7 +7,7 @@ com.microsoft.azure azure-eventhubs-clients - 2.0.0 + 2.1.0 4.0.0 diff --git a/azure-eventhubs/pom.xml b/azure-eventhubs/pom.xml index 786b4ea51688..f216bc9ba90c 100644 --- a/azure-eventhubs/pom.xml +++ b/azure-eventhubs/pom.xml @@ -4,7 +4,7 @@ com.microsoft.azure azure-eventhubs-clients - 2.0.0 + 2.1.0 4.0.0 diff --git a/azure-eventhubs/src/main/java/com/microsoft/azure/eventhubs/impl/ClientConstants.java b/azure-eventhubs/src/main/java/com/microsoft/azure/eventhubs/impl/ClientConstants.java index 80ab06af36d0..5389dbcc93c5 100644 --- a/azure-eventhubs/src/main/java/com/microsoft/azure/eventhubs/impl/ClientConstants.java +++ b/azure-eventhubs/src/main/java/com/microsoft/azure/eventhubs/impl/ClientConstants.java @@ -37,7 +37,7 @@ public final class ClientConstants { public final static String NO_RETRY = "NoRetry"; public final static String DEFAULT_RETRY = "Default"; public final static String PRODUCT_NAME = "MSJavaClient"; - public final static String CURRENT_JAVACLIENT_VERSION = "2.0.0"; + public final static String CURRENT_JAVACLIENT_VERSION = "2.1.0"; public static final String PLATFORM_INFO = getPlatformInfo(); public static final String FRAMEWORK_INFO = getFrameworkInfo(); public static final String CBS_ADDRESS = "$cbs"; diff --git a/pom.xml b/pom.xml index c99ba2231242..00654a7713c2 100644 --- a/pom.xml +++ b/pom.xml @@ -6,7 +6,7 @@ com.microsoft.azure azure-eventhubs-clients - 2.0.0 + 2.1.0 pom https://github.com/Azure/azure-event-hubs diff --git a/readme.md b/readme.md index ea52c6191cd0..b12893ad3a4e 100644 --- a/readme.md +++ b/readme.md @@ -44,7 +44,7 @@ the required versions of Apache Qpid Proton-J, and the cryptography library BCPK com.microsoft.azure azure-eventhubs - 2.0.0 + 2.1.0 ``` @@ -61,7 +61,7 @@ It pulls the required versions of Event Hubs, Azure Storage and GSon libraries. com.microsoft.azure azure-eventhubs-eph - 2.2.0 + 2.3.0 ``` From 11c68b086da60d6ebbf8108d1ac3d567efb09a5b Mon Sep 17 00:00:00 2001 From: SJ Date: Thu, 10 Jan 2019 11:11:02 -0800 Subject: [PATCH 11/42] Update prefetch sendflow logic and increment version for new release (#420) --- ConsumingEvents.md | 2 +- PublishingEvents.md | 2 +- azure-eventhubs-eph/pom.xml | 2 +- azure-eventhubs-extensions/pom.xml | 2 +- azure-eventhubs/pom.xml | 2 +- .../microsoft/azure/eventhubs/impl/BaseLinkHandler.java | 2 +- .../microsoft/azure/eventhubs/impl/ClientConstants.java | 2 +- .../microsoft/azure/eventhubs/impl/MessageReceiver.java | 7 ++++++- pom.xml | 2 +- readme.md | 2 +- 10 files changed, 15 insertions(+), 10 deletions(-) diff --git a/ConsumingEvents.md b/ConsumingEvents.md index 5f1da1740d92..3f890a4b49f5 100644 --- a/ConsumingEvents.md +++ b/ConsumingEvents.md @@ -26,7 +26,7 @@ following dependency declaration inside of your Maven project file: com.microsoft.azure azure-eventhubs - 2.1.0 + 2.2.0 ``` diff --git a/PublishingEvents.md b/PublishingEvents.md index f4254366e3b6..67e26833eb6b 100644 --- a/PublishingEvents.md +++ b/PublishingEvents.md @@ -12,7 +12,7 @@ following dependency declaration inside of your Maven project file: com.microsoft.azure azure-eventhubs - 2.1.0 + 2.2.0 ``` diff --git a/azure-eventhubs-eph/pom.xml b/azure-eventhubs-eph/pom.xml index c7ba9a77e6c2..83753e8a5f5e 100644 --- a/azure-eventhubs-eph/pom.xml +++ b/azure-eventhubs-eph/pom.xml @@ -4,7 +4,7 @@ com.microsoft.azure azure-eventhubs-clients - 2.1.0 + 2.2.0 2.3.0 diff --git a/azure-eventhubs-extensions/pom.xml b/azure-eventhubs-extensions/pom.xml index c632875a814b..7266898a4e9e 100644 --- a/azure-eventhubs-extensions/pom.xml +++ b/azure-eventhubs-extensions/pom.xml @@ -7,7 +7,7 @@ com.microsoft.azure azure-eventhubs-clients - 2.1.0 + 2.2.0 4.0.0 diff --git a/azure-eventhubs/pom.xml b/azure-eventhubs/pom.xml index f216bc9ba90c..acb77607d50b 100644 --- a/azure-eventhubs/pom.xml +++ b/azure-eventhubs/pom.xml @@ -4,7 +4,7 @@ com.microsoft.azure azure-eventhubs-clients - 2.1.0 + 2.2.0 4.0.0 diff --git a/azure-eventhubs/src/main/java/com/microsoft/azure/eventhubs/impl/BaseLinkHandler.java b/azure-eventhubs/src/main/java/com/microsoft/azure/eventhubs/impl/BaseLinkHandler.java index 592a5a96538c..5ab442a19cf1 100644 --- a/azure-eventhubs/src/main/java/com/microsoft/azure/eventhubs/impl/BaseLinkHandler.java +++ b/azure-eventhubs/src/main/java/com/microsoft/azure/eventhubs/impl/BaseLinkHandler.java @@ -36,7 +36,7 @@ public void onLinkLocalClose(Event event) { @Override public void onLinkRemoteClose(Event event) { final Link link = event.getLink(); - final ErrorCondition condition = link.getCondition(); + final ErrorCondition condition = link.getRemoteCondition(); if (TRACE_LOGGER.isInfoEnabled()) { TRACE_LOGGER.info(String.format("onLinkRemoteClose linkName[%s], errorCondition[%s], errorDescription[%s]", diff --git a/azure-eventhubs/src/main/java/com/microsoft/azure/eventhubs/impl/ClientConstants.java b/azure-eventhubs/src/main/java/com/microsoft/azure/eventhubs/impl/ClientConstants.java index 5389dbcc93c5..cf56737ca4f6 100644 --- a/azure-eventhubs/src/main/java/com/microsoft/azure/eventhubs/impl/ClientConstants.java +++ b/azure-eventhubs/src/main/java/com/microsoft/azure/eventhubs/impl/ClientConstants.java @@ -37,7 +37,7 @@ public final class ClientConstants { public final static String NO_RETRY = "NoRetry"; public final static String DEFAULT_RETRY = "Default"; public final static String PRODUCT_NAME = "MSJavaClient"; - public final static String CURRENT_JAVACLIENT_VERSION = "2.1.0"; + public final static String CURRENT_JAVACLIENT_VERSION = "2.2.0"; public static final String PLATFORM_INFO = getPlatformInfo(); public static final String FRAMEWORK_INFO = getFrameworkInfo(); public static final String CBS_ADDRESS = "$cbs"; diff --git a/azure-eventhubs/src/main/java/com/microsoft/azure/eventhubs/impl/MessageReceiver.java b/azure-eventhubs/src/main/java/com/microsoft/azure/eventhubs/impl/MessageReceiver.java index 8ed5cbc82cc3..c44c81da6b28 100644 --- a/azure-eventhubs/src/main/java/com/microsoft/azure/eventhubs/impl/MessageReceiver.java +++ b/azure-eventhubs/src/main/java/com/microsoft/azure/eventhubs/impl/MessageReceiver.java @@ -613,7 +613,7 @@ private Message pollPrefetchQueue() { private void sendFlow(final int credits) { // slow down sending the flow - to make the protocol less-chat'y this.nextCreditToFlow += credits; - if (this.nextCreditToFlow >= this.prefetchCount || this.nextCreditToFlow >= 100) { + if (this.shouldSendFlow()) { final int tempFlow = this.nextCreditToFlow; this.receiveLink.flow(tempFlow); this.nextCreditToFlow = 0; @@ -625,6 +625,11 @@ private void sendFlow(final int credits) { } } + private boolean shouldSendFlow() { + return (this.nextCreditToFlow > 0 && this.nextCreditToFlow >= (this.prefetchCount / 2)) || + (this.nextCreditToFlow >= 100); + } + private void scheduleLinkOpenTimeout(final TimeoutTracker timeout) { // timer to signal a timeout if exceeds the operationTimeout on MessagingFactory this.openTimer = timer.schedule( diff --git a/pom.xml b/pom.xml index 00654a7713c2..f4060015d16c 100644 --- a/pom.xml +++ b/pom.xml @@ -6,7 +6,7 @@ com.microsoft.azure azure-eventhubs-clients - 2.1.0 + 2.2.0 pom https://github.com/Azure/azure-event-hubs diff --git a/readme.md b/readme.md index b12893ad3a4e..6bd36e8df0b7 100644 --- a/readme.md +++ b/readme.md @@ -44,7 +44,7 @@ the required versions of Apache Qpid Proton-J, and the cryptography library BCPK com.microsoft.azure azure-eventhubs - 2.1.0 + 2.2.0 ``` From a1fa1a55ffe2c7f122ba92e8d8391d237b305bf9 Mon Sep 17 00:00:00 2001 From: JamesBirdsall Date: Thu, 10 Jan 2019 13:47:51 -0800 Subject: [PATCH 12/42] Fix args for proxy auth call to Authenticator (#421) --- .../eventhubs/impl/WebSocketProxyConnectionHandler.java | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/azure-eventhubs/src/main/java/com/microsoft/azure/eventhubs/impl/WebSocketProxyConnectionHandler.java b/azure-eventhubs/src/main/java/com/microsoft/azure/eventhubs/impl/WebSocketProxyConnectionHandler.java index 41dc0baa3d04..81220c33868f 100644 --- a/azure-eventhubs/src/main/java/com/microsoft/azure/eventhubs/impl/WebSocketProxyConnectionHandler.java +++ b/azure-eventhubs/src/main/java/com/microsoft/azure/eventhubs/impl/WebSocketProxyConnectionHandler.java @@ -124,9 +124,9 @@ private Map getAuthorizationHeader() { getRemoteHostName(), null, getRemotePort(), - null, - null, - "http", + "https", + "Event Hubs client websocket proxy support", + "basic", null, Authenticator.RequestorType.PROXY); if (authentication == null) { From 5fbdbe422f54fabfec1639a153f0d032cc24fc87 Mon Sep 17 00:00:00 2001 From: SJ Date: Tue, 15 Jan 2019 10:05:37 -0800 Subject: [PATCH 13/42] Prepare EPH 2.3.4 release (#423) --- azure-eventhubs-eph/pom.xml | 2 +- readme.md | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/azure-eventhubs-eph/pom.xml b/azure-eventhubs-eph/pom.xml index 83753e8a5f5e..2e66fab09c92 100644 --- a/azure-eventhubs-eph/pom.xml +++ b/azure-eventhubs-eph/pom.xml @@ -7,7 +7,7 @@ 2.2.0 - 2.3.0 + 2.4.0 4.0.0 diff --git a/readme.md b/readme.md index 6bd36e8df0b7..aaa10caf557f 100644 --- a/readme.md +++ b/readme.md @@ -61,7 +61,7 @@ It pulls the required versions of Event Hubs, Azure Storage and GSon libraries. com.microsoft.azure azure-eventhubs-eph - 2.3.0 + 2.4.0 ``` From 3ddd268a9ac94bc79c810a5551bdc8d9eb1a48fd Mon Sep 17 00:00:00 2001 From: SJ Date: Tue, 15 Jan 2019 11:19:56 -0800 Subject: [PATCH 14/42] Prepare EPH 2.4.0 release (#423) (#424) From 120231b687f29f916c02e7a0dcfd1a6400bc43c2 Mon Sep 17 00:00:00 2001 From: JamesBirdsall Date: Tue, 29 Jan 2019 13:49:33 -0800 Subject: [PATCH 15/42] Handle proton:io errors with meaningful error msg (#427) * Handle proton:io errors with meaningful error msg * Use Proton-supplied message if present --- .../com/microsoft/azure/eventhubs/impl/AmqpConstants.java | 1 + .../com/microsoft/azure/eventhubs/impl/ClientConstants.java | 4 ++++ .../com/microsoft/azure/eventhubs/impl/ExceptionUtil.java | 6 ++++++ 3 files changed, 11 insertions(+) diff --git a/azure-eventhubs/src/main/java/com/microsoft/azure/eventhubs/impl/AmqpConstants.java b/azure-eventhubs/src/main/java/com/microsoft/azure/eventhubs/impl/AmqpConstants.java index 8ca75a0d2692..065e46fc1943 100644 --- a/azure-eventhubs/src/main/java/com/microsoft/azure/eventhubs/impl/AmqpConstants.java +++ b/azure-eventhubs/src/main/java/com/microsoft/azure/eventhubs/impl/AmqpConstants.java @@ -13,6 +13,7 @@ public final class AmqpConstants { public static final String APACHE = "apache.org"; + public static final String PROTON = "proton"; public static final String VENDOR = "com.microsoft"; public static final String AMQP_ANNOTATION_FORMAT = "amqp.annotation.%s >%s '%s'"; public static final String OFFSET_ANNOTATION_NAME = "x-opt-offset"; diff --git a/azure-eventhubs/src/main/java/com/microsoft/azure/eventhubs/impl/ClientConstants.java b/azure-eventhubs/src/main/java/com/microsoft/azure/eventhubs/impl/ClientConstants.java index cf56737ca4f6..fa0803dff084 100644 --- a/azure-eventhubs/src/main/java/com/microsoft/azure/eventhubs/impl/ClientConstants.java +++ b/azure-eventhubs/src/main/java/com/microsoft/azure/eventhubs/impl/ClientConstants.java @@ -20,6 +20,7 @@ public final class ClientConstants { public final static Symbol STORE_LOCK_LOST_ERROR = Symbol.getSymbol(AmqpConstants.VENDOR + ":store-lock-lost"); public final static Symbol PUBLISHER_REVOKED_ERROR = Symbol.getSymbol(AmqpConstants.VENDOR + ":publisher-revoked"); public final static Symbol TIMEOUT_ERROR = Symbol.getSymbol(AmqpConstants.VENDOR + ":timeout"); + public final static Symbol PROTON_IO_ERROR = Symbol.getSymbol(AmqpConstants.PROTON + ":io"); public final static Symbol TRACKING_ID_PROPERTY = Symbol.getSymbol(AmqpConstants.VENDOR + ":tracking-id"); public static final int MAX_MESSAGE_LENGTH_BYTES = 256 * 1024; public static final int MAX_FRAME_SIZE_BYTES = 64 * 1024; @@ -76,6 +77,9 @@ public final class ClientConstants { public static final String TOKEN_AUDIENCE_FORMAT = "amqp://%s/%s"; public static final String HTTPS_URI_FORMAT = "https://%s:%s"; public static final int MAX_RECEIVER_NAME_LENGTH = 64; + + public static final String COMMUNICATION_EXCEPTION_GENERIC_MESSAGE = "A communication error has occurred. " + + "This may be due to an incorrect host name in your connection string or a problem with your network connection."; /** * This is a constant defined to represent the start of a partition stream in EventHub. diff --git a/azure-eventhubs/src/main/java/com/microsoft/azure/eventhubs/impl/ExceptionUtil.java b/azure-eventhubs/src/main/java/com/microsoft/azure/eventhubs/impl/ExceptionUtil.java index 0814f2ceeeb9..56fa9b28ee36 100644 --- a/azure-eventhubs/src/main/java/com/microsoft/azure/eventhubs/impl/ExceptionUtil.java +++ b/azure-eventhubs/src/main/java/com/microsoft/azure/eventhubs/impl/ExceptionUtil.java @@ -55,6 +55,12 @@ static Exception toException(ErrorCondition errorCondition) { return new EventHubException(true, new AmqpException(errorCondition)); } else if (errorCondition.getCondition() == AmqpErrorCode.ResourceLimitExceeded) { return new QuotaExceededException(new AmqpException(errorCondition)); + } else if (errorCondition.getCondition() == ClientConstants.PROTON_IO_ERROR) { + String message = ClientConstants.COMMUNICATION_EXCEPTION_GENERIC_MESSAGE; + if (errorCondition.getDescription() != null) { + message = errorCondition.getDescription(); + } + return new CommunicationException(message, null); } return new EventHubException(ClientConstants.DEFAULT_IS_TRANSIENT, errorCondition.getDescription()); From 58262883fb8932b166baca7d09cf87fa994fac06 Mon Sep 17 00:00:00 2001 From: JamesBirdsall Date: Wed, 6 Feb 2019 10:42:17 -0800 Subject: [PATCH 16/42] Minor changes to lease scanner (#428) * Add logging if the scanner threw an exception. * Change logging level to warn when scanner shuts down for any reason. * Scanner can call EventProcessorOptions.notifyOfException, which calls user code. Change notifyOfException to defensively catch any exceptions coming out of user code. --- .../eventprocessorhost/EventProcessorOptions.java | 12 +++++++++++- .../azure/eventprocessorhost/PartitionManager.java | 5 ++++- 2 files changed, 15 insertions(+), 2 deletions(-) diff --git a/azure-eventhubs-eph/src/main/java/com/microsoft/azure/eventprocessorhost/EventProcessorOptions.java b/azure-eventhubs-eph/src/main/java/com/microsoft/azure/eventprocessorhost/EventProcessorOptions.java index b1f73fe348a7..2d29111fbe1b 100644 --- a/azure-eventhubs-eph/src/main/java/com/microsoft/azure/eventprocessorhost/EventProcessorOptions.java +++ b/azure-eventhubs-eph/src/main/java/com/microsoft/azure/eventprocessorhost/EventProcessorOptions.java @@ -13,6 +13,9 @@ import java.util.function.Consumer; import java.util.function.Function; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + /*** * Options affecting the behavior of the event processor host instance in general. */ @@ -27,6 +30,8 @@ public final class EventProcessorOptions { return EventPosition.fromStartOfStream(); }; + private static final Logger TRACE_LOGGER = LoggerFactory.getLogger(EventProcessorOptions.class); + public EventProcessorOptions() { } @@ -212,7 +217,12 @@ void notifyOfException(String hostname, Exception exception, String action, Stri // Capture handler so it doesn't get set to null between test and use Consumer handler = this.exceptionNotificationHandler; if (handler != null) { - handler.accept(new ExceptionReceivedEventArgs(hostname, exception, action, partitionId)); + try { + handler.accept(new ExceptionReceivedEventArgs(hostname, exception, action, partitionId)); + } + catch (Exception e) { + TRACE_LOGGER.error("host " + hostname + ": caught exception from user-provided exception notification handler", e); + } } } diff --git a/azure-eventhubs-eph/src/main/java/com/microsoft/azure/eventprocessorhost/PartitionManager.java b/azure-eventhubs-eph/src/main/java/com/microsoft/azure/eventprocessorhost/PartitionManager.java index ffad0a9de930..438d81f74cef 100644 --- a/azure-eventhubs-eph/src/main/java/com/microsoft/azure/eventprocessorhost/PartitionManager.java +++ b/azure-eventhubs-eph/src/main/java/com/microsoft/azure/eventprocessorhost/PartitionManager.java @@ -294,6 +294,9 @@ private Void scan(boolean isFirst) { .whenCompleteAsync((didSteal, e) -> { TRACE_LOGGER.debug(this.hostContext.withHost("Scanning took " + (System.currentTimeMillis() - start))); + if ((e != null) && !(e instanceof ClosingException)) { + TRACE_LOGGER.warn(this.hostContext.withHost("Lease scanner got exception"), e); + } onPartitionCheckCompleteTestHook(); @@ -309,7 +312,7 @@ private Void scan(boolean isFirst) { } TRACE_LOGGER.debug(this.hostContext.withHost("Scheduling lease scanner in " + seconds)); } else { - TRACE_LOGGER.debug(this.hostContext.withHost("Not scheduling lease scanner due to shutdown")); + TRACE_LOGGER.warn(this.hostContext.withHost("Not scheduling lease scanner due to shutdown")); } }, this.hostContext.getExecutor()); From 6edab2c480946e2c4b2dbf4be75fb138f7b478b6 Mon Sep 17 00:00:00 2001 From: JamesBirdsall Date: Fri, 8 Mar 2019 11:04:24 -0800 Subject: [PATCH 17/42] Make EventData.SystemProperties completely public (#435) Porting testability changes from .NET Core to Java: provide full access to EventData's SystemProperties so that a complete EventData can be fabricated in tests. --- .../java/com/microsoft/azure/eventhubs/EventData.java | 10 +++++++++- .../microsoft/azure/eventhubs/impl/EventDataImpl.java | 4 ++++ 2 files changed, 13 insertions(+), 1 deletion(-) diff --git a/azure-eventhubs/src/main/java/com/microsoft/azure/eventhubs/EventData.java b/azure-eventhubs/src/main/java/com/microsoft/azure/eventhubs/EventData.java index d9884bf248c5..2f037bb77f8e 100755 --- a/azure-eventhubs/src/main/java/com/microsoft/azure/eventhubs/EventData.java +++ b/azure-eventhubs/src/main/java/com/microsoft/azure/eventhubs/EventData.java @@ -145,13 +145,21 @@ static EventData create(final ByteBuffer buffer) { * @see SystemProperties#getEnqueuedTime */ SystemProperties getSystemProperties(); + void setSystemProperties(SystemProperties props); - class SystemProperties extends HashMap { + public class SystemProperties extends HashMap { private static final long serialVersionUID = -2827050124966993723L; public SystemProperties(final HashMap map) { super(Collections.unmodifiableMap(map)); } + + public SystemProperties(final long sequenceNumber, final Instant enqueuedTimeUtc, final String offset, final String partitionKey) { + this.put(AmqpConstants.SEQUENCE_NUMBER_ANNOTATION_NAME, sequenceNumber); + this.put(AmqpConstants.ENQUEUED_TIME_UTC_ANNOTATION_NAME, new Date(enqueuedTimeUtc.toEpochMilli())); + this.put(AmqpConstants.OFFSET_ANNOTATION_NAME, offset); + this.put(AmqpConstants.PARTITION_KEY_ANNOTATION_NAME, partitionKey); + } public String getOffset() { return this.getSystemProperty(AmqpConstants.OFFSET_ANNOTATION_NAME); diff --git a/azure-eventhubs/src/main/java/com/microsoft/azure/eventhubs/impl/EventDataImpl.java b/azure-eventhubs/src/main/java/com/microsoft/azure/eventhubs/impl/EventDataImpl.java index 69986268623c..4dfe10d60d0b 100755 --- a/azure-eventhubs/src/main/java/com/microsoft/azure/eventhubs/impl/EventDataImpl.java +++ b/azure-eventhubs/src/main/java/com/microsoft/azure/eventhubs/impl/EventDataImpl.java @@ -146,6 +146,10 @@ public SystemProperties getSystemProperties() { return this.systemProperties; } + public void setSystemProperties(EventData.SystemProperties props) { + this.systemProperties = props; + } + // This is intended to be used while sending EventData - so EventData.SystemProperties will not be copied over to the AmqpMessage Message toAmqpMessage() { final Message amqpMessage = Proton.message(); From 07b40723a4e4b2590894f71d9b56e940305addc6 Mon Sep 17 00:00:00 2001 From: Shawn Fang <45607042+mssfang@users.noreply.github.com> Date: Mon, 11 Mar 2019 10:21:35 -0700 Subject: [PATCH 18/42] Digest Support: init first connection with null headers (#431) Related to https://github.com/Azure/qpid-proton-j-extensions/pull/10 --- .../impl/WebSocketProxyConnectionHandler.java | 35 +------------------ 1 file changed, 1 insertion(+), 34 deletions(-) diff --git a/azure-eventhubs/src/main/java/com/microsoft/azure/eventhubs/impl/WebSocketProxyConnectionHandler.java b/azure-eventhubs/src/main/java/com/microsoft/azure/eventhubs/impl/WebSocketProxyConnectionHandler.java index 81220c33868f..e6ebc67585f8 100644 --- a/azure-eventhubs/src/main/java/com/microsoft/azure/eventhubs/impl/WebSocketProxyConnectionHandler.java +++ b/azure-eventhubs/src/main/java/com/microsoft/azure/eventhubs/impl/WebSocketProxyConnectionHandler.java @@ -58,8 +58,7 @@ protected void addTransportLayers(final Event event, final TransportInternal tra // after creating the socket to proxy final String hostName = event.getConnection().getHostname(); final ProxyHandler proxyHandler = new ProxyHandlerImpl(); - final Map proxyHeader = getAuthorizationHeader(); - proxy.configure(hostName, proxyHeader, proxyHandler, transport); + proxy.configure(hostName, null, proxyHandler, transport); transport.addTransportLayer(proxy); @@ -119,38 +118,6 @@ public int getRemotePort() { return socketAddress.getPort(); } - private Map getAuthorizationHeader() { - final PasswordAuthentication authentication = Authenticator.requestPasswordAuthentication( - getRemoteHostName(), - null, - getRemotePort(), - "https", - "Event Hubs client websocket proxy support", - "basic", - null, - Authenticator.RequestorType.PROXY); - if (authentication == null) { - return null; - } - - final String proxyUserName = authentication.getUserName(); - final String proxyPassword = authentication.getPassword() != null - ? new String(authentication.getPassword()) - : null; - if (StringUtil.isNullOrEmpty(proxyUserName) - || StringUtil.isNullOrEmpty(proxyPassword)) { - return null; - } - - final HashMap proxyAuthorizationHeader = new HashMap<>(); - // https://tools.ietf.org/html/rfc7617 - final String usernamePasswordPair = proxyUserName + ":" + proxyPassword; - proxyAuthorizationHeader.put( - "Proxy-Authorization", - "Basic " + Base64.getEncoder().encodeToString(usernamePasswordPair.getBytes())); - return proxyAuthorizationHeader; - } - private InetSocketAddress getProxyAddress() { final URI serviceUri = createURIFromHostNamePort( this.getAmqpConnection().getHostName(), From f4827abd0c252779b19a53ec4d5ba85a5c0e33fd Mon Sep 17 00:00:00 2001 From: JamesBirdsall Date: Tue, 12 Mar 2019 11:10:49 -0700 Subject: [PATCH 19/42] Fix lease scanner issues when Storage unreachable (#434) This fix is for issue #432. There are two parts: AzureStorageCheckpointLeaseManager performs certain Storage actions within a forEach. If those actions fail, the StorageException gets wrapped in a NoSuchElementException. Catch those and strip off the NoSuchElementException, then handle the StorageException in the existing way. The unexpected NoSuchElementExceptions were not being caught anywhere and the scanner thread was dying without rescheduling itself. Added code in PartitionMananger.scan to catch any exceptions that leak out of PartitionScanner and reschedule the scanner unless the host instance is shutting down. --- .../AzureStorageCheckpointLeaseManager.java | 13 +++- .../eventprocessorhost/PartitionManager.java | 61 +++++++++++-------- 2 files changed, 46 insertions(+), 28 deletions(-) diff --git a/azure-eventhubs-eph/src/main/java/com/microsoft/azure/eventprocessorhost/AzureStorageCheckpointLeaseManager.java b/azure-eventhubs-eph/src/main/java/com/microsoft/azure/eventprocessorhost/AzureStorageCheckpointLeaseManager.java index 65020d91a7f4..29907f03556a 100644 --- a/azure-eventhubs-eph/src/main/java/com/microsoft/azure/eventprocessorhost/AzureStorageCheckpointLeaseManager.java +++ b/azure-eventhubs-eph/src/main/java/com/microsoft/azure/eventprocessorhost/AzureStorageCheckpointLeaseManager.java @@ -22,6 +22,7 @@ import java.util.Hashtable; import java.util.Iterator; import java.util.List; +import java.util.NoSuchElementException; import java.util.concurrent.*; import java.util.regex.Matcher; import java.util.regex.Pattern; @@ -317,10 +318,16 @@ public CompletableFuture> getAllLeases() { (bp.getLeaseState() == LeaseState.LEASED))); }); future = CompletableFuture.completedFuture(infos); - } catch (URISyntaxException | StorageException e) { - TRACE_LOGGER.warn(this.hostContext.withHost("Failure while getting lease state details"), e); + } catch (Exception e) { + Throwable effective = e; + if (e instanceof NoSuchElementException) { + // If there is a StorageException in the forEach, it arrives wrapped in a NoSuchElementException. + // Strip the misleading NoSuchElementException to provide a meaningful error for the user. + effective = e.getCause(); + } + TRACE_LOGGER.warn(this.hostContext.withHost("Failure while getting lease state details"), effective); future = new CompletableFuture>(); - future.completeExceptionally(LoggingUtils.wrapException(e, EventProcessorHostActionStrings.GETTING_LEASE)); + future.completeExceptionally(LoggingUtils.wrapException(effective, EventProcessorHostActionStrings.GETTING_LEASE)); } return future; diff --git a/azure-eventhubs-eph/src/main/java/com/microsoft/azure/eventprocessorhost/PartitionManager.java b/azure-eventhubs-eph/src/main/java/com/microsoft/azure/eventprocessorhost/PartitionManager.java index 438d81f74cef..e02b0f2b4204 100644 --- a/azure-eventhubs-eph/src/main/java/com/microsoft/azure/eventprocessorhost/PartitionManager.java +++ b/azure-eventhubs-eph/src/main/java/com/microsoft/azure/eventprocessorhost/PartitionManager.java @@ -290,31 +290,42 @@ private Void scan(boolean isFirst) { TRACE_LOGGER.debug(this.hostContext.withHost("Starting lease scan")); long start = System.currentTimeMillis(); - (new PartitionScanner(this.hostContext, (lease) -> this.pumpManager.addPump(lease), this)).scan(isFirst) - .whenCompleteAsync((didSteal, e) -> - { - TRACE_LOGGER.debug(this.hostContext.withHost("Scanning took " + (System.currentTimeMillis() - start))); - if ((e != null) && !(e instanceof ClosingException)) { - TRACE_LOGGER.warn(this.hostContext.withHost("Lease scanner got exception"), e); - } - - onPartitionCheckCompleteTestHook(); - - // Schedule the next scan unless we are shutting down. - if (!this.getIsClosingOrClosed()) { - int seconds = didSteal ? this.hostContext.getPartitionManagerOptions().getFastScanIntervalInSeconds() : - this.hostContext.getPartitionManagerOptions().getSlowScanIntervalInSeconds(); - if (isFirst) { - seconds = this.hostContext.getPartitionManagerOptions().getStartupScanDelayInSeconds(); - } - synchronized (this.scanFutureSynchronizer) { - this.scanFuture = this.hostContext.getExecutor().schedule(() -> scan(false), seconds, TimeUnit.SECONDS); - } - TRACE_LOGGER.debug(this.hostContext.withHost("Scheduling lease scanner in " + seconds)); - } else { - TRACE_LOGGER.warn(this.hostContext.withHost("Not scheduling lease scanner due to shutdown")); - } - }, this.hostContext.getExecutor()); + try { + (new PartitionScanner(this.hostContext, (lease) -> this.pumpManager.addPump(lease), this)).scan(isFirst) + .whenCompleteAsync((didSteal, e) -> + { + TRACE_LOGGER.debug(this.hostContext.withHost("Scanning took " + (System.currentTimeMillis() - start))); + if ((e != null) && !(e instanceof ClosingException)) { + TRACE_LOGGER.warn(this.hostContext.withHost("Lease scanner got exception"), e); + } + + onPartitionCheckCompleteTestHook(); + + // Schedule the next scan unless we are shutting down. + if (!this.getIsClosingOrClosed()) { + int seconds = didSteal ? this.hostContext.getPartitionManagerOptions().getFastScanIntervalInSeconds() : + this.hostContext.getPartitionManagerOptions().getSlowScanIntervalInSeconds(); + if (isFirst) { + seconds = this.hostContext.getPartitionManagerOptions().getStartupScanDelayInSeconds(); + } + synchronized (this.scanFutureSynchronizer) { + this.scanFuture = this.hostContext.getExecutor().schedule(() -> scan(false), seconds, TimeUnit.SECONDS); + } + TRACE_LOGGER.debug(this.hostContext.withHost("Scheduling lease scanner in " + seconds)); + } else { + TRACE_LOGGER.warn(this.hostContext.withHost("Not scheduling lease scanner due to shutdown")); + } + }, this.hostContext.getExecutor()); + } catch (Exception e) { + TRACE_LOGGER.error(this.hostContext.withHost("Lease scanner threw directly"), e); + if (!this.getIsClosingOrClosed()) { + int seconds = this.hostContext.getPartitionManagerOptions().getSlowScanIntervalInSeconds(); + synchronized (this.scanFutureSynchronizer) { + this.scanFuture = this.hostContext.getExecutor().schedule(() -> scan(false), seconds, TimeUnit.SECONDS); + } + TRACE_LOGGER.debug(this.hostContext.withHost("Forced schedule of lease scanner in " + seconds)); + } + } return null; } From 50f99ca74ed1ea40875cc60d555ef635e2dde0b3 Mon Sep 17 00:00:00 2001 From: SJ Date: Thu, 4 Apr 2019 09:32:34 -0700 Subject: [PATCH 20/42] message receiver - fix null pointer error and ensure that receive link is recreated upon a failure (#439) * message receiver/sender - fix null pointer error and ensure that receive/send link is recreated on a failure. --- .../azure/eventhubs/impl/MessageReceiver.java | 26 +++++++++++-------- .../azure/eventhubs/impl/MessageSender.java | 26 +++++++++++-------- 2 files changed, 30 insertions(+), 22 deletions(-) diff --git a/azure-eventhubs/src/main/java/com/microsoft/azure/eventhubs/impl/MessageReceiver.java b/azure-eventhubs/src/main/java/com/microsoft/azure/eventhubs/impl/MessageReceiver.java index c44c81da6b28..0a561d9c48e0 100644 --- a/azure-eventhubs/src/main/java/com/microsoft/azure/eventhubs/impl/MessageReceiver.java +++ b/azure-eventhubs/src/main/java/com/microsoft/azure/eventhubs/impl/MessageReceiver.java @@ -118,7 +118,7 @@ public void run() { "clientId[%s], path[%s], linkName[%s] - Reschedule operation timer, current: [%s], remaining: [%s] secs", getClientId(), receivePath, - receiveLink.getName(), + getReceiveLinkName(), Instant.now(), timeoutTracker.remaining().getSeconds())); } @@ -154,7 +154,7 @@ public void onComplete(Void result) { TRACE_LOGGER.debug( String.format(Locale.US, "clientId[%s], path[%s], linkName[%s] - token renewed", - getClientId(), receivePath, receiveLink.getName())); + getClientId(), receivePath, getReceiveLinkName())); } } @@ -164,7 +164,7 @@ public void onError(Exception error) { TRACE_LOGGER.info( String.format(Locale.US, "clientId[%s], path[%s], linkName[%s], tokenRenewalFailure[%s]", - getClientId(), receivePath, receiveLink.getName(), error.getMessage())); + getClientId(), receivePath, getReceiveLinkName(), error.getMessage())); } } }); @@ -173,7 +173,7 @@ public void onError(Exception error) { TRACE_LOGGER.info( String.format(Locale.US, "clientId[%s], path[%s], linkName[%s], tokenRenewalScheduleFailure[%s]", - getClientId(), receivePath, receiveLink.getName(), exception.getMessage())); + getClientId(), receivePath, getReceiveLinkName(), exception.getMessage())); } } } @@ -236,6 +236,10 @@ private List receiveCore(final int messageCount) { return returnMessages; } + private String getReceiveLinkName() { + return this.receiveLink == null ? "null" : this.receiveLink.getName(); + } + public Duration getReceiveTimeout() { return this.receiveTimeout; } @@ -263,7 +267,7 @@ public CompletableFuture> receive(final int maxMessageCount) "clientId[%s], path[%s], linkName[%s] - schedule operation timer, current: [%s], remaining: [%s] secs", this.getClientId(), this.receivePath, - this.receiveLink.getName(), + this.getReceiveLinkName(), Instant.now(), this.receiveTimeout.getSeconds())); } @@ -308,7 +312,7 @@ public void onOpenComplete(Exception exception) { if (TRACE_LOGGER.isInfoEnabled()) { TRACE_LOGGER.info(String.format("onOpenComplete - clientId[%s], receiverPath[%s], linkName[%s], updated-link-credit[%s], sentCredits[%s]", - this.getClientId(), this.receivePath, this.receiveLink.getName(), this.receiveLink.getCredit(), this.prefetchCount)); + this.getClientId(), this.receivePath, this.getReceiveLinkName(), this.receiveLink.getCredit(), this.prefetchCount)); } } else { synchronized (this.errorConditionLock) { @@ -407,7 +411,7 @@ public void onError(final Exception exception) { String.format(Locale.US, "clientId[%s], receiverPath[%s], linkName[%s], onError: %s", this.getClientId(), this.receivePath, - this.receiveLink.getName(), + this.getReceiveLinkName(), completionException)); } @@ -425,7 +429,7 @@ public void onError(final Exception exception) { @Override public void onEvent() { if (!MessageReceiver.this.getIsClosingOrClosed() - && (receiveLink.getLocalState() == EndpointState.CLOSED || receiveLink.getRemoteState() == EndpointState.CLOSED)) { + && (receiveLink == null || receiveLink.getLocalState() == EndpointState.CLOSED || receiveLink.getRemoteState() == EndpointState.CLOSED)) { createReceiveLink(); underlyingFactory.getRetryPolicy().incrementRetryCount(getClientId()); } @@ -438,7 +442,7 @@ public void onEvent() { String.format(Locale.US, "clientId[%s], receiverPath[%s], linkName[%s], scheduling createLink encountered error: %s", this.getClientId(), this.receivePath, - this.receiveLink.getName(), ignore.getLocalizedMessage())); + this.getReceiveLinkName(), ignore.getLocalizedMessage())); } } } @@ -620,7 +624,7 @@ private void sendFlow(final int credits) { if (TRACE_LOGGER.isDebugEnabled()) { TRACE_LOGGER.debug(String.format("clientId[%s], receiverPath[%s], linkName[%s], updated-link-credit[%s], sentCredits[%s], ThreadId[%s]", - this.getClientId(), this.receivePath, this.receiveLink.getName(), this.receiveLink.getCredit(), tempFlow, Thread.currentThread().getId())); + this.getClientId(), this.receivePath, this.getReceiveLinkName(), this.receiveLink.getCredit(), tempFlow, Thread.currentThread().getId())); } } } @@ -825,7 +829,7 @@ public void onEvent() { receiveWork.onEvent(); if (!MessageReceiver.this.getIsClosingOrClosed() - && (receiveLink.getLocalState() == EndpointState.CLOSED || receiveLink.getRemoteState() == EndpointState.CLOSED)) { + && (receiveLink == null || receiveLink.getLocalState() == EndpointState.CLOSED || receiveLink.getRemoteState() == EndpointState.CLOSED)) { createReceiveLink(); } } diff --git a/azure-eventhubs/src/main/java/com/microsoft/azure/eventhubs/impl/MessageSender.java b/azure-eventhubs/src/main/java/com/microsoft/azure/eventhubs/impl/MessageSender.java index 5db1765d5668..c98c897c5da7 100644 --- a/azure-eventhubs/src/main/java/com/microsoft/azure/eventhubs/impl/MessageSender.java +++ b/azure-eventhubs/src/main/java/com/microsoft/azure/eventhubs/impl/MessageSender.java @@ -107,7 +107,7 @@ public void onComplete(Void result) { if (TRACE_LOGGER.isDebugEnabled()) { TRACE_LOGGER.debug(String.format(Locale.US, "clientId[%s], path[%s], linkName[%s] - token renewed", - getClientId(), sendPath, sendLink.getName())); + getClientId(), sendPath, getSendLinkName())); } } @@ -116,7 +116,7 @@ public void onError(Exception error) { if (TRACE_LOGGER.isInfoEnabled()) { TRACE_LOGGER.info(String.format(Locale.US, "clientId[%s], path[%s], linkName[%s] - tokenRenewalFailure[%s]", - getClientId(), sendPath, sendLink.getName(), error.getMessage())); + getClientId(), sendPath, getSendLinkName(), error.getMessage())); } } }); @@ -124,7 +124,7 @@ public void onError(Exception error) { if (TRACE_LOGGER.isWarnEnabled()) { TRACE_LOGGER.warn(String.format(Locale.US, "clientId[%s], path[%s], linkName[%s] - tokenRenewalScheduleFailure[%s]", - getClientId(), sendPath, sendLink.getName(), exception.getMessage())); + getClientId(), sendPath, getSendLinkName(), exception.getMessage())); } } } @@ -241,6 +241,10 @@ private CompletableFuture send( return this.sendCore(bytes, arrayOffset, messageFormat, onSend, tracker, null, null); } + private String getSendLinkName() { + return this.sendLink == null ? "null" : this.sendLink.getName(); + } + public CompletableFuture send(final Iterable messages) { if (messages == null || IteratorUtil.sizeEquals(messages, 0)) { throw new IllegalArgumentException(String.format(Locale.US, @@ -335,7 +339,7 @@ public void onOpenComplete(Exception completionException) { if (TRACE_LOGGER.isInfoEnabled()) { TRACE_LOGGER.info(String.format("onOpenComplete - clientId[%s], sendPath[%s], linkName[%s]", - this.getClientId(), this.sendPath, this.sendLink.getName())); + this.getClientId(), this.sendPath, this.getSendLinkName())); } if (!this.linkFirstOpen.isDone()) { @@ -471,7 +475,7 @@ public void onError(final Exception completionException) { @Override public void onEvent() { if (!MessageSender.this.getIsClosingOrClosed() - && (sendLink.getLocalState() == EndpointState.CLOSED || sendLink.getRemoteState() == EndpointState.CLOSED)) { + && (sendLink == null || sendLink.getLocalState() == EndpointState.CLOSED || sendLink.getRemoteState() == EndpointState.CLOSED)) { recreateSendLink(); } } @@ -506,7 +510,7 @@ public void onSendComplete(final Delivery delivery) { String.format( Locale.US, "clientId[%s], path[%s], linkName[%s], deliveryTag[%s]", - this.getClientId(), this.sendPath, this.sendLink.getName(), deliveryTag)); + this.getClientId(), this.sendPath, this.getSendLinkName(), deliveryTag)); final ReplayableWorkItem pendingSendWorkItem = this.pendingSendsData.remove(deliveryTag); @@ -574,7 +578,7 @@ public void onEvent() { if (TRACE_LOGGER.isDebugEnabled()) TRACE_LOGGER.debug( String.format(Locale.US, "clientId[%s]. path[%s], linkName[%s], delivery[%s] - mismatch (or send timed out)", - this.getClientId(), this.sendPath, this.sendLink.getName(), deliveryTag)); + this.getClientId(), this.sendPath, this.getSendLinkName(), deliveryTag)); } } @@ -773,7 +777,7 @@ public void onFlow(final int creditIssued) { int numberOfSendsWaitingforCredit = this.pendingSends.size(); TRACE_LOGGER.debug(String.format(Locale.US, "clientId[%s], path[%s], linkName[%s], remoteLinkCredit[%s], pendingSendsWaitingForCredit[%s], pendingSendsWaitingDelivery[%s]", - this.getClientId(), this.sendPath, this.sendLink.getName(), creditIssued, numberOfSendsWaitingforCredit, this.pendingSendsData.size() - numberOfSendsWaitingforCredit)); + this.getClientId(), this.sendPath, this.getSendLinkName(), creditIssued, numberOfSendsWaitingforCredit, this.pendingSendsData.size() - numberOfSendsWaitingforCredit)); } this.sendWork.onEvent(); @@ -786,7 +790,7 @@ private void recreateSendLink() { // actual send on the SenderLink should happen only in this method & should run on Reactor Thread private void processSendWork() { - if (this.sendLink.getLocalState() == EndpointState.CLOSED || this.sendLink.getRemoteState() == EndpointState.CLOSED) { + if (this.sendLink == null || this.sendLink.getLocalState() == EndpointState.CLOSED || this.sendLink.getRemoteState() == EndpointState.CLOSED) { if (!this.getIsClosingOrClosed()) this.recreateSendLink(); @@ -840,7 +844,7 @@ private void processSendWork() { if (TRACE_LOGGER.isDebugEnabled()) { TRACE_LOGGER.debug( String.format(Locale.US, "clientId[%s], path[%s], linkName[%s], deliveryTag[%s], sentMessageSize[%s], payloadActualSize[%s] - sendlink advance failed", - this.getClientId(), this.sendPath, this.sendLink.getName(), deliveryTag, sentMsgSize, sendData.getEncodedMessageSize())); + this.getClientId(), this.sendPath, this.getSendLinkName(), deliveryTag, sentMsgSize, sendData.getEncodedMessageSize())); } if (delivery != null) { @@ -858,7 +862,7 @@ private void processSendWork() { if (TRACE_LOGGER.isDebugEnabled()) { TRACE_LOGGER.debug( String.format(Locale.US, "clientId[%s], path[%s], linkName[%s], deliveryTag[%s] - sendData not found for this delivery.", - this.getClientId(), this.sendPath, this.sendLink.getName(), deliveryTag)); + this.getClientId(), this.sendPath, this.getSendLinkName(), deliveryTag)); } } From 325d4712e7291e1eca4d57e2fdaaedf577094074 Mon Sep 17 00:00:00 2001 From: JamesBirdsall Date: Thu, 4 Apr 2019 17:42:27 -0700 Subject: [PATCH 21/42] Update version numbers for release (#440) --- ConsumingEvents.md | 2 +- PublishingEvents.md | 2 +- azure-eventhubs-eph/pom.xml | 4 ++-- azure-eventhubs-extensions/pom.xml | 2 +- azure-eventhubs/pom.xml | 2 +- .../com/microsoft/azure/eventhubs/impl/ClientConstants.java | 2 +- pom.xml | 4 ++-- readme.md | 4 ++-- 8 files changed, 11 insertions(+), 11 deletions(-) diff --git a/ConsumingEvents.md b/ConsumingEvents.md index 3f890a4b49f5..b5ed7614294a 100644 --- a/ConsumingEvents.md +++ b/ConsumingEvents.md @@ -26,7 +26,7 @@ following dependency declaration inside of your Maven project file: com.microsoft.azure azure-eventhubs - 2.2.0 + 2.3.0 ``` diff --git a/PublishingEvents.md b/PublishingEvents.md index 67e26833eb6b..fd3b259142b0 100644 --- a/PublishingEvents.md +++ b/PublishingEvents.md @@ -12,7 +12,7 @@ following dependency declaration inside of your Maven project file: com.microsoft.azure azure-eventhubs - 2.2.0 + 2.3.0 ``` diff --git a/azure-eventhubs-eph/pom.xml b/azure-eventhubs-eph/pom.xml index 2e66fab09c92..5f57d60e6b81 100644 --- a/azure-eventhubs-eph/pom.xml +++ b/azure-eventhubs-eph/pom.xml @@ -4,10 +4,10 @@ com.microsoft.azure azure-eventhubs-clients - 2.2.0 + 2.3.0 - 2.4.0 + 2.5.0 4.0.0 diff --git a/azure-eventhubs-extensions/pom.xml b/azure-eventhubs-extensions/pom.xml index 7266898a4e9e..9dc8ad7645c3 100644 --- a/azure-eventhubs-extensions/pom.xml +++ b/azure-eventhubs-extensions/pom.xml @@ -7,7 +7,7 @@ com.microsoft.azure azure-eventhubs-clients - 2.2.0 + 2.3.0 4.0.0 diff --git a/azure-eventhubs/pom.xml b/azure-eventhubs/pom.xml index acb77607d50b..ce2d431da20a 100644 --- a/azure-eventhubs/pom.xml +++ b/azure-eventhubs/pom.xml @@ -4,7 +4,7 @@ com.microsoft.azure azure-eventhubs-clients - 2.2.0 + 2.3.0 4.0.0 diff --git a/azure-eventhubs/src/main/java/com/microsoft/azure/eventhubs/impl/ClientConstants.java b/azure-eventhubs/src/main/java/com/microsoft/azure/eventhubs/impl/ClientConstants.java index fa0803dff084..932e9a26b4a0 100644 --- a/azure-eventhubs/src/main/java/com/microsoft/azure/eventhubs/impl/ClientConstants.java +++ b/azure-eventhubs/src/main/java/com/microsoft/azure/eventhubs/impl/ClientConstants.java @@ -38,7 +38,7 @@ public final class ClientConstants { public final static String NO_RETRY = "NoRetry"; public final static String DEFAULT_RETRY = "Default"; public final static String PRODUCT_NAME = "MSJavaClient"; - public final static String CURRENT_JAVACLIENT_VERSION = "2.2.0"; + public final static String CURRENT_JAVACLIENT_VERSION = "2.3.0"; public static final String PLATFORM_INFO = getPlatformInfo(); public static final String FRAMEWORK_INFO = getFrameworkInfo(); public static final String CBS_ADDRESS = "$cbs"; diff --git a/pom.xml b/pom.xml index f4060015d16c..854f27481832 100644 --- a/pom.xml +++ b/pom.xml @@ -6,14 +6,14 @@ com.microsoft.azure azure-eventhubs-clients - 2.2.0 + 2.3.0 pom https://github.com/Azure/azure-event-hubs 0.31.0 - 1.1.0 + 1.2.0 4.12 1.8.0-alpha2 diff --git a/readme.md b/readme.md index aaa10caf557f..eee0a7be2b60 100644 --- a/readme.md +++ b/readme.md @@ -44,7 +44,7 @@ the required versions of Apache Qpid Proton-J, and the cryptography library BCPK com.microsoft.azure azure-eventhubs - 2.2.0 + 2.3.0 ``` @@ -61,7 +61,7 @@ It pulls the required versions of Event Hubs, Azure Storage and GSon libraries. com.microsoft.azure azure-eventhubs-eph - 2.4.0 + 2.5.0 ``` From b2d7507ff38dcf404d2650a209c0aa643a644ad2 Mon Sep 17 00:00:00 2001 From: SJ Date: Mon, 8 Apr 2019 18:00:39 -0700 Subject: [PATCH 22/42] Update prefetch count for a receiver (#441) --- .../java/com/microsoft/azure/eventhubs/PartitionReceiver.java | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/azure-eventhubs/src/main/java/com/microsoft/azure/eventhubs/PartitionReceiver.java b/azure-eventhubs/src/main/java/com/microsoft/azure/eventhubs/PartitionReceiver.java index 83912309702a..aa766d70e5e2 100644 --- a/azure-eventhubs/src/main/java/com/microsoft/azure/eventhubs/PartitionReceiver.java +++ b/azure-eventhubs/src/main/java/com/microsoft/azure/eventhubs/PartitionReceiver.java @@ -26,7 +26,7 @@ public interface PartitionReceiver { int MINIMUM_PREFETCH_COUNT = 1; int DEFAULT_PREFETCH_COUNT = 500; - int MAXIMUM_PREFETCH_COUNT = 2000; + int MAXIMUM_PREFETCH_COUNT = 8000; long NULL_EPOCH = 0; @@ -141,4 +141,4 @@ default Iterable receiveSync(final int maxEventCount) throws EventHub CompletableFuture close(); void closeSync() throws EventHubException; -} \ No newline at end of file +} From f5da49467dd1a48a97c57f4ef5b7f2bc46e42b91 Mon Sep 17 00:00:00 2001 From: SJ Date: Mon, 15 Apr 2019 15:41:20 -0700 Subject: [PATCH 23/42] Fix an issue of creating multiple sessions for $management & $cbs channel for a single connection and improve logging (#443) * Fix an issue of creating multiple sessions for $management & $cbs for a connection and improve logging --- .../EventProcessorHost.java | 3 +- .../eventhubs/ConnectionStringBuilder.java | 2 +- .../impl/ActiveClientTokenManager.java | 9 ++- .../azure/eventhubs/impl/BaseLinkHandler.java | 41 ++++++------- .../azure/eventhubs/impl/CBSChannel.java | 5 +- .../azure/eventhubs/impl/ClientConstants.java | 2 +- .../eventhubs/impl/ConnectionHandler.java | 61 ++++++++----------- .../azure/eventhubs/impl/CustomIOHandler.java | 10 ++- .../eventhubs/impl/EventDataBatchImpl.java | 3 +- .../azure/eventhubs/impl/EventDataUtil.java | 3 - .../eventhubs/impl/EventHubClientImpl.java | 9 +-- .../eventhubs/impl/EventPositionImpl.java | 3 +- .../eventhubs/impl/ManagementChannel.java | 11 ++-- .../azure/eventhubs/impl/MessageReceiver.java | 12 +++- .../azure/eventhubs/impl/MessageSender.java | 4 +- .../eventhubs/impl/MessagingFactory.java | 37 ++++++----- .../eventhubs/impl/PartitionReceiverImpl.java | 6 +- .../eventhubs/impl/PartitionSenderImpl.java | 5 +- .../azure/eventhubs/impl/ProtonUtil.java | 4 +- .../azure/eventhubs/impl/ReactorHandler.java | 14 +++-- .../eventhubs/impl/ReceiveLinkHandler.java | 32 +++++----- .../azure/eventhubs/impl/ReceivePump.java | 9 +-- .../impl/RequestResponseChannel.java | 4 +- .../eventhubs/impl/RequestResponseOpener.java | 40 +++++++++++- .../eventhubs/impl/SchedulerProvider.java | 4 ++ .../azure/eventhubs/impl/SendLinkHandler.java | 27 ++++---- .../azure/eventhubs/impl/SessionHandler.java | 51 ++++++++-------- .../azure/eventhubs/impl/StringUtil.java | 7 ++- .../azure/eventhubs/impl/TrackingUtil.java | 24 ++------ .../impl/WebSocketConnectionHandler.java | 4 +- .../SecurityExceptionsTest.java | 3 +- .../SendLargeMessageTest.java | 3 +- .../lib/FaultInjectingReactorFactory.java | 6 +- .../azure/eventhubs/lib/SasTokenTestBase.java | 3 +- .../sendrecv/ReceiveParallelManualTest.java | 5 +- .../azure/eventhubs/sendrecv/ReceiveTest.java | 3 +- .../azure/eventhubs/sendrecv/SendTest.java | 5 +- 37 files changed, 265 insertions(+), 209 deletions(-) diff --git a/azure-eventhubs-eph/src/main/java/com/microsoft/azure/eventprocessorhost/EventProcessorHost.java b/azure-eventhubs-eph/src/main/java/com/microsoft/azure/eventprocessorhost/EventProcessorHost.java index 86724933e0c9..ddec21127281 100644 --- a/azure-eventhubs-eph/src/main/java/com/microsoft/azure/eventprocessorhost/EventProcessorHost.java +++ b/azure-eventhubs-eph/src/main/java/com/microsoft/azure/eventprocessorhost/EventProcessorHost.java @@ -13,6 +13,7 @@ import java.net.URISyntaxException; import java.security.InvalidKeyException; +import java.util.Locale; import java.util.UUID; import java.util.concurrent.*; import java.util.concurrent.atomic.AtomicInteger; @@ -556,7 +557,7 @@ public Thread newThread(Runnable r) { } private String getNamePrefix() { - return String.format("[%s|%s|%s]-%s-", + return String.format(Locale.US, "[%s|%s|%s]-%s-", this.entityName, this.consumerGroupName, this.hostName, poolNumber.getAndIncrement()); } diff --git a/azure-eventhubs/src/main/java/com/microsoft/azure/eventhubs/ConnectionStringBuilder.java b/azure-eventhubs/src/main/java/com/microsoft/azure/eventhubs/ConnectionStringBuilder.java index cb05f5584daa..439484c3a269 100644 --- a/azure-eventhubs/src/main/java/com/microsoft/azure/eventhubs/ConnectionStringBuilder.java +++ b/azure-eventhubs/src/main/java/com/microsoft/azure/eventhubs/ConnectionStringBuilder.java @@ -407,7 +407,7 @@ private void parseConnectionString(final String connectionString) { this.transportType = TransportType.fromString(values[valueIndex]); } catch (IllegalArgumentException exception) { throw new IllegalConnectionStringFormatException( - String.format("Invalid value specified for property '%s' in the ConnectionString.", TransportTypeConfigName), + String.format(Locale.US, "Invalid value specified for property '%s' in the ConnectionString.", TransportTypeConfigName), exception); } } else { diff --git a/azure-eventhubs/src/main/java/com/microsoft/azure/eventhubs/impl/ActiveClientTokenManager.java b/azure-eventhubs/src/main/java/com/microsoft/azure/eventhubs/impl/ActiveClientTokenManager.java index c2c339e369f7..d7fbfe04c503 100644 --- a/azure-eventhubs/src/main/java/com/microsoft/azure/eventhubs/impl/ActiveClientTokenManager.java +++ b/azure-eventhubs/src/main/java/com/microsoft/azure/eventhubs/impl/ActiveClientTokenManager.java @@ -41,6 +41,10 @@ public ActiveClientTokenManager( } public void cancel() { + if (TRACE_LOGGER.isInfoEnabled()) { + TRACE_LOGGER.info(String.format(Locale.US, "clientEntity[%s] - canceling ActiveClientLinkManager", + clientEntity.getClientId())); + } synchronized (this.timerLock) { this.timer.cancel(false); @@ -62,9 +66,8 @@ public void run() { } else { if (TRACE_LOGGER.isInfoEnabled()) { - TRACE_LOGGER.info( - String.format(Locale.US, - "clientEntity[%s] - closing ActiveClientLinkManager", clientEntity.getClientId())); + TRACE_LOGGER.info(String.format(Locale.US, "clientEntity[%s] - closing ActiveClientLinkManager", + clientEntity.getClientId())); } } } diff --git a/azure-eventhubs/src/main/java/com/microsoft/azure/eventhubs/impl/BaseLinkHandler.java b/azure-eventhubs/src/main/java/com/microsoft/azure/eventhubs/impl/BaseLinkHandler.java index 5ab442a19cf1..ca10a9655e40 100644 --- a/azure-eventhubs/src/main/java/com/microsoft/azure/eventhubs/impl/BaseLinkHandler.java +++ b/azure-eventhubs/src/main/java/com/microsoft/azure/eventhubs/impl/BaseLinkHandler.java @@ -9,12 +9,16 @@ import org.slf4j.Logger; import org.slf4j.LoggerFactory; +import java.util.Locale; + public class BaseLinkHandler extends BaseHandler { protected static final Logger TRACE_LOGGER = LoggerFactory.getLogger(BaseLinkHandler.class); + private final String name; private final AmqpLink underlyingEntity; - public BaseLinkHandler(final AmqpLink amqpLink) { + public BaseLinkHandler(final AmqpLink amqpLink, final String name) { + this.name = name; this.underlyingEntity = amqpLink; } @@ -24,10 +28,8 @@ public void onLinkLocalClose(Event event) { final ErrorCondition condition = link.getCondition(); if (TRACE_LOGGER.isInfoEnabled()) { - TRACE_LOGGER.info(String.format("onLinkLocalClose linkName[%s], errorCondition[%s], errorDescription[%s]", - link.getName(), - condition != null ? condition.getCondition() : "n/a", - condition != null ? condition.getDescription() : "n/a")); + TRACE_LOGGER.info(String.format(Locale.US, "onLinkLocalClose clientName[%s], linkName[%s], errorCondition[%s], errorDescription[%s]", + this.name, link.getName(), condition != null ? condition.getCondition() : "n/a", condition != null ? condition.getDescription() : "n/a")); } closeSession(link, link.getCondition()); @@ -39,10 +41,8 @@ public void onLinkRemoteClose(Event event) { final ErrorCondition condition = link.getRemoteCondition(); if (TRACE_LOGGER.isInfoEnabled()) { - TRACE_LOGGER.info(String.format("onLinkRemoteClose linkName[%s], errorCondition[%s], errorDescription[%s]", - link.getName(), - condition != null ? condition.getCondition() : "n/a", - condition != null ? condition.getDescription() : "n/a")); + TRACE_LOGGER.info(String.format(Locale.US, "onLinkRemoteClose clientName[%s], linkName[%s], errorCondition[%s], errorDescription[%s]", + this.name, link.getName(), condition != null ? condition.getCondition() : "n/a", condition != null ? condition.getDescription() : "n/a")); } handleRemoteLinkClosed(event); @@ -54,10 +54,8 @@ public void onLinkRemoteDetach(Event event) { final ErrorCondition condition = link.getCondition(); if (TRACE_LOGGER.isInfoEnabled()) { - TRACE_LOGGER.info(String.format("onLinkRemoteDetach linkName[%s], errorCondition[%s], errorDescription[%s]", - link.getName(), - condition != null ? condition.getCondition() : "n/a", - condition != null ? condition.getDescription() : "n/a")); + TRACE_LOGGER.info(String.format(Locale.US, "onLinkRemoteDetach clientName[%s], linkName[%s], errorCondition[%s], errorDescription[%s]", + this.name, link.getName(), condition != null ? condition.getCondition() : "n/a", condition != null ? condition.getDescription() : "n/a")); } handleRemoteLinkClosed(event); @@ -65,10 +63,8 @@ public void onLinkRemoteDetach(Event event) { public void processOnClose(Link link, ErrorCondition condition) { if (TRACE_LOGGER.isInfoEnabled()) { - TRACE_LOGGER.info(String.format("processOnClose linkName[%s], errorCondition[%s], errorDescription[%s]", - link.getName(), - condition != null ? condition.getCondition() : "n/a", - condition != null ? condition.getDescription() : "n/a")); + TRACE_LOGGER.info(String.format(Locale.US, "processOnClose clientName[%s], linkName[%s], errorCondition[%s], errorDescription[%s]", + this.name, link.getName(), condition != null ? condition.getCondition() : "n/a", condition != null ? condition.getDescription() : "n/a")); } this.underlyingEntity.onClose(condition); @@ -76,9 +72,8 @@ public void processOnClose(Link link, ErrorCondition condition) { public void processOnClose(Link link, Exception exception) { if (TRACE_LOGGER.isInfoEnabled()) { - TRACE_LOGGER.info(String.format("processOnClose linkName[%s], exception[%s]", - link.getName(), - exception != null ? exception.getMessage() : "n/a")); + TRACE_LOGGER.info(String.format(Locale.US, "processOnClose clientName[%s], linkName[%s], exception[%s]", + this.name, link.getName(), exception != null ? exception.getMessage() : "n/a")); } this.underlyingEntity.onError(exception); @@ -89,10 +84,8 @@ private void closeSession(Link link, ErrorCondition condition) { if (session != null && session.getLocalState() != EndpointState.CLOSED) { if (TRACE_LOGGER.isInfoEnabled()) { - TRACE_LOGGER.info(String.format("closeSession for linkName[%s], errorCondition[%s], errorDescription[%s]", - link.getName(), - condition != null ? condition.getCondition() : "n/a", - condition != null ? condition.getDescription() : "n/a")); + TRACE_LOGGER.info(String.format(Locale.US, "closeSession for clientName[%s], linkName[%s], errorCondition[%s], errorDescription[%s]", + this.name, link.getName(), condition != null ? condition.getCondition() : "n/a", condition != null ? condition.getDescription() : "n/a")); } session.setCondition(condition); diff --git a/azure-eventhubs/src/main/java/com/microsoft/azure/eventhubs/impl/CBSChannel.java b/azure-eventhubs/src/main/java/com/microsoft/azure/eventhubs/impl/CBSChannel.java index cbc0aa56378f..2a89853b7a27 100644 --- a/azure-eventhubs/src/main/java/com/microsoft/azure/eventhubs/impl/CBSChannel.java +++ b/azure-eventhubs/src/main/java/com/microsoft/azure/eventhubs/impl/CBSChannel.java @@ -20,14 +20,15 @@ final class CBSChannel { public CBSChannel( final SessionProvider sessionProvider, - final AmqpConnection connection) { + final AmqpConnection connection, + final String clientId) { this.sessionProvider = sessionProvider; this.connectionEventDispatcher = connection; RequestResponseCloser closer = new RequestResponseCloser(); this.innerChannel = new FaultTolerantObject<>( - new RequestResponseOpener(sessionProvider, "cbs-session", "cbs", ClientConstants.CBS_ADDRESS, connection), + new RequestResponseOpener(sessionProvider, clientId, "cbs-session", "cbs", ClientConstants.CBS_ADDRESS, connection), closer); closer.setInnerChannel(this.innerChannel); } diff --git a/azure-eventhubs/src/main/java/com/microsoft/azure/eventhubs/impl/ClientConstants.java b/azure-eventhubs/src/main/java/com/microsoft/azure/eventhubs/impl/ClientConstants.java index 932e9a26b4a0..b72092b17073 100644 --- a/azure-eventhubs/src/main/java/com/microsoft/azure/eventhubs/impl/ClientConstants.java +++ b/azure-eventhubs/src/main/java/com/microsoft/azure/eventhubs/impl/ClientConstants.java @@ -28,7 +28,7 @@ public final class ClientConstants { public final static Duration TIMER_TOLERANCE = Duration.ofSeconds(1); public final static Duration DEFAULT_RETRY_MIN_BACKOFF = Duration.ofSeconds(0); public final static Duration DEFAULT_RETRY_MAX_BACKOFF = Duration.ofSeconds(30); - public final static Duration TOKEN_REFRESH_INTERVAL = Duration.ofMinutes(10); // renew every 10 mins, which expires 20 mins + public final static Duration TOKEN_REFRESH_INTERVAL = Duration.ofMinutes(5); // renew every 5 minutes, which expires 20 minutes public final static Duration TOKEN_VALIDITY = Duration.ofMinutes(20); public final static int DEFAULT_MAX_RETRY_COUNT = 10; public final static boolean DEFAULT_IS_TRANSIENT = true; diff --git a/azure-eventhubs/src/main/java/com/microsoft/azure/eventhubs/impl/ConnectionHandler.java b/azure-eventhubs/src/main/java/com/microsoft/azure/eventhubs/impl/ConnectionHandler.java index 1e13d52c6a65..c9280f4bc003 100644 --- a/azure-eventhubs/src/main/java/com/microsoft/azure/eventhubs/impl/ConnectionHandler.java +++ b/azure-eventhubs/src/main/java/com/microsoft/azure/eventhubs/impl/ConnectionHandler.java @@ -18,21 +18,21 @@ import java.util.Locale; import java.util.Map; -// ServiceBus <-> ProtonReactor interaction handles all -// amqp_connection/transport related events from reactor public class ConnectionHandler extends BaseHandler { private static final Logger TRACE_LOGGER = LoggerFactory.getLogger(ConnectionHandler.class); private final AmqpConnection amqpConnection; + private final String connectionId; - protected ConnectionHandler(final AmqpConnection amqpConnection) { + protected ConnectionHandler(final AmqpConnection amqpConnection, final String connectionId) { add(new Handshaker()); this.amqpConnection = amqpConnection; + this.connectionId = connectionId; } - static ConnectionHandler create(TransportType transportType, AmqpConnection amqpConnection) { + static ConnectionHandler create(TransportType transportType, AmqpConnection amqpConnection, String connectionId) { switch (transportType) { case AMQP_WEB_SOCKETS: if (WebSocketProxyConnectionHandler.shouldUseProxy(amqpConnection.getHostName())) { @@ -42,7 +42,7 @@ static ConnectionHandler create(TransportType transportType, AmqpConnection amqp } case AMQP: default: - return new ConnectionHandler(amqpConnection); + return new ConnectionHandler(amqpConnection, connectionId); } } @@ -63,17 +63,18 @@ protected AmqpConnection getAmqpConnection() { @Override public void onConnectionInit(Event event) { if (TRACE_LOGGER.isInfoEnabled()) { - TRACE_LOGGER.info(String.format(Locale.US, "onConnectionInit hostname[%s]", this.amqpConnection.getHostName())); + TRACE_LOGGER.info(String.format(Locale.US, "onConnectionInit hostname[%s], connectionId[%s]", + this.amqpConnection.getHostName(), this.connectionId)); } final Connection connection = event.getConnection(); final String hostName = new StringBuilder(this.amqpConnection.getHostName()) .append(":") - .append(String.valueOf(this.getProtocolPort())) + .append(this.getProtocolPort()) .toString(); connection.setHostname(hostName); - connection.setContainer(StringUtil.getRandomString()); + connection.setContainer(this.connectionId); final Map connectionProperties = new HashMap<>(); connectionProperties.put(AmqpConstants.PRODUCT, ClientConstants.PRODUCT_NAME); @@ -137,7 +138,8 @@ protected int getMaxFrameSize() { @Override public void onConnectionBound(Event event) { if (TRACE_LOGGER.isInfoEnabled()) { - TRACE_LOGGER.info(String.format(Locale.US, "onConnectionBound hostname[%s]", this.amqpConnection.getHostName())); + TRACE_LOGGER.info(String.format(Locale.US, "onConnectionBound hostname[%s], connectionId[%s]", + this.amqpConnection.getHostName(), this.connectionId)); } final Transport transport = event.getTransport(); @@ -150,8 +152,8 @@ public void onConnectionUnbound(Event event) { final Connection connection = event.getConnection(); if (TRACE_LOGGER.isInfoEnabled()) { - TRACE_LOGGER.info(String.format(Locale.US, "onConnectionUnbound: hostname[%s], state[%s], remoteState[%s]", - connection.getHostname(), connection.getLocalState(), connection.getRemoteState())); + TRACE_LOGGER.info(String.format(Locale.US, "onConnectionUnbound hostname[%s], connectionId[%s], state[%s], remoteState[%s]", + connection.getHostname(), this.connectionId, connection.getLocalState(), connection.getRemoteState())); } // if failure happened while establishing transport - nothing to free up. @@ -167,9 +169,8 @@ public void onTransportError(Event event) { final ErrorCondition condition = transport.getCondition(); if (TRACE_LOGGER.isWarnEnabled()) { - TRACE_LOGGER.warn(String.format(Locale.US, "onTransportError: hostname[%s], error[%s]", - connection != null ? connection.getHostname() : "n/a", - condition != null ? condition.getDescription() : "n/a")); + TRACE_LOGGER.warn(String.format(Locale.US, "onTransportError hostname[%s], connectionId[%s], error[%s]", + connection != null ? connection.getHostname() : "n/a", this.connectionId, condition != null ? condition.getDescription() : "n/a")); } if (connection != null && connection.getRemoteState() != EndpointState.CLOSED) { @@ -192,8 +193,8 @@ public void onTransportClosed(Event event) { final ErrorCondition condition = transport.getCondition(); if (TRACE_LOGGER.isInfoEnabled()) { - TRACE_LOGGER.info(String.format(Locale.US, "onTransportClosed: hostname[%s], error[%s]", - connection != null ? connection.getHostname() : "n/a", (condition != null ? condition.getDescription() : "n/a"))); + TRACE_LOGGER.info(String.format(Locale.US, "onTransportClosed hostname[%s], connectionId[%s], error[%s]", + connection != null ? connection.getHostname() : "n/a", this.connectionId, (condition != null ? condition.getDescription() : "n/a"))); } if (connection != null && connection.getRemoteState() != EndpointState.CLOSED) { @@ -209,10 +210,8 @@ public void onConnectionLocalOpen(Event event) { final ErrorCondition error = connection.getCondition(); if (TRACE_LOGGER.isInfoEnabled()) { - TRACE_LOGGER.info(String.format(Locale.US, "onConnectionLocalOpen: hostname[%s], errorCondition[%s], errorDescription[%s]", - connection.getHostname(), - error != null ? error.getCondition() : "n/a", - error != null ? error.getDescription() : "n/a")); + TRACE_LOGGER.info(String.format(Locale.US, "onConnectionLocalOpen hostname[%s], connectionId[%s], errorCondition[%s], errorDescription[%s]", + connection.getHostname(), this.connectionId, error != null ? error.getCondition() : "n/a", error != null ? error.getDescription() : "n/a")); } } @@ -220,8 +219,8 @@ public void onConnectionLocalOpen(Event event) { public void onConnectionRemoteOpen(Event event) { if (TRACE_LOGGER.isInfoEnabled()) { - TRACE_LOGGER.info(String.format(Locale.US, "onConnectionRemoteOpen: hostname[%s], remoteContainer[%s]", - event.getConnection().getHostname(), event.getConnection().getRemoteContainer())); + TRACE_LOGGER.info(String.format(Locale.US, "onConnectionRemoteOpen hostname[%s], connectionId[%s], remoteContainer[%s]", + event.getConnection().getHostname(), this.connectionId, event.getConnection().getRemoteContainer())); } this.amqpConnection.onOpenComplete(null); @@ -234,10 +233,8 @@ public void onConnectionLocalClose(Event event) { final ErrorCondition error = connection.getCondition(); if (TRACE_LOGGER.isInfoEnabled()) { - TRACE_LOGGER.info(String.format(Locale.US, "onConnectionLocalClose: hostname[%s], errorCondition[%s], errorDescription[%s]", - connection.getHostname(), - error != null ? error.getCondition() : "n/a", - error != null ? error.getDescription() : "n/a")); + TRACE_LOGGER.info(String.format(Locale.US, "onConnectionLocalClose hostname[%s], connectionId[%s], errorCondition[%s], errorDescription[%s]", + connection.getHostname(), this.connectionId, error != null ? error.getCondition() : "n/a", error != null ? error.getDescription() : "n/a")); } if (connection.getRemoteState() == EndpointState.CLOSED) { @@ -256,10 +253,8 @@ public void onConnectionRemoteClose(Event event) { final ErrorCondition error = connection.getRemoteCondition(); if (TRACE_LOGGER.isInfoEnabled()) { - TRACE_LOGGER.info(String.format(Locale.US, "onConnectionRemoteClose: hostname[%s], errorCondition[%s], errorDescription[%s]", - connection.getHostname(), - error != null ? error.getCondition() : "n/a", - error != null ? error.getDescription() : "n/a")); + TRACE_LOGGER.info(String.format(Locale.US, "onConnectionRemoteClose hostname[%s], connectionId[%s], errorCondition[%s], errorDescription[%s]", + connection.getHostname(), this.connectionId, error != null ? error.getCondition() : "n/a", error != null ? error.getDescription() : "n/a")); } this.amqpConnection.onConnectionError(error); @@ -271,10 +266,8 @@ public void onConnectionFinal(Event event) { final ErrorCondition error = connection.getCondition(); if (TRACE_LOGGER.isInfoEnabled()) { - TRACE_LOGGER.info(String.format(Locale.US, "onConnectionFinal: hostname[%s], errorCondition[%s], errorDescription[%s]", - connection.getHostname(), - error != null ? error.getCondition() : "n/a", - error != null ? error.getDescription() : "n/a")); + TRACE_LOGGER.info(String.format(Locale.US, "onConnectionFinal hostname[%s], connectionId[%s], errorCondition[%s], errorDescription[%s]", + connection.getHostname(), this.connectionId, error != null ? error.getCondition() : "n/a", error != null ? error.getDescription() : "n/a")); } } } diff --git a/azure-eventhubs/src/main/java/com/microsoft/azure/eventhubs/impl/CustomIOHandler.java b/azure-eventhubs/src/main/java/com/microsoft/azure/eventhubs/impl/CustomIOHandler.java index c091c00be1fc..9a1359069cb3 100644 --- a/azure-eventhubs/src/main/java/com/microsoft/azure/eventhubs/impl/CustomIOHandler.java +++ b/azure-eventhubs/src/main/java/com/microsoft/azure/eventhubs/impl/CustomIOHandler.java @@ -13,14 +13,20 @@ public class CustomIOHandler extends IOHandler { private static final Logger TRACE_LOGGER = LoggerFactory.getLogger(CustomIOHandler.class); + private final String name; + + public CustomIOHandler(final String name) { + this.name = name; + } + @Override public void onTransportClosed(Event event) { final Transport transport = event.getTransport(); final Connection connection = event.getConnection(); if (TRACE_LOGGER.isInfoEnabled()) { - TRACE_LOGGER.info(String.format(Locale.US, "onTransportClosed hostname[%s]", - (connection != null ? connection.getHostname() : "n/a"))); + TRACE_LOGGER.info(String.format(Locale.US, "onTransportClosed name[%s], hostname[%s]", + this.name, (connection != null ? connection.getHostname() : "n/a"))); } if (transport != null && connection != null && connection.getTransport() != null) { diff --git a/azure-eventhubs/src/main/java/com/microsoft/azure/eventhubs/impl/EventDataBatchImpl.java b/azure-eventhubs/src/main/java/com/microsoft/azure/eventhubs/impl/EventDataBatchImpl.java index 1f138df8d414..167132cd0817 100644 --- a/azure-eventhubs/src/main/java/com/microsoft/azure/eventhubs/impl/EventDataBatchImpl.java +++ b/azure-eventhubs/src/main/java/com/microsoft/azure/eventhubs/impl/EventDataBatchImpl.java @@ -12,6 +12,7 @@ import java.util.Iterator; import java.util.LinkedList; import java.util.List; +import java.util.Locale; final class EventDataBatchImpl implements EventDataBatch { @@ -46,7 +47,7 @@ public final boolean tryAdd(final EventData eventData) throws PayloadSizeExceede try { size = getSize(eventDataImpl, events.isEmpty()); } catch (java.nio.BufferOverflowException exception) { - throw new PayloadSizeExceededException(String.format("Size of the payload exceeded Maximum message size: %s kb", this.maxMessageSize / 1024)); + throw new PayloadSizeExceededException(String.format(Locale.US, "Size of the payload exceeded Maximum message size: %s kb", this.maxMessageSize / 1024)); } if (this.currentSize + size > this.maxMessageSize) diff --git a/azure-eventhubs/src/main/java/com/microsoft/azure/eventhubs/impl/EventDataUtil.java b/azure-eventhubs/src/main/java/com/microsoft/azure/eventhubs/impl/EventDataUtil.java index 491ee6b6e60e..83fdac4b1c60 100644 --- a/azure-eventhubs/src/main/java/com/microsoft/azure/eventhubs/impl/EventDataUtil.java +++ b/azure-eventhubs/src/main/java/com/microsoft/azure/eventhubs/impl/EventDataUtil.java @@ -11,9 +11,6 @@ import java.util.*; import java.util.function.Consumer; -/* - * Internal utility class for EventData - */ final class EventDataUtil { @SuppressWarnings("serial") diff --git a/azure-eventhubs/src/main/java/com/microsoft/azure/eventhubs/impl/EventHubClientImpl.java b/azure-eventhubs/src/main/java/com/microsoft/azure/eventhubs/impl/EventHubClientImpl.java index 4dc5e927bb7d..3f08c7c2cf9d 100644 --- a/azure-eventhubs/src/main/java/com/microsoft/azure/eventhubs/impl/EventHubClientImpl.java +++ b/azure-eventhubs/src/main/java/com/microsoft/azure/eventhubs/impl/EventHubClientImpl.java @@ -38,7 +38,7 @@ public final class EventHubClientImpl extends ClientEntity implements EventHubCl private CompletableFuture createSender; private EventHubClientImpl(final ConnectionStringBuilder connectionString, final ScheduledExecutorService executor) { - super("EventHubClientImpl".concat(StringUtil.getRandomString()), null, executor); + super(StringUtil.getRandomString("EC"), null, executor); this.eventHubName = connectionString.getEventHubName(); this.senderCreateSync = new Object(); @@ -46,7 +46,7 @@ private EventHubClientImpl(final ConnectionStringBuilder connectionString, final public static CompletableFuture create( final String connectionString, final RetryPolicy retryPolicy, final ScheduledExecutorService executor) - throws EventHubException, IOException { + throws IOException { final ConnectionStringBuilder connStr = new ConnectionStringBuilder(connectionString); final EventHubClientImpl eventHubClient = new EventHubClientImpl(connStr, executor); @@ -220,7 +220,8 @@ private CompletableFuture createInternalSender() { if (!this.isSenderCreateStarted) { synchronized (this.senderCreateSync) { if (!this.isSenderCreateStarted) { - this.createSender = MessageSender.create(this.underlyingFactory, this.getClientId().concat("-InternalSender"), this.eventHubName) + String senderName = StringUtil.getRandomString("EC").concat(StringUtil.SEPARATOR + this.underlyingFactory.getClientId()).concat("-InternalSender"); + this.createSender = MessageSender.create(this.underlyingFactory, senderName, this.eventHubName) .thenAcceptAsync(new Consumer() { public void accept(MessageSender a) { EventHubClientImpl.this.sender = a; @@ -302,7 +303,7 @@ public CompletableFuture apply(Map private CompletableFuture addManagementToken(Map request) { CompletableFuture retval = null; try { - String audience = String.format("amqp://%s/%s", this.underlyingFactory.getHostName(), this.eventHubName); + String audience = String.format(Locale.US, "amqp://%s/%s", this.underlyingFactory.getHostName(), this.eventHubName); String token = this.underlyingFactory.getTokenProvider().getToken(audience, ClientConstants.TOKEN_REFRESH_INTERVAL); request.put(ClientConstants.MANAGEMENT_SECURITY_TOKEN_KEY, token); } catch (InvalidKeyException | NoSuchAlgorithmException | IOException e) { diff --git a/azure-eventhubs/src/main/java/com/microsoft/azure/eventhubs/impl/EventPositionImpl.java b/azure-eventhubs/src/main/java/com/microsoft/azure/eventhubs/impl/EventPositionImpl.java index 898975d5b0e2..844ed60f2a12 100644 --- a/azure-eventhubs/src/main/java/com/microsoft/azure/eventhubs/impl/EventPositionImpl.java +++ b/azure-eventhubs/src/main/java/com/microsoft/azure/eventhubs/impl/EventPositionImpl.java @@ -9,6 +9,7 @@ import org.slf4j.LoggerFactory; import java.time.Instant; +import java.util.Locale; public final class EventPositionImpl implements EventPosition { @@ -103,7 +104,7 @@ String getExpression() { @Override public String toString() { - return String.format("offset[%s], sequenceNumber[%s], enqueuedTime[%s], inclusiveFlag[%s]", + return String.format(Locale.US, "offset[%s], sequenceNumber[%s], enqueuedTime[%s], inclusiveFlag[%s]", this.offset, this.sequenceNumber, (this.dateTime != null) ? this.dateTime.toEpochMilli() : "null", this.inclusiveFlag); diff --git a/azure-eventhubs/src/main/java/com/microsoft/azure/eventhubs/impl/ManagementChannel.java b/azure-eventhubs/src/main/java/com/microsoft/azure/eventhubs/impl/ManagementChannel.java index 8941ddb01c54..56be7bbc704a 100644 --- a/azure-eventhubs/src/main/java/com/microsoft/azure/eventhubs/impl/ManagementChannel.java +++ b/azure-eventhubs/src/main/java/com/microsoft/azure/eventhubs/impl/ManagementChannel.java @@ -4,25 +4,25 @@ */ package com.microsoft.azure.eventhubs.impl; +import com.microsoft.azure.eventhubs.OperationCancelledException; +import com.microsoft.azure.eventhubs.TimeoutException; import org.apache.qpid.proton.Proton; import org.apache.qpid.proton.amqp.messaging.AmqpValue; import org.apache.qpid.proton.amqp.messaging.ApplicationProperties; import org.apache.qpid.proton.message.Message; import java.io.IOException; +import java.util.Locale; import java.util.Map; import java.util.concurrent.CompletableFuture; -import com.microsoft.azure.eventhubs.OperationCancelledException; -import com.microsoft.azure.eventhubs.TimeoutException; - final class ManagementChannel { final FaultTolerantObject innerChannel; final SessionProvider sessionProvider; final AmqpConnection connectionEventDispatcher; - public ManagementChannel(final SessionProvider sessionProvider, final AmqpConnection connection) { + public ManagementChannel(final SessionProvider sessionProvider, final AmqpConnection connection, final String clientId) { this.sessionProvider = sessionProvider; this.connectionEventDispatcher = connection; @@ -30,6 +30,7 @@ public ManagementChannel(final SessionProvider sessionProvider, final AmqpConnec this.innerChannel = new FaultTolerantObject<>( new RequestResponseOpener( sessionProvider, + clientId, "mgmt-session", "mgmt", ClientConstants.MANAGEMENT_ADDRESS, @@ -57,7 +58,7 @@ public void onEvent() { final String errorMessage; if (channel != null && channel.getState() == IOObject.IOObjectState.OPENED) { final String remoteContainerId = channel.getSendLink().getSession().getConnection().getRemoteContainer(); - errorMessage = String.format("Management request timed out (%sms), after not receiving response from service. TrackingId: %s", + errorMessage = String.format(Locale.US, "Management request timed out (%sms), after not receiving response from service. TrackingId: %s", timeoutInMillis, StringUtil.isNullOrEmpty(remoteContainerId) ? "n/a" : remoteContainerId); } else { errorMessage = "Management request timed out on the client - enable info level tracing to diagnose."; diff --git a/azure-eventhubs/src/main/java/com/microsoft/azure/eventhubs/impl/MessageReceiver.java b/azure-eventhubs/src/main/java/com/microsoft/azure/eventhubs/impl/MessageReceiver.java index 0a561d9c48e0..8a01b3834868 100644 --- a/azure-eventhubs/src/main/java/com/microsoft/azure/eventhubs/impl/MessageReceiver.java +++ b/azure-eventhubs/src/main/java/com/microsoft/azure/eventhubs/impl/MessageReceiver.java @@ -311,7 +311,7 @@ public void onOpenComplete(Exception exception) { this.sendFlow(this.prefetchCount - this.prefetchedMessages.size()); if (TRACE_LOGGER.isInfoEnabled()) { - TRACE_LOGGER.info(String.format("onOpenComplete - clientId[%s], receiverPath[%s], linkName[%s], updated-link-credit[%s], sentCredits[%s]", + TRACE_LOGGER.info(String.format(Locale.US, "onOpenComplete - clientId[%s], receiverPath[%s], linkName[%s], updated-link-credit[%s], sentCredits[%s]", this.getClientId(), this.receivePath, this.getReceiveLinkName(), this.receiveLink.getCredit(), this.prefetchCount)); } } else { @@ -506,6 +506,12 @@ private void createReceiveLink() { public void accept(Session session) { // if the MessageReceiver is closed - we no-longer need to create the link if (MessageReceiver.this.getIsClosingOrClosed()) { + if (TRACE_LOGGER.isInfoEnabled()) { + TRACE_LOGGER.info( + String.format(Locale.US, + "clientId[%s], path[%s], canceling the job of creating a receive link because the receiver was closed", + getClientId(), receivePath)); + } session.close(); return; @@ -537,7 +543,7 @@ public void accept(Session session) { if (desiredCapabilities != null) receiver.setDesiredCapabilities(desiredCapabilities); - final ReceiveLinkHandler handler = new ReceiveLinkHandler(MessageReceiver.this); + final ReceiveLinkHandler handler = new ReceiveLinkHandler(MessageReceiver.this, MessageReceiver.this.getClientId()); BaseHandler.setHandler(receiver, handler); if (MessageReceiver.this.receiveLink != null) { @@ -623,7 +629,7 @@ private void sendFlow(final int credits) { this.nextCreditToFlow = 0; if (TRACE_LOGGER.isDebugEnabled()) { - TRACE_LOGGER.debug(String.format("clientId[%s], receiverPath[%s], linkName[%s], updated-link-credit[%s], sentCredits[%s], ThreadId[%s]", + TRACE_LOGGER.debug(String.format(Locale.US, "clientId[%s], receiverPath[%s], linkName[%s], updated-link-credit[%s], sentCredits[%s], ThreadId[%s]", this.getClientId(), this.receivePath, this.getReceiveLinkName(), this.receiveLink.getCredit(), tempFlow, Thread.currentThread().getId())); } } diff --git a/azure-eventhubs/src/main/java/com/microsoft/azure/eventhubs/impl/MessageSender.java b/azure-eventhubs/src/main/java/com/microsoft/azure/eventhubs/impl/MessageSender.java index c98c897c5da7..a4d6485ce0f0 100644 --- a/azure-eventhubs/src/main/java/com/microsoft/azure/eventhubs/impl/MessageSender.java +++ b/azure-eventhubs/src/main/java/com/microsoft/azure/eventhubs/impl/MessageSender.java @@ -338,7 +338,7 @@ public void onOpenComplete(Exception completionException) { this.cancelOpenTimer(); if (TRACE_LOGGER.isInfoEnabled()) { - TRACE_LOGGER.info(String.format("onOpenComplete - clientId[%s], sendPath[%s], linkName[%s]", + TRACE_LOGGER.info(String.format(Locale.US, "onOpenComplete - clientId[%s], sendPath[%s], linkName[%s]", this.getClientId(), this.sendPath, this.getSendLinkName())); } @@ -635,7 +635,7 @@ public void accept(Session session) { sender.setSenderSettleMode(SenderSettleMode.UNSETTLED); - final SendLinkHandler handler = new SendLinkHandler(MessageSender.this); + final SendLinkHandler handler = new SendLinkHandler(MessageSender.this, MessageSender.this.getClientId()); BaseHandler.setHandler(sender, handler); if (MessageSender.this.sendLink != null) { diff --git a/azure-eventhubs/src/main/java/com/microsoft/azure/eventhubs/impl/MessagingFactory.java b/azure-eventhubs/src/main/java/com/microsoft/azure/eventhubs/impl/MessagingFactory.java index a87802275945..51d07eefadf5 100644 --- a/azure-eventhubs/src/main/java/com/microsoft/azure/eventhubs/impl/MessagingFactory.java +++ b/azure-eventhubs/src/main/java/com/microsoft/azure/eventhubs/impl/MessagingFactory.java @@ -5,8 +5,8 @@ package com.microsoft.azure.eventhubs.impl; -import com.microsoft.azure.eventhubs.*; import com.microsoft.azure.eventhubs.TimeoutException; +import com.microsoft.azure.eventhubs.*; import org.apache.qpid.proton.amqp.Symbol; import org.apache.qpid.proton.amqp.transport.ErrorCondition; import org.apache.qpid.proton.engine.*; @@ -59,7 +59,7 @@ public final class MessagingFactory extends ClientEntity implements AmqpConnecti final RetryPolicy retryPolicy, final ScheduledExecutorService executor, final ReactorFactory reactorFactory) { - super("MessagingFactory".concat(StringUtil.getRandomString()), null, executor); + super(StringUtil.getRandomString("MF"), null, executor); this.hostName = builder.getEndpoint().getHost(); this.reactorFactory = reactorFactory; @@ -67,7 +67,7 @@ public final class MessagingFactory extends ClientEntity implements AmqpConnecti this.retryPolicy = retryPolicy; this.registeredLinks = new LinkedList<>(); this.reactorLock = new Object(); - this.connectionHandler = ConnectionHandler.create(builder.getTransportType(), this); + this.connectionHandler = ConnectionHandler.create(builder.getTransportType(), this, this.getClientId()); this.cbsChannelCreateLock = new Object(); this.mgmtChannelCreateLock = new Object(); this.tokenProvider = builder.getSharedAccessSignature() == null @@ -155,7 +155,7 @@ private void createConnection() throws IOException { } private void startReactor(final ReactorHandler reactorHandler) throws IOException { - final Reactor newReactor = this.reactorFactory.create(reactorHandler, this.connectionHandler.getMaxFrameSize()); + final Reactor newReactor = this.reactorFactory.create(reactorHandler, this.connectionHandler.getMaxFrameSize(), this.getClientId()); synchronized (this.reactorLock) { this.reactor = newReactor; this.reactorDispatcher = new ReactorDispatcher(newReactor); @@ -170,7 +170,7 @@ private void startReactor(final ReactorHandler reactorHandler) throws IOExceptio public CBSChannel getCBSChannel() { synchronized (this.cbsChannelCreateLock) { if (this.cbsChannel == null) { - this.cbsChannel = new CBSChannel(this, this); + this.cbsChannel = new CBSChannel(this, this, this.getClientId()); } } @@ -180,7 +180,7 @@ public CBSChannel getCBSChannel() { public ManagementChannel getManagementChannel() { synchronized (this.mgmtChannelCreateLock) { if (this.mgmtChannel == null) { - this.mgmtChannel = new ManagementChannel(this, this); + this.mgmtChannel = new ManagementChannel(this, this, this.getClientId()); } } @@ -190,11 +190,16 @@ public ManagementChannel getManagementChannel() { @Override public Session getSession(final String path, final Consumer onRemoteSessionOpen, final BiConsumer onRemoteSessionOpenError) { if (this.getIsClosingOrClosed()) { - onRemoteSessionOpenError.accept(null, new OperationCancelledException("underlying messagingFactory instance is closed")); return null; } + if (TRACE_LOGGER.isInfoEnabled()) { + TRACE_LOGGER.info( + String.format(Locale.US, "messagingFactory[%s], hostName[%s], getting a session.", + getClientId(), getHostName())); + } + if (this.connection == null || this.connection.getLocalState() == EndpointState.CLOSED || this.connection.getRemoteState() == EndpointState.CLOSED) { this.connection = this.getReactor().connectionToHost( this.connectionHandler.getRemoteHostName(), @@ -203,7 +208,7 @@ public Session getSession(final String path, final Consumer onRemoteSes } final Session session = this.connection.session(); - BaseHandler.setHandler(session, new SessionHandler(path, onRemoteSessionOpen, onRemoteSessionOpenError, this.operationTimeout)); + BaseHandler.setHandler(session, new SessionHandler(path, onRemoteSessionOpen, onRemoteSessionOpenError, this.operationTimeout, this.getClientId())); session.open(); return session; @@ -236,7 +241,7 @@ public void onOpenComplete(Exception exception) { @Override public void onConnectionError(ErrorCondition error) { if (TRACE_LOGGER.isWarnEnabled()) { - TRACE_LOGGER.warn(String.format(Locale.US, "onConnectionError: messagingFactory[%s], hostname[%s], error[%s]", + TRACE_LOGGER.warn(String.format(Locale.US, "onConnectionError messagingFactory[%s], hostname[%s], error[%s]", this.getClientId(), this.hostName, error != null ? error.getDescription() : "n/a")); @@ -244,7 +249,7 @@ public void onConnectionError(ErrorCondition error) { if (!this.open.isDone()) { if (TRACE_LOGGER.isWarnEnabled()) { - TRACE_LOGGER.warn(String.format(Locale.US, "onConnectionError: messagingFactory[%s], hostname[%s], open hasn't complete, stopping the reactor", + TRACE_LOGGER.warn(String.format(Locale.US, "onConnectionError messagingFactory[%s], hostname[%s], open hasn't complete, stopping the reactor", this.getClientId(), this.hostName)); } @@ -259,7 +264,7 @@ public void onConnectionError(ErrorCondition error) { for (Link link : oldRegisteredLinksCopy) { if (link.getLocalState() != EndpointState.CLOSED) { if (TRACE_LOGGER.isWarnEnabled()) { - TRACE_LOGGER.warn(String.format(Locale.US, "onConnectionError: messagingFactory[%s], hostname[%s], closing link [%s]", + TRACE_LOGGER.warn(String.format(Locale.US, "onConnectionError messagingFactory[%s], hostname[%s], closing link [%s]", this.getClientId(), this.hostName, link.getName())); } @@ -274,7 +279,7 @@ public void onConnectionError(ErrorCondition error) { // in connection recreation we depend on currentConnection state to evaluate need for recreation if (oldConnection.getLocalState() != EndpointState.CLOSED) { if (TRACE_LOGGER.isWarnEnabled()) { - TRACE_LOGGER.warn(String.format(Locale.US, "onConnectionError: messagingFactory[%s], hostname[%s], closing current connection", + TRACE_LOGGER.warn(String.format(Locale.US, "onConnectionError messagingFactory[%s], hostname[%s], closing current connection", this.getClientId(), this.hostName)); } @@ -410,8 +415,8 @@ public void scheduleOnReactorThread(final int delay, final DispatchHandler handl public static class ReactorFactory { - public Reactor create(final ReactorHandler reactorHandler, final int maxFrameSize) throws IOException { - return ProtonUtil.reactor(reactorHandler, maxFrameSize); + public Reactor create(final ReactorHandler reactorHandler, final int maxFrameSize, final String name) throws IOException { + return ProtonUtil.reactor(reactorHandler, maxFrameSize, name); } } @@ -606,6 +611,10 @@ public void run() { } private class ReactorHandlerWithConnection extends ReactorHandler { + public ReactorHandlerWithConnection() { + super(getClientId()); + } + @Override public void onReactorInit(Event e) { super.onReactorInit(e); diff --git a/azure-eventhubs/src/main/java/com/microsoft/azure/eventhubs/impl/PartitionReceiverImpl.java b/azure-eventhubs/src/main/java/com/microsoft/azure/eventhubs/impl/PartitionReceiverImpl.java index 3e06503835f8..1b7a70bd3c22 100644 --- a/azure-eventhubs/src/main/java/com/microsoft/azure/eventhubs/impl/PartitionReceiverImpl.java +++ b/azure-eventhubs/src/main/java/com/microsoft/azure/eventhubs/impl/PartitionReceiverImpl.java @@ -47,7 +47,7 @@ private PartitionReceiverImpl(MessagingFactory factory, final boolean isEpochReceiver, final ReceiverOptions receiverOptions, final ScheduledExecutorService executor) { - super("PartitionReceiverImpl".concat(StringUtil.getRandomString()), null, executor); + super(StringUtil.getRandomString("PR").concat(StringUtil.SEPARATOR + factory.getClientId()), null, executor); this.underlyingFactory = factory; this.eventHubName = eventHubName; @@ -96,7 +96,7 @@ public PartitionReceiver apply(Void a) { private CompletableFuture createInternalReceiver() { return MessageReceiver.create(this.underlyingFactory, this.getClientId().concat("-InternalReceiver"), - String.format("%s/ConsumerGroups/%s/Partitions/%s", this.eventHubName, this.consumerGroupName, this.partitionId), + String.format(Locale.US, "%s/ConsumerGroups/%s/Partitions/%s", this.eventHubName, this.consumerGroupName, this.partitionId), this.receiverOptions.getPrefetchCount(), this) .thenAcceptAsync(new Consumer() { public void accept(MessageReceiver r) { @@ -239,7 +239,7 @@ public Map getFilter(final Message lastReceivedMes } else { logReceivePath = "receiverPath[" + this.internalReceiver.getReceivePath() + "]"; } - TRACE_LOGGER.info(String.format("%s, action[createReceiveLink], %s", logReceivePath, this.eventPosition)); + TRACE_LOGGER.info(String.format(Locale.US, "%s, action[createReceiveLink], %s", logReceivePath, this.eventPosition)); } return Collections.singletonMap(AmqpConstants.STRING_FILTER, new UnknownDescribedType(AmqpConstants.STRING_FILTER, expression)); diff --git a/azure-eventhubs/src/main/java/com/microsoft/azure/eventhubs/impl/PartitionSenderImpl.java b/azure-eventhubs/src/main/java/com/microsoft/azure/eventhubs/impl/PartitionSenderImpl.java index 8acdc2a27d05..7fde91c648ea 100644 --- a/azure-eventhubs/src/main/java/com/microsoft/azure/eventhubs/impl/PartitionSenderImpl.java +++ b/azure-eventhubs/src/main/java/com/microsoft/azure/eventhubs/impl/PartitionSenderImpl.java @@ -6,6 +6,7 @@ import com.microsoft.azure.eventhubs.*; +import java.util.Locale; import java.util.concurrent.CompletableFuture; import java.util.concurrent.ScheduledExecutorService; import java.util.function.Consumer; @@ -19,7 +20,7 @@ final class PartitionSenderImpl extends ClientEntity implements PartitionSender private volatile MessageSender internalSender; private PartitionSenderImpl(final MessagingFactory factory, final String eventHubName, final String partitionId, final ScheduledExecutorService executor) { - super("PartitionSenderImpl".concat(StringUtil.getRandomString()), null, executor); + super(StringUtil.getRandomString("PS").concat(StringUtil.SEPARATOR + factory.getClientId()), null, executor); this.partitionId = partitionId; this.eventHubName = eventHubName; @@ -41,7 +42,7 @@ public PartitionSender apply(Void a) { private CompletableFuture createInternalSender() throws EventHubException { return MessageSender.create(this.factory, this.getClientId().concat("-InternalSender"), - String.format("%s/Partitions/%s", this.eventHubName, this.partitionId)) + String.format(Locale.US, "%s/Partitions/%s", this.eventHubName, this.partitionId)) .thenAcceptAsync(new Consumer() { public void accept(MessageSender a) { PartitionSenderImpl.this.internalSender = a; diff --git a/azure-eventhubs/src/main/java/com/microsoft/azure/eventhubs/impl/ProtonUtil.java b/azure-eventhubs/src/main/java/com/microsoft/azure/eventhubs/impl/ProtonUtil.java index 7b719fcf4eee..f648a1834f1d 100644 --- a/azure-eventhubs/src/main/java/com/microsoft/azure/eventhubs/impl/ProtonUtil.java +++ b/azure-eventhubs/src/main/java/com/microsoft/azure/eventhubs/impl/ProtonUtil.java @@ -15,14 +15,14 @@ public final class ProtonUtil { private ProtonUtil() { } - public static Reactor reactor(final ReactorHandler reactorHandler, final int maxFrameSize) throws IOException { + public static Reactor reactor(final ReactorHandler reactorHandler, final int maxFrameSize, final String name) throws IOException { final ReactorOptions reactorOptions = new ReactorOptions(); reactorOptions.setMaxFrameSize(maxFrameSize); reactorOptions.setEnableSaslByDefault(true); final Reactor reactor = Proton.reactor(reactorOptions, reactorHandler); - reactor.setGlobalHandler(new CustomIOHandler()); + reactor.setGlobalHandler(new CustomIOHandler(name)); return reactor; } diff --git a/azure-eventhubs/src/main/java/com/microsoft/azure/eventhubs/impl/ReactorHandler.java b/azure-eventhubs/src/main/java/com/microsoft/azure/eventhubs/impl/ReactorHandler.java index 9b1bea3c0d13..ab7e20d52c39 100644 --- a/azure-eventhubs/src/main/java/com/microsoft/azure/eventhubs/impl/ReactorHandler.java +++ b/azure-eventhubs/src/main/java/com/microsoft/azure/eventhubs/impl/ReactorHandler.java @@ -10,12 +10,20 @@ import org.slf4j.Logger; import org.slf4j.LoggerFactory; +import java.util.Locale; + public class ReactorHandler extends BaseHandler { private static final Logger TRACE_LOGGER = LoggerFactory.getLogger(ReactorHandler.class); + private final String name; + private ReactorDispatcher reactorDispatcher; + public ReactorHandler(final String name) { + this.name = name; + } + public ReactorDispatcher getReactorDispatcher() { return this.reactorDispatcher; } @@ -27,8 +35,7 @@ public void unsafeSetReactorDispatcher(final ReactorDispatcher reactorDispatcher @Override public void onReactorInit(Event e) { - - TRACE_LOGGER.info("reactor.onReactorInit"); + TRACE_LOGGER.info(String.format(Locale.US, "name[%s] reactor.onReactorInit", this.name)); final Reactor reactor = e.getReactor(); reactor.setTimeout(ClientConstants.REACTOR_IO_POLL_TIMEOUT); @@ -36,7 +43,6 @@ public void onReactorInit(Event e) { @Override public void onReactorFinal(Event e) { - - TRACE_LOGGER.info("reactor.onReactorFinal"); + TRACE_LOGGER.info(String.format(Locale.US, "name[%s] reactor.onReactorFinal", this.name)); } } diff --git a/azure-eventhubs/src/main/java/com/microsoft/azure/eventhubs/impl/ReceiveLinkHandler.java b/azure-eventhubs/src/main/java/com/microsoft/azure/eventhubs/impl/ReceiveLinkHandler.java index db32fe36d881..1bd9b0b4b175 100644 --- a/azure-eventhubs/src/main/java/com/microsoft/azure/eventhubs/impl/ReceiveLinkHandler.java +++ b/azure-eventhubs/src/main/java/com/microsoft/azure/eventhubs/impl/ReceiveLinkHandler.java @@ -13,18 +13,18 @@ import java.util.Locale; -// ServiceBus <-> ProtonReactor interaction -// handles all recvLink - reactor events public final class ReceiveLinkHandler extends BaseLinkHandler { private static final Logger TRACE_LOGGER = LoggerFactory.getLogger(ReceiveLinkHandler.class); private final AmqpReceiver amqpReceiver; + private final String receiverName; private final Object firstResponse; private boolean isFirstResponse; - public ReceiveLinkHandler(final AmqpReceiver receiver) { - super(receiver); + public ReceiveLinkHandler(final AmqpReceiver receiver, final String receiverName) { + super(receiver, receiverName); this.amqpReceiver = receiver; + this.receiverName = receiverName; this.firstResponse = new Object(); this.isFirstResponse = true; } @@ -33,11 +33,9 @@ public ReceiveLinkHandler(final AmqpReceiver receiver) { public void onLinkLocalOpen(Event evt) { Link link = evt.getLink(); if (link instanceof Receiver) { - Receiver receiver = (Receiver) link; - if (TRACE_LOGGER.isInfoEnabled()) { - TRACE_LOGGER.info( - String.format("onLinkLocalOpen linkName[%s], localSource[%s]", receiver.getName(), receiver.getSource())); + TRACE_LOGGER.info(String.format(Locale.US, "onLinkLocalOpen receiverName[%s], linkName[%s], localSource[%s]", + this.receiverName, link.getName(), link.getSource())); } } } @@ -46,11 +44,10 @@ public void onLinkLocalOpen(Event evt) { public void onLinkRemoteOpen(Event event) { Link link = event.getLink(); if (link instanceof Receiver) { - Receiver receiver = (Receiver) link; if (link.getRemoteSource() != null) { if (TRACE_LOGGER.isInfoEnabled()) { - TRACE_LOGGER.info(String.format(Locale.US, "onLinkRemoteOpen linkName[%s], remoteSource[%s]", - receiver.getName(), link.getRemoteSource())); + TRACE_LOGGER.info(String.format(Locale.US, "onLinkRemoteOpen receiverName[%s], linkName[%s], remoteSource[%s]", + this.receiverName, link.getName(), link.getRemoteSource())); } synchronized (this.firstResponse) { @@ -59,9 +56,8 @@ public void onLinkRemoteOpen(Event event) { } } else { if (TRACE_LOGGER.isInfoEnabled()) { - TRACE_LOGGER.info( - String.format(Locale.US, "onLinkRemoteOpen linkName[%s], remoteTarget[null], " + - "remoteSource[null], action[waitingForError]", receiver.getName())); + TRACE_LOGGER.info(String.format(Locale.US, "onLinkRemoteOpen receiverName[%s], linkName[%s], action[waitingForError]", + this.receiverName, link.getName())); } } } @@ -91,9 +87,9 @@ public void onDelivery(Event event) { if (TRACE_LOGGER.isWarnEnabled()) { TRACE_LOGGER.warn( receiveLink != null - ? String.format(Locale.US, "onDelivery linkName[%s], updatedLinkCredit[%s], remoteCredit[%s], " + + ? String.format(Locale.US, "onDelivery receiverName[%s], linkName[%s], updatedLinkCredit[%s], remoteCredit[%s], " + "remoteCondition[%s], delivery.isSettled[%s]", - receiveLink.getName(), receiveLink.getCredit(), receiveLink.getRemoteCredit(), receiveLink.getRemoteCondition(), delivery.isSettled()) + this.receiverName, receiveLink.getName(), receiveLink.getCredit(), receiveLink.getRemoteCredit(), receiveLink.getRemoteCondition(), delivery.isSettled()) : String.format(Locale.US, "delivery.isSettled[%s]", delivery.isSettled())); } } else { @@ -103,9 +99,9 @@ public void onDelivery(Event event) { if (TRACE_LOGGER.isTraceEnabled() && receiveLink != null) { TRACE_LOGGER.trace( - String.format(Locale.US, "onDelivery linkName[%s], updatedLinkCredit[%s], remoteCredit[%s], " + + String.format(Locale.US, "onDelivery receiverName[%s], linkName[%s], updatedLinkCredit[%s], remoteCredit[%s], " + "remoteCondition[%s], delivery.isPartial[%s]", - receiveLink.getName(), receiveLink.getCredit(), receiveLink.getRemoteCredit(), receiveLink.getRemoteCondition(), delivery.isPartial())); + this.receiverName, receiveLink.getName(), receiveLink.getCredit(), receiveLink.getRemoteCredit(), receiveLink.getRemoteCondition(), delivery.isPartial())); } } } diff --git a/azure-eventhubs/src/main/java/com/microsoft/azure/eventhubs/impl/ReceivePump.java b/azure-eventhubs/src/main/java/com/microsoft/azure/eventhubs/impl/ReceivePump.java index b60e67db0462..0369a0bf9fe4 100644 --- a/azure-eventhubs/src/main/java/com/microsoft/azure/eventhubs/impl/ReceivePump.java +++ b/azure-eventhubs/src/main/java/com/microsoft/azure/eventhubs/impl/ReceivePump.java @@ -9,6 +9,7 @@ import org.slf4j.Logger; import org.slf4j.LoggerFactory; +import java.util.Locale; import java.util.concurrent.CompletableFuture; import java.util.concurrent.Executor; import java.util.concurrent.RejectedExecutionException; @@ -56,7 +57,7 @@ public void run() { } catch (final Exception exception) { if (TRACE_LOGGER.isErrorEnabled()) { TRACE_LOGGER.error( - String.format("Receive pump for eventHub (%s), consumerGroup (%s), partition (%s) " + + String.format(Locale.US, "Receive pump for eventHub (%s), consumerGroup (%s), partition (%s) " + "encountered unrecoverable error and exited with exception %s.", this.eventHubName, this.consumerGroupName, this.receiver.getPartitionId(), exception.toString())); } @@ -72,7 +73,7 @@ public void receiveAndProcess() { .handleAsync(this.processAndReschedule, this.executor); } else { if (TRACE_LOGGER.isInfoEnabled()) { - TRACE_LOGGER.info(String.format("Stopping receive pump for eventHub (%s), consumerGroup (%s), partition (%s) as %s", + TRACE_LOGGER.info(String.format(Locale.US, "Stopping receive pump for eventHub (%s), consumerGroup (%s), partition (%s) as %s", this.eventHubName, this.consumerGroupName, this.receiver.getPartitionId(), this.stopPumpRaised.get() ? "per the request." : "pump ran into errors.")); } @@ -112,7 +113,7 @@ private void handleUserCodeExceptions(final Throwable userCodeException) { this.isPumpHealthy = false; if (TRACE_LOGGER.isErrorEnabled()) { TRACE_LOGGER.error( - String.format("Receive pump for eventHub (%s), consumerGroup (%s), partition (%s) " + + String.format(Locale.US, "Receive pump for eventHub (%s), consumerGroup (%s), partition (%s) " + "exiting after user-code exception %s", this.eventHubName, this.consumerGroupName, this.receiver.getPartitionId(), userCodeException.toString())); } @@ -121,7 +122,7 @@ private void handleUserCodeExceptions(final Throwable userCodeException) { if (userCodeException instanceof InterruptedException) { if (TRACE_LOGGER.isInfoEnabled()) { - TRACE_LOGGER.info(String.format("Interrupting receive pump for eventHub (%s), consumerGroup (%s), partition (%s)", + TRACE_LOGGER.info(String.format(Locale.US, "Interrupting receive pump for eventHub (%s), consumerGroup (%s), partition (%s)", this.eventHubName, this.consumerGroupName, this.receiver.getPartitionId())); } diff --git a/azure-eventhubs/src/main/java/com/microsoft/azure/eventhubs/impl/RequestResponseChannel.java b/azure-eventhubs/src/main/java/com/microsoft/azure/eventhubs/impl/RequestResponseChannel.java index 68a9719b4ab5..2299d3272621 100644 --- a/azure-eventhubs/src/main/java/com/microsoft/azure/eventhubs/impl/RequestResponseChannel.java +++ b/azure-eventhubs/src/main/java/com/microsoft/azure/eventhubs/impl/RequestResponseChannel.java @@ -51,7 +51,7 @@ public RequestResponseChannel( this.sendLink.setTarget(target); sendLink.setSource(new Source()); this.sendLink.setSenderSettleMode(SenderSettleMode.SETTLED); - BaseHandler.setHandler(this.sendLink, new SendLinkHandler(new RequestHandler())); + BaseHandler.setHandler(this.sendLink, new SendLinkHandler(new RequestHandler(), linkName)); this.receiveLink = session.receiver(linkName + ":receiver"); final Source source = new Source(); @@ -62,7 +62,7 @@ public RequestResponseChannel( this.receiveLink.setTarget(receiverTarget); this.receiveLink.setSenderSettleMode(SenderSettleMode.SETTLED); this.receiveLink.setReceiverSettleMode(ReceiverSettleMode.SECOND); - BaseHandler.setHandler(this.receiveLink, new ReceiveLinkHandler(new ResponseHandler())); + BaseHandler.setHandler(this.receiveLink, new ReceiveLinkHandler(new ResponseHandler(), linkName)); } // open should be called only once - we use FaultTolerantObject for that diff --git a/azure-eventhubs/src/main/java/com/microsoft/azure/eventhubs/impl/RequestResponseOpener.java b/azure-eventhubs/src/main/java/com/microsoft/azure/eventhubs/impl/RequestResponseOpener.java index bd4d55617084..15ddc3948dca 100644 --- a/azure-eventhubs/src/main/java/com/microsoft/azure/eventhubs/impl/RequestResponseOpener.java +++ b/azure-eventhubs/src/main/java/com/microsoft/azure/eventhubs/impl/RequestResponseOpener.java @@ -2,19 +2,28 @@ import org.apache.qpid.proton.amqp.transport.ErrorCondition; import org.apache.qpid.proton.engine.Session; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; +import java.util.Locale; import java.util.function.BiConsumer; public class RequestResponseOpener implements Operation { + private static final Logger TRACE_LOGGER = LoggerFactory.getLogger(RequestResponseOpener.class); + private final SessionProvider sessionProvider; + private final String clientId; private final String sessionName; private final String linkName; private final String endpointAddress; private final AmqpConnection eventDispatcher; - public RequestResponseOpener(final SessionProvider sessionProvider, final String sessionName, final String linkName, + private boolean isOpened; + + public RequestResponseOpener(final SessionProvider sessionProvider, final String clientId, final String sessionName, final String linkName, final String endpointAddress, final AmqpConnection eventDispatcher) { this.sessionProvider = sessionProvider; + this.clientId = clientId; this.sessionName = sessionName; this.linkName = linkName; this.endpointAddress = endpointAddress; @@ -22,7 +31,10 @@ public RequestResponseOpener(final SessionProvider sessionProvider, final String } @Override - public void run(OperationResult operationCallback) { + public synchronized void run(OperationResult operationCallback) { + if (this.isOpened) { + return; + } final Session session = this.sessionProvider.getSession( this.sessionName, @@ -53,11 +65,23 @@ public void onComplete(Void result) { eventDispatcher.registerForConnectionError(requestResponseChannel.getReceiveLink()); operationCallback.onComplete(requestResponseChannel); + + isOpened = true; + + if (TRACE_LOGGER.isInfoEnabled()) { + TRACE_LOGGER.info(String.format(Locale.US, "requestResponseChannel.onOpen complete clientId[%s], session[%s], link[%s], endpoint[%s]", + clientId, sessionName, linkName, endpointAddress)); + } } @Override public void onError(Exception error) { operationCallback.onError(error); + + if (TRACE_LOGGER.isWarnEnabled()) { + TRACE_LOGGER.warn(String.format(Locale.US, "requestResponseChannel.onOpen error clientId[%s], session[%s], link[%s], endpoint[%s], error %s", + clientId, sessionName, linkName, endpointAddress, error)); + } } }, new OperationResult() { @@ -65,12 +89,24 @@ public void onError(Exception error) { public void onComplete(Void result) { eventDispatcher.deregisterForConnectionError(requestResponseChannel.getSendLink()); eventDispatcher.deregisterForConnectionError(requestResponseChannel.getReceiveLink()); + + isOpened = false; + + if (TRACE_LOGGER.isInfoEnabled()) { + TRACE_LOGGER.info(String.format(Locale.US, "requestResponseChannel.onClose complete clientId[%s], session[%s], link[%s], endpoint[%s]", + clientId, sessionName, linkName, endpointAddress)); + } } @Override public void onError(Exception error) { eventDispatcher.deregisterForConnectionError(requestResponseChannel.getSendLink()); eventDispatcher.deregisterForConnectionError(requestResponseChannel.getReceiveLink()); + + if (TRACE_LOGGER.isWarnEnabled()) { + TRACE_LOGGER.warn(String.format(Locale.US, "requestResponseChannel.onClose error clientId[%s], session[%s], link[%s], endpoint[%s], error %s", + clientId, sessionName, linkName, endpointAddress, error)); + } } }); } diff --git a/azure-eventhubs/src/main/java/com/microsoft/azure/eventhubs/impl/SchedulerProvider.java b/azure-eventhubs/src/main/java/com/microsoft/azure/eventhubs/impl/SchedulerProvider.java index 03e6d91c9d8c..c2a59eae92f6 100644 --- a/azure-eventhubs/src/main/java/com/microsoft/azure/eventhubs/impl/SchedulerProvider.java +++ b/azure-eventhubs/src/main/java/com/microsoft/azure/eventhubs/impl/SchedulerProvider.java @@ -1,3 +1,7 @@ +/* + * Copyright (c) Microsoft. All rights reserved. + * Licensed under the MIT license. See LICENSE file in the project root for full license information. + */ package com.microsoft.azure.eventhubs.impl; interface SchedulerProvider { diff --git a/azure-eventhubs/src/main/java/com/microsoft/azure/eventhubs/impl/SendLinkHandler.java b/azure-eventhubs/src/main/java/com/microsoft/azure/eventhubs/impl/SendLinkHandler.java index 8a9df26a626c..4cb3fe7f05a5 100644 --- a/azure-eventhubs/src/main/java/com/microsoft/azure/eventhubs/impl/SendLinkHandler.java +++ b/azure-eventhubs/src/main/java/com/microsoft/azure/eventhubs/impl/SendLinkHandler.java @@ -16,13 +16,15 @@ public class SendLinkHandler extends BaseLinkHandler { private static final Logger TRACE_LOGGER = LoggerFactory.getLogger(SendLinkHandler.class); private final AmqpSender msgSender; + private final String senderName; private final Object firstFlow; private boolean isFirstFlow; - public SendLinkHandler(final AmqpSender sender) { - super(sender); + public SendLinkHandler(final AmqpSender sender, final String senderName) { + super(sender, senderName); this.msgSender = sender; + this.senderName = senderName; this.firstFlow = new Object(); this.isFirstFlow = true; } @@ -31,9 +33,9 @@ public SendLinkHandler(final AmqpSender sender) { public void onLinkLocalOpen(Event event) { Link link = event.getLink(); if (link instanceof Sender) { - Sender sender = (Sender) link; if (TRACE_LOGGER.isInfoEnabled()) { - TRACE_LOGGER.info(String.format("onLinkLocalOpen linkName[%s], localTarget[%s]", sender.getName(), sender.getTarget())); + TRACE_LOGGER.info(String.format(Locale.US, "onLinkLocalOpen senderName[%s], linkName[%s], localTarget[%s]", + this.senderName, link.getName(), link.getTarget())); } } } @@ -42,10 +44,10 @@ public void onLinkLocalOpen(Event event) { public void onLinkRemoteOpen(Event event) { Link link = event.getLink(); if (link instanceof Sender) { - Sender sender = (Sender) link; if (link.getRemoteTarget() != null) { if (TRACE_LOGGER.isInfoEnabled()) { - TRACE_LOGGER.info(String.format(Locale.US, "onLinkRemoteOpen linkName[%s], remoteTarget[%s]", sender.getName(), link.getRemoteTarget())); + TRACE_LOGGER.info(String.format(Locale.US, "onLinkRemoteOpen senderName[%s], linkName[%s], remoteTarget[%s]", + this.senderName, link.getName(), link.getRemoteTarget())); } synchronized (this.firstFlow) { @@ -54,8 +56,8 @@ public void onLinkRemoteOpen(Event event) { } } else { if (TRACE_LOGGER.isInfoEnabled()) { - TRACE_LOGGER.info( - String.format(Locale.US, "onLinkRemoteOpen linkName[%s], remoteTarget[null], remoteSource[null], action[waitingForError]", sender.getName())); + TRACE_LOGGER.info(String.format(Locale.US, "onLinkRemoteOpen senderName[%s], linkName[%s], remoteTarget[null], remoteSource[null], action[waitingForError]", + this.senderName, link.getName())); } } } @@ -69,10 +71,8 @@ public void onDelivery(Event event) { Sender sender = (Sender) delivery.getLink(); if (TRACE_LOGGER.isTraceEnabled()) { - TRACE_LOGGER.trace( - "onDelivery linkName[" + sender.getName() + - "], unsettled[" + sender.getUnsettled() + "], credit[" + sender.getRemoteCredit() + "], deliveryState[" + delivery.getRemoteState() + - "], delivery.isBuffered[" + delivery.isBuffered() + "], delivery.id[" + new String(delivery.getTag()) + "]"); + TRACE_LOGGER.trace(String.format(Locale.US, "onDelivery senderName[%s], linkName[%s], unsettled[%s], credit[%s], deliveryState[%s], delivery.isBuffered[%s], delivery.id[%s]", + this.senderName, sender.getName(), sender.getUnsettled(), sender.getRemoteCredit(), delivery.getRemoteState(), delivery.isBuffered(), new String(delivery.getTag()))); } msgSender.onSendComplete(delivery); @@ -97,7 +97,8 @@ public void onLinkFlow(Event event) { this.msgSender.onFlow(sender.getRemoteCredit()); if (TRACE_LOGGER.isDebugEnabled()) { - TRACE_LOGGER.debug("onLinkFlow linkName[" + sender.getName() + "], unsettled[" + sender.getUnsettled() + "], credit[" + sender.getCredit() + "]"); + TRACE_LOGGER.debug(String.format(Locale.US, "onLinkFlow senderName[%s], linkName[%s], unsettled[%s], credit[%s]", + this.senderName, sender.getName(), sender.getUnsettled(), sender.getCredit())); } } } diff --git a/azure-eventhubs/src/main/java/com/microsoft/azure/eventhubs/impl/SessionHandler.java b/azure-eventhubs/src/main/java/com/microsoft/azure/eventhubs/impl/SessionHandler.java index 65714d2e57c5..f5b4fc47e6d6 100644 --- a/azure-eventhubs/src/main/java/com/microsoft/azure/eventhubs/impl/SessionHandler.java +++ b/azure-eventhubs/src/main/java/com/microsoft/azure/eventhubs/impl/SessionHandler.java @@ -25,6 +25,7 @@ public class SessionHandler extends BaseHandler { private final Consumer onRemoteSessionOpen; private final BiConsumer onRemoteSessionOpenError; private final Duration openTimeout; + private final String connectionId; private boolean sessionCreated = false; private boolean sessionOpenErrorDispatched = false; @@ -32,18 +33,20 @@ public class SessionHandler extends BaseHandler { public SessionHandler(final String entityName, final Consumer onRemoteSessionOpen, final BiConsumer onRemoteSessionOpenError, - final Duration openTimeout) { + final Duration openTimeout, + final String connectionId) { this.entityName = entityName; this.onRemoteSessionOpenError = onRemoteSessionOpenError; this.onRemoteSessionOpen = onRemoteSessionOpen; this.openTimeout = openTimeout; + this.connectionId = connectionId; } @Override public void onSessionLocalOpen(Event e) { if (TRACE_LOGGER.isInfoEnabled()) { - TRACE_LOGGER.info(String.format(Locale.US, "onSessionLocalOpen entityName[%s], condition[%s]", this.entityName, - e.getSession().getCondition() == null ? "none" : e.getSession().getCondition().toString())); + TRACE_LOGGER.info(String.format(Locale.US, "onSessionLocalOpen connectionId[%s], entityName[%s], condition[%s]", + this.connectionId, this.entityName, e.getSession().getCondition() == null ? "none" : e.getSession().getCondition().toString())); } if (this.onRemoteSessionOpenError != null) { @@ -62,11 +65,11 @@ public void onSessionLocalOpen(Event e) { final Session session = e.getSession(); try { - reactorDispatcher.invoke((int) this.openTimeout.toMillis(), new SessionTimeoutHandler(session, entityName)); + reactorDispatcher.invoke((int) this.openTimeout.toMillis(), new SessionTimeoutHandler(session, entityName, connectionId)); } catch (IOException ioException) { if (TRACE_LOGGER.isWarnEnabled()) { - TRACE_LOGGER.warn(String.format(Locale.US, "onSessionLocalOpen entityName[%s], reactorDispatcherError[%s]", - this.entityName, ioException.getMessage())); + TRACE_LOGGER.warn(String.format(Locale.US, "onSessionLocalOpen connectionId[%s], entityName[%s], reactorDispatcherError[%s]", + this.connectionId, this.entityName, ioException.getMessage())); } session.close(); @@ -74,8 +77,8 @@ public void onSessionLocalOpen(Event e) { null, new EventHubException( false, - String.format("onSessionLocalOpen entityName[%s], underlying IO of reactorDispatcher faulted with error: %s", - this.entityName, ioException.getMessage()), ioException)); + String.format(Locale.US, "onSessionLocalOpen connectionId[%s], entityName[%s], underlying IO of reactorDispatcher faulted with error: %s", + this.connectionId, this.entityName, ioException.getMessage()), ioException)); } } } @@ -83,8 +86,8 @@ public void onSessionLocalOpen(Event e) { @Override public void onSessionRemoteOpen(Event e) { if (TRACE_LOGGER.isInfoEnabled()) { - TRACE_LOGGER.info(String.format(Locale.US, "onSessionRemoteOpen entityName[%s], sessionIncCapacity[%s], sessionOutgoingWindow[%s]", - this.entityName, e.getSession().getIncomingCapacity(), e.getSession().getOutgoingWindow())); + TRACE_LOGGER.info(String.format(Locale.US, "onSessionRemoteOpen connectionId[%s], entityName[%s], sessionIncCapacity[%s], sessionOutgoingWindow[%s]", + this.connectionId, this.entityName, e.getSession().getIncomingCapacity(), e.getSession().getOutgoingWindow())); } final Session session = e.getSession(); @@ -100,16 +103,16 @@ public void onSessionRemoteOpen(Event e) { @Override public void onSessionLocalClose(Event e) { if (TRACE_LOGGER.isInfoEnabled()) { - TRACE_LOGGER.info(String.format(Locale.US, "onSessionLocalClose entityName[%s], condition[%s]", this.entityName, - e.getSession().getCondition() == null ? "none" : e.getSession().getCondition().toString())); + TRACE_LOGGER.info(String.format(Locale.US, "onSessionLocalClose connectionId[%s], entityName[%s], condition[%s]", this.entityName, + this.connectionId, e.getSession().getCondition() == null ? "none" : e.getSession().getCondition().toString())); } } @Override public void onSessionRemoteClose(Event e) { if (TRACE_LOGGER.isInfoEnabled()) { - TRACE_LOGGER.info(String.format(Locale.US, "onSessionRemoteClose entityName[%s], condition[%s]", this.entityName, - e.getSession().getRemoteCondition() == null ? "none" : e.getSession().getRemoteCondition().toString())); + TRACE_LOGGER.info(String.format(Locale.US, "onSessionRemoteClose connectionId[%s], entityName[%s], condition[%s]", this.entityName, + this.connectionId, e.getSession().getRemoteCondition() == null ? "none" : e.getSession().getRemoteCondition().toString())); } final Session session = e.getSession(); @@ -117,10 +120,8 @@ public void onSessionRemoteClose(Event e) { if (session != null && session.getLocalState() != EndpointState.CLOSED) { if (TRACE_LOGGER.isInfoEnabled()) { - TRACE_LOGGER.info(String.format(Locale.US, "onSessionRemoteClose closing a local session for entityName[%s], condition[%s], description[%s]", - this.entityName, - condition != null ? condition.getCondition() : "n/a", - condition != null ? condition.getDescription() : "n/a")); + TRACE_LOGGER.info(String.format(Locale.US, "onSessionRemoteClose closing a local session for connectionId[%s], entityName[%s], condition[%s], description[%s]", + this.connectionId, this.entityName, condition != null ? condition.getCondition() : "n/a", condition != null ? condition.getDescription() : "n/a")); } session.setCondition(session.getRemoteCondition()); @@ -138,10 +139,8 @@ public void onSessionFinal(Event e) { final Session session = e.getSession(); ErrorCondition condition = session != null ? session.getCondition() : null; - TRACE_LOGGER.info(String.format(Locale.US, "onSessionFinal entityName[%s], condition[%s], description[%s]", - this.entityName, - condition != null ? condition.getCondition() : "n/a", - condition != null ? condition.getDescription() : "n/a")); + TRACE_LOGGER.info(String.format(Locale.US, "onSessionFinal connectionId[%s], entityName[%s], condition[%s], description[%s]", + this.connectionId, this.entityName, condition != null ? condition.getCondition() : "n/a", condition != null ? condition.getDescription() : "n/a")); } } @@ -149,10 +148,12 @@ private class SessionTimeoutHandler extends DispatchHandler { private final Session session; private final String entityName; + private final String connectionId; - SessionTimeoutHandler(final Session session, final String entityName) { + SessionTimeoutHandler(final Session session, final String entityName, final String connectionId) { this.session = session; this.entityName = entityName; + this.connectionId = connectionId; } @Override @@ -166,8 +167,8 @@ public void onEvent() { if (!sessionCreated && !sessionOpenErrorDispatched) { if (TRACE_LOGGER.isWarnEnabled()) { - TRACE_LOGGER.warn(String.format(Locale.US, "SessionTimeoutHandler.onEvent - entityName[%s], session open timed out.", - this.entityName)); + TRACE_LOGGER.warn(String.format(Locale.US, "SessionTimeoutHandler.onEvent - connectionId[%s], entityName[%s], session open timed out.", + this.connectionId, this.entityName)); } } } diff --git a/azure-eventhubs/src/main/java/com/microsoft/azure/eventhubs/impl/StringUtil.java b/azure-eventhubs/src/main/java/com/microsoft/azure/eventhubs/impl/StringUtil.java index e7da5dec9249..599eb81b1965 100644 --- a/azure-eventhubs/src/main/java/com/microsoft/azure/eventhubs/impl/StringUtil.java +++ b/azure-eventhubs/src/main/java/com/microsoft/azure/eventhubs/impl/StringUtil.java @@ -4,10 +4,13 @@ */ package com.microsoft.azure.eventhubs.impl; +import java.time.Instant; +import java.util.Locale; import java.util.UUID; public final class StringUtil { public final static String EMPTY = ""; + public static final String SEPARATOR = "_"; public static boolean isNullOrEmpty(String string) { return (string == null || string.isEmpty()); @@ -26,7 +29,7 @@ public static boolean isNullOrWhiteSpace(String string) { return true; } - public static String getRandomString() { - return UUID.randomUUID().toString().substring(0, 6); + public static String getRandomString(String prefix) { + return String.format(Locale.US, "%s_%s_%s", prefix, UUID.randomUUID().toString().substring(0, 6), Instant.now().toEpochMilli()); } } diff --git a/azure-eventhubs/src/main/java/com/microsoft/azure/eventhubs/impl/TrackingUtil.java b/azure-eventhubs/src/main/java/com/microsoft/azure/eventhubs/impl/TrackingUtil.java index cc20776589d3..8d425c923aa1 100644 --- a/azure-eventhubs/src/main/java/com/microsoft/azure/eventhubs/impl/TrackingUtil.java +++ b/azure-eventhubs/src/main/java/com/microsoft/azure/eventhubs/impl/TrackingUtil.java @@ -6,34 +6,18 @@ import org.apache.qpid.proton.engine.Session; -import java.time.Instant; - public final class TrackingUtil { public static final String TRACKING_ID_TOKEN_SEPARATOR = "_"; private TrackingUtil() { } - /** - * parses ServiceBus role identifiers from trackingId - * - * @return null if no roleIdentifier found - */ - static String parseRoleIdentifier(final String trackingId) { - if (StringUtil.isNullOrWhiteSpace(trackingId) || !trackingId.contains(TRACKING_ID_TOKEN_SEPARATOR)) { - return null; - } - - return trackingId.substring(trackingId.indexOf(TRACKING_ID_TOKEN_SEPARATOR)); - } - public static String getLinkName(final Session session) { - // returned linkName lookslike: ea9cac_8b_G27_1479943074829 - final String linkNamePrefix = StringUtil.getRandomString(); - final String linkNameWithServiceRoleTracker = session.getConnection() != null && !StringUtil.isNullOrEmpty(session.getConnection().getRemoteContainer()) ? + // LN_1479943074829_ea9cac_8b_G27 + final String linkNamePrefix = StringUtil.getRandomString("LN"); + return session.getConnection() != null && !StringUtil.isNullOrEmpty(session.getConnection().getRemoteContainer()) ? linkNamePrefix.concat(TrackingUtil.TRACKING_ID_TOKEN_SEPARATOR).concat(session.getConnection().getRemoteContainer() - .substring(Math.max(session.getConnection().getRemoteContainer().length() - 7, 0), session.getConnection().getRemoteContainer().length())) : + .substring(Math.max(session.getConnection().getRemoteContainer().length() - 7, 0))) : linkNamePrefix; - return linkNameWithServiceRoleTracker.concat(TrackingUtil.TRACKING_ID_TOKEN_SEPARATOR).concat(String.valueOf(Instant.now().toEpochMilli())); } } diff --git a/azure-eventhubs/src/main/java/com/microsoft/azure/eventhubs/impl/WebSocketConnectionHandler.java b/azure-eventhubs/src/main/java/com/microsoft/azure/eventhubs/impl/WebSocketConnectionHandler.java index b8ab9484b012..adfae2d7a532 100644 --- a/azure-eventhubs/src/main/java/com/microsoft/azure/eventhubs/impl/WebSocketConnectionHandler.java +++ b/azure-eventhubs/src/main/java/com/microsoft/azure/eventhubs/impl/WebSocketConnectionHandler.java @@ -14,7 +14,7 @@ public class WebSocketConnectionHandler extends ConnectionHandler { private static final Logger TRACE_LOGGER = LoggerFactory.getLogger(WebSocketConnectionHandler.class); public WebSocketConnectionHandler(AmqpConnection amqpConnection) { - super(amqpConnection); + super(amqpConnection, StringUtil.getRandomString("WS")); } @Override @@ -34,7 +34,7 @@ protected void addTransportLayers(final Event event, final TransportInternal tra transport.addTransportLayer(webSocket); if (TRACE_LOGGER.isInfoEnabled()) { - TRACE_LOGGER.info("addWebsocketHandshake: hostname[" + hostName +"]"); + TRACE_LOGGER.info("addWebsocketHandshake: hostname[" + hostName + "]"); } super.addTransportLayers(event, transport); diff --git a/azure-eventhubs/src/test/java/com/microsoft/azure/eventhubs/exceptioncontracts/SecurityExceptionsTest.java b/azure-eventhubs/src/test/java/com/microsoft/azure/eventhubs/exceptioncontracts/SecurityExceptionsTest.java index 1ce01910cd5d..6749dac9a79f 100644 --- a/azure-eventhubs/src/test/java/com/microsoft/azure/eventhubs/exceptioncontracts/SecurityExceptionsTest.java +++ b/azure-eventhubs/src/test/java/com/microsoft/azure/eventhubs/exceptioncontracts/SecurityExceptionsTest.java @@ -12,6 +12,7 @@ import org.junit.Test; import java.time.Duration; +import java.util.Locale; import java.util.UUID; public class SecurityExceptionsTest extends ApiTestBase { @@ -74,7 +75,7 @@ public void testEventHubClientUnAuthorizedAccessToken() throws Throwable { final String wrongToken = SharedAccessSignatureTokenProvider.generateSharedAccessSignature( "wrongkey", correctConnectionString.getSasKey(), - String.format("amqps://%s/%s", correctConnectionString.getEndpoint().getHost(), correctConnectionString.getEventHubName()), + String.format(Locale.US, "amqps://%s/%s", correctConnectionString.getEndpoint().getHost(), correctConnectionString.getEventHubName()), Duration.ofSeconds(10)); final ConnectionStringBuilder connectionString = new ConnectionStringBuilder() .setEndpoint(correctConnectionString.getEndpoint()) diff --git a/azure-eventhubs/src/test/java/com/microsoft/azure/eventhubs/exceptioncontracts/SendLargeMessageTest.java b/azure-eventhubs/src/test/java/com/microsoft/azure/eventhubs/exceptioncontracts/SendLargeMessageTest.java index b5cccf85c9b4..f4b22a183a7d 100644 --- a/azure-eventhubs/src/test/java/com/microsoft/azure/eventhubs/exceptioncontracts/SendLargeMessageTest.java +++ b/azure-eventhubs/src/test/java/com/microsoft/azure/eventhubs/exceptioncontracts/SendLargeMessageTest.java @@ -14,6 +14,7 @@ import java.io.IOException; import java.time.Instant; +import java.util.Locale; import java.util.concurrent.ExecutionException; public class SendLargeMessageTest extends ApiTestBase { @@ -87,7 +88,7 @@ public void sendLargeMessageTest(int msgSize) throws InterruptedException, Execu EventData recdMessage = messages.iterator().next(); Assert.assertTrue( - String.format("sent msg size: %s, recvd msg size: %s", msgSize, recdMessage.getBytes().length), + String.format(Locale.US, "sent msg size: %s, recvd msg size: %s", msgSize, recdMessage.getBytes().length), recdMessage.getBytes().length == msgSize); } } diff --git a/azure-eventhubs/src/test/java/com/microsoft/azure/eventhubs/lib/FaultInjectingReactorFactory.java b/azure-eventhubs/src/test/java/com/microsoft/azure/eventhubs/lib/FaultInjectingReactorFactory.java index d86d14b7a2e8..e9160b4b4cf2 100644 --- a/azure-eventhubs/src/test/java/com/microsoft/azure/eventhubs/lib/FaultInjectingReactorFactory.java +++ b/azure-eventhubs/src/test/java/com/microsoft/azure/eventhubs/lib/FaultInjectingReactorFactory.java @@ -21,7 +21,7 @@ public void setFaultType(final FaultType faultType) { } @Override - public Reactor create(final ReactorHandler reactorHandler, final int maxFrameSize) throws IOException { + public Reactor create(final ReactorHandler reactorHandler, final int maxFrameSize, final String name) throws IOException { final Reactor reactor = Proton.reactor(reactorHandler); switch (this.faultType) { @@ -41,6 +41,10 @@ public enum FaultType { public final static class NetworkOutageSimulator extends CustomIOHandler { + public NetworkOutageSimulator() { + super("NetworkOutageSimulator"); + } + @Override public void onUnhandled(final Event event) { switch (event.getType()) { diff --git a/azure-eventhubs/src/test/java/com/microsoft/azure/eventhubs/lib/SasTokenTestBase.java b/azure-eventhubs/src/test/java/com/microsoft/azure/eventhubs/lib/SasTokenTestBase.java index fa522e663f9d..17cc8c905448 100644 --- a/azure-eventhubs/src/test/java/com/microsoft/azure/eventhubs/lib/SasTokenTestBase.java +++ b/azure-eventhubs/src/test/java/com/microsoft/azure/eventhubs/lib/SasTokenTestBase.java @@ -11,6 +11,7 @@ import org.junit.BeforeClass; import java.time.Duration; +import java.util.Locale; public class SasTokenTestBase extends ApiTestBase { @@ -26,7 +27,7 @@ public static void replaceConnectionString() throws Exception { .setSharedAccessSignature( SharedAccessSignatureTokenProvider.generateSharedAccessSignature(originalConnectionString.getSasKeyName(), originalConnectionString.getSasKey(), - String.format("amqp://%s/%s", originalConnectionString.getEndpoint().getHost(), originalConnectionString.getEventHubName()), + String.format(Locale.US, "amqp://%s/%s", originalConnectionString.getEndpoint().getHost(), originalConnectionString.getEventHubName()), Duration.ofDays(1)) ) .toString(); diff --git a/azure-eventhubs/src/test/java/com/microsoft/azure/eventhubs/sendrecv/ReceiveParallelManualTest.java b/azure-eventhubs/src/test/java/com/microsoft/azure/eventhubs/sendrecv/ReceiveParallelManualTest.java index 86935e74148d..0cd6d971a070 100644 --- a/azure-eventhubs/src/test/java/com/microsoft/azure/eventhubs/sendrecv/ReceiveParallelManualTest.java +++ b/azure-eventhubs/src/test/java/com/microsoft/azure/eventhubs/sendrecv/ReceiveParallelManualTest.java @@ -12,6 +12,7 @@ import org.junit.AfterClass; import org.junit.BeforeClass; +import java.util.Locale; import java.util.concurrent.ExecutionException; import java.util.logging.FileHandler; import java.util.logging.Level; @@ -100,14 +101,14 @@ public void run() { long batchSize = (1 + IteratorUtil.getLast(receivedEvents.iterator()).getSystemProperties().getSequenceNumber()) - (IteratorUtil.getFirst(receivedEvents).getSystemProperties().getSequenceNumber()); totalEvents += batchSize; - System.out.println(String.format("[partitionId: %s] received %s events; total sofar: %s, begin: %s, end: %s", + System.out.println(String.format(Locale.US, "[partitionId: %s] received %s events; total sofar: %s, begin: %s, end: %s", sPartitionId, batchSize, totalEvents, IteratorUtil.getLast(receivedEvents.iterator()).getSystemProperties().getSequenceNumber(), IteratorUtil.getFirst(receivedEvents).getSystemProperties().getSequenceNumber())); } else { - System.out.println(String.format("received null on partition %s", sPartitionId)); + System.out.println(String.format(Locale.US, "received null on partition %s", sPartitionId)); } } catch (Exception exp) { System.out.println(exp.getMessage() + exp.toString()); diff --git a/azure-eventhubs/src/test/java/com/microsoft/azure/eventhubs/sendrecv/ReceiveTest.java b/azure-eventhubs/src/test/java/com/microsoft/azure/eventhubs/sendrecv/ReceiveTest.java index fe072dcf610e..dc7ad8d21dd7 100644 --- a/azure-eventhubs/src/test/java/com/microsoft/azure/eventhubs/sendrecv/ReceiveTest.java +++ b/azure-eventhubs/src/test/java/com/microsoft/azure/eventhubs/sendrecv/ReceiveTest.java @@ -14,6 +14,7 @@ import java.time.Duration; import java.time.Instant; import java.util.Iterator; +import java.util.Locale; import java.util.concurrent.ExecutionException; import java.util.function.Consumer; @@ -60,7 +61,7 @@ public void testReceiverStartOfStreamFilters() throws EventHubException { for (EventData eventDataUsingOffset : startingEventsUsingOffsetReceiver) { EventData eventDataUsingDateTime = dateTimeIterator.next(); Assert.assertTrue( - String.format("START_OF_STREAM offset: %s, EPOCH offset: %s", eventDataUsingOffset.getSystemProperties().getOffset(), eventDataUsingDateTime.getSystemProperties().getOffset()), + String.format(Locale.US, "START_OF_STREAM offset: %s, EPOCH offset: %s", eventDataUsingOffset.getSystemProperties().getOffset(), eventDataUsingDateTime.getSystemProperties().getOffset()), eventDataUsingOffset.getSystemProperties().getOffset().equalsIgnoreCase(eventDataUsingDateTime.getSystemProperties().getOffset())); if (!dateTimeIterator.hasNext()) diff --git a/azure-eventhubs/src/test/java/com/microsoft/azure/eventhubs/sendrecv/SendTest.java b/azure-eventhubs/src/test/java/com/microsoft/azure/eventhubs/sendrecv/SendTest.java index 7f4eaed43b9e..6e60a2d1e3a3 100644 --- a/azure-eventhubs/src/test/java/com/microsoft/azure/eventhubs/sendrecv/SendTest.java +++ b/azure-eventhubs/src/test/java/com/microsoft/azure/eventhubs/sendrecv/SendTest.java @@ -17,6 +17,7 @@ import java.time.Instant; import java.util.LinkedList; import java.util.List; +import java.util.Locale; import java.util.UUID; import java.util.concurrent.CompletableFuture; import java.util.concurrent.ExecutionException; @@ -166,7 +167,7 @@ public void onReceive(Iterable events) { for (EventData event : events) { if (!partitionKey.equals(event.getSystemProperties().getPartitionKey())) this.validateSignal.completeExceptionally( - new AssertionFailedError(String.format("received partitionKey: %s, expected partitionKey: %s", event.getSystemProperties().getPartitionKey(), partitionKey))); + new AssertionFailedError(String.format(Locale.US, "received partitionKey: %s, expected partitionKey: %s", event.getSystemProperties().getPartitionKey(), partitionKey))); this.currentEventCount++; } @@ -204,7 +205,7 @@ public void onReceive(Iterable events) { for (EventData event : events) { final int currentEventOrder = (int) event.getProperties().get(ORDER_PROPERTY); if (currentEventOrder != currentCount) - this.validateSignal.completeExceptionally(new AssertionError(String.format("expected %s, got %s", currentCount, currentEventOrder))); + this.validateSignal.completeExceptionally(new AssertionError(String.format(Locale.US, "expected %s, got %s", currentCount, currentEventOrder))); currentCount++; } From d54d756e74fc15162a717a10f772948150d79319 Mon Sep 17 00:00:00 2001 From: Connie Date: Fri, 26 Apr 2019 23:35:08 -0700 Subject: [PATCH 24/42] Running through java files and double checking changes --- .../EventProcessorHost.java | 1 - .../InMemoryLeaseManager.java | 6 +++ .../eventprocessorhost/PartitionScanner.java | 2 +- .../azure/eventhubs/BatchOptions.java | 4 +- .../azure/eventhubs/RetryPolicy.java | 2 +- .../azure/eventhubs/impl/CBSChannel.java | 40 ++++++++++++++++--- .../azure/eventhubs/impl/ExceptionUtil.java | 33 +++++++-------- .../azure/eventhubs/impl/MessageSender.java | 5 +-- .../azure/eventhubs/impl/ReceivePump.java | 2 +- .../eventhubs/impl/RequestResponseCloser.java | 12 +++++- .../azure/eventhubs/impl/TimeoutTracker.java | 1 - .../impl/WebSocketProxyConnectionHandler.java | 2 - .../MsgFactoryOpenCloseTest.java | 2 +- .../proxy/ProxySendLargeMessageTest.java | 1 - .../azure/eventhubs/sendrecv/SendTest.java | 10 +++-- eventhubs/data-plane/pom.xml | 4 +- 16 files changed, 84 insertions(+), 43 deletions(-) diff --git a/eventhubs/data-plane/azure-eventhubs-eph/src/main/java/com/microsoft/azure/eventprocessorhost/EventProcessorHost.java b/eventhubs/data-plane/azure-eventhubs-eph/src/main/java/com/microsoft/azure/eventprocessorhost/EventProcessorHost.java index 5270800e8502..320164d500b2 100644 --- a/eventhubs/data-plane/azure-eventhubs-eph/src/main/java/com/microsoft/azure/eventprocessorhost/EventProcessorHost.java +++ b/eventhubs/data-plane/azure-eventhubs-eph/src/main/java/com/microsoft/azure/eventprocessorhost/EventProcessorHost.java @@ -278,7 +278,6 @@ public EventProcessorHost( this.partitionManagerOptions = new PartitionManagerOptions(); } - if (executorService != null) { // User has supplied an ExecutorService, so use that. this.weOwnExecutor = false; diff --git a/eventhubs/data-plane/azure-eventhubs-eph/src/main/java/com/microsoft/azure/eventprocessorhost/InMemoryLeaseManager.java b/eventhubs/data-plane/azure-eventhubs-eph/src/main/java/com/microsoft/azure/eventprocessorhost/InMemoryLeaseManager.java index a2238c2bca9a..3b0dd0a8f5b3 100644 --- a/eventhubs/data-plane/azure-eventhubs-eph/src/main/java/com/microsoft/azure/eventprocessorhost/InMemoryLeaseManager.java +++ b/eventhubs/data-plane/azure-eventhubs-eph/src/main/java/com/microsoft/azure/eventprocessorhost/InMemoryLeaseManager.java @@ -402,6 +402,12 @@ void setExpirationTime(long expireAtMillis) { public boolean isExpiredSync() { boolean hasExpired = (System.currentTimeMillis() >= this.expirationTimeMillis); + // if (hasExpired) { + // CHANGE TO MATCH BEHAVIOR OF AzureStorageCheckpointLeaseManager + // An expired lease can be renewed by the previous owner. In order to implement that behavior for + // InMemory, the owner field has to remain unchanged. + //setOwner(""); + // } TRACE_LOGGER.debug("isExpired(" + this.getPartitionId() + (hasExpired ? ") expired " : ") leased ") + (this.expirationTimeMillis - System.currentTimeMillis())); return hasExpired; } diff --git a/eventhubs/data-plane/azure-eventhubs-eph/src/main/java/com/microsoft/azure/eventprocessorhost/PartitionScanner.java b/eventhubs/data-plane/azure-eventhubs-eph/src/main/java/com/microsoft/azure/eventprocessorhost/PartitionScanner.java index 429798d6520e..bafa1af7b381 100644 --- a/eventhubs/data-plane/azure-eventhubs-eph/src/main/java/com/microsoft/azure/eventprocessorhost/PartitionScanner.java +++ b/eventhubs/data-plane/azure-eventhubs-eph/src/main/java/com/microsoft/azure/eventprocessorhost/PartitionScanner.java @@ -312,7 +312,7 @@ private CompletableFuture stealLeases(List stealThese) { return allSteals; } - + private static class AcquisitionHolder { private CompleteLease acquiredLease; diff --git a/eventhubs/data-plane/azure-eventhubs/src/main/java/com/microsoft/azure/eventhubs/BatchOptions.java b/eventhubs/data-plane/azure-eventhubs/src/main/java/com/microsoft/azure/eventhubs/BatchOptions.java index 33c52179feeb..e7d080129050 100644 --- a/eventhubs/data-plane/azure-eventhubs/src/main/java/com/microsoft/azure/eventhubs/BatchOptions.java +++ b/eventhubs/data-plane/azure-eventhubs/src/main/java/com/microsoft/azure/eventhubs/BatchOptions.java @@ -47,14 +47,14 @@ public final class BatchOptions { * The partitionKey to use for all {@link EventData}s sent in the current {@link EventDataBatch}. * Setting a PartitionKey will deliver the {@link EventData} to a specific Event Hubs partition. */ - public String partitionKey; + public String partitionKey = null; /** * The maximum size in bytes of {@link EventDataBatch} being constructed. * This value cannot exceed the maximum size supported by Event Hubs service. * {@link EventDataBatch#tryAdd(EventData)} API will use this value as the upper limit. */ - public Integer maxMessageSize; + public Integer maxMessageSize = null; public BatchOptions with(Consumer builderFunction) { builderFunction.accept(this); diff --git a/eventhubs/data-plane/azure-eventhubs/src/main/java/com/microsoft/azure/eventhubs/RetryPolicy.java b/eventhubs/data-plane/azure-eventhubs/src/main/java/com/microsoft/azure/eventhubs/RetryPolicy.java index 541f6c716de1..b5d9f02463c6 100644 --- a/eventhubs/data-plane/azure-eventhubs/src/main/java/com/microsoft/azure/eventhubs/RetryPolicy.java +++ b/eventhubs/data-plane/azure-eventhubs/src/main/java/com/microsoft/azure/eventhubs/RetryPolicy.java @@ -56,7 +56,7 @@ public void incrementRetryCount(String clientId) { public void resetRetryCount(String clientId) { Integer currentRetryCount = this.retryCounts.get(clientId); if (currentRetryCount != null && currentRetryCount.intValue() != 0) { - this.retryCounts.replace(clientId, 0); + this.retryCounts.put(clientId, 0); } } diff --git a/eventhubs/data-plane/azure-eventhubs/src/main/java/com/microsoft/azure/eventhubs/impl/CBSChannel.java b/eventhubs/data-plane/azure-eventhubs/src/main/java/com/microsoft/azure/eventhubs/impl/CBSChannel.java index 4dcfcd6c5c38..83e4fc49a364 100644 --- a/eventhubs/data-plane/azure-eventhubs/src/main/java/com/microsoft/azure/eventhubs/impl/CBSChannel.java +++ b/eventhubs/data-plane/azure-eventhubs/src/main/java/com/microsoft/azure/eventhubs/impl/CBSChannel.java @@ -14,12 +14,17 @@ final class CBSChannel { final FaultTolerantObject innerChannel; + final SessionProvider sessionProvider; + final AmqpConnection connectionEventDispatcher; CBSChannel( final SessionProvider sessionProvider, final AmqpConnection connection, final String clientId) { + this.sessionProvider = sessionProvider; + this.connectionEventDispatcher = connection; + RequestResponseCloser closer = new RequestResponseCloser(); this.innerChannel = new FaultTolerantObject<>( new RequestResponseOpener(sessionProvider, clientId, "cbs-session", "cbs", ClientConstants.CBS_ADDRESS, connection), @@ -42,12 +47,37 @@ public void sendToken( request.setApplicationProperties(applicationProperties); request.setBody(new AmqpValue(token)); - final MessageOperationResult messageOperation = new MessageOperationResult(response -> sendTokenCallback.onComplete(null), sendTokenCallback::onError); - final OperationResultBase operation = new OperationResultBase<>( - result -> result.request(request, messageOperation), - sendTokenCallback::onError); + this.innerChannel.runOnOpenedObject(dispatcher, + new OperationResult() { + @Override + public void onComplete(final RequestResponseChannel result) { + result.request(request, + new OperationResult() { + @Override + public void onComplete(final Message response) { + + final int statusCode = (int) response.getApplicationProperties().getValue().get(ClientConstants.PUT_TOKEN_STATUS_CODE); + final String statusDescription = (String) response.getApplicationProperties().getValue().get(ClientConstants.PUT_TOKEN_STATUS_DESCRIPTION); + + if (statusCode == AmqpResponseCode.ACCEPTED.getValue() || statusCode == AmqpResponseCode.OK.getValue()) { + sendTokenCallback.onComplete(null); + } else { + this.onError(ExceptionUtil.amqpResponseCodeToException(statusCode, statusDescription)); + } + } + + @Override + public void onError(final Exception error) { + sendTokenCallback.onError(error); + } + }); + } - this.innerChannel.runOnOpenedObject(dispatcher, operation); + @Override + public void onError(Exception error) { + sendTokenCallback.onError(error); + } + }); } public void close( diff --git a/eventhubs/data-plane/azure-eventhubs/src/main/java/com/microsoft/azure/eventhubs/impl/ExceptionUtil.java b/eventhubs/data-plane/azure-eventhubs/src/main/java/com/microsoft/azure/eventhubs/impl/ExceptionUtil.java index 03a01f592822..0cdccfc092da 100644 --- a/eventhubs/data-plane/azure-eventhubs/src/main/java/com/microsoft/azure/eventhubs/impl/ExceptionUtil.java +++ b/eventhubs/data-plane/azure-eventhubs/src/main/java/com/microsoft/azure/eventhubs/impl/ExceptionUtil.java @@ -4,6 +4,7 @@ package com.microsoft.azure.eventhubs.impl; import com.microsoft.azure.eventhubs.AuthorizationFailedException; +import com.microsoft.azure.eventhubs.CommunicationException; import com.microsoft.azure.eventhubs.ErrorContext; import com.microsoft.azure.eventhubs.EventHubException; import com.microsoft.azure.eventhubs.IllegalEntityException; @@ -63,11 +64,11 @@ static Exception toException(ErrorCondition errorCondition) { } else if (errorCondition.getCondition() == AmqpErrorCode.ResourceLimitExceeded) { return new QuotaExceededException(new AmqpException(errorCondition)); } else if (errorCondition.getCondition() == ClientConstants.PROTON_IO_ERROR) { - String message = ClientConstants.COMMUNICATION_EXCEPTION_GENERIC_MESSAGE; - if (errorCondition.getDescription() != null) { - message = errorCondition.getDescription(); - } - return new CommunicationException(message, null); + String message = ClientConstants.COMMUNICATION_EXCEPTION_GENERIC_MESSAGE; + if (errorCondition.getDescription() != null) { + message = errorCondition.getDescription(); + } + return new CommunicationException(message, null); } return new EventHubException(ClientConstants.DEFAULT_IS_TRANSIENT, errorCondition.getDescription()); @@ -103,11 +104,7 @@ static Exception distinguishNotFound(final String message) { } static void completeExceptionally(CompletableFuture future, Exception exception, ErrorContextProvider contextProvider) { - if (exception == null) { - throw new NullPointerException(); - } - - if (exception instanceof EventHubException) { + if (exception != null && exception instanceof EventHubException) { final ErrorContext errorContext = contextProvider.getContext(); ((EventHubException) exception).setContext(errorContext); } @@ -136,18 +133,22 @@ public static String toStackTraceString(final Throwable exception, final String builder.append(exception.getMessage()); final StackTraceElement[] stackTraceElements = exception.getStackTrace(); - for (final StackTraceElement ste : stackTraceElements) { - builder.append(System.lineSeparator()); - builder.append(ste.toString()); + if (stackTraceElements != null) { + for (final StackTraceElement ste : stackTraceElements) { + builder.append(System.lineSeparator()); + builder.append(ste.toString()); + } } final Throwable innerException = exception.getCause(); if (innerException != null) { builder.append("Cause: " + innerException.getMessage()); final StackTraceElement[] innerStackTraceElements = innerException.getStackTrace(); - for (final StackTraceElement ste : innerStackTraceElements) { - builder.append(System.lineSeparator()); - builder.append(ste.toString()); + if (innerStackTraceElements != null) { + for (final StackTraceElement ste : innerStackTraceElements) { + builder.append(System.lineSeparator()); + builder.append(ste.toString()); + } } } diff --git a/eventhubs/data-plane/azure-eventhubs/src/main/java/com/microsoft/azure/eventhubs/impl/MessageSender.java b/eventhubs/data-plane/azure-eventhubs/src/main/java/com/microsoft/azure/eventhubs/impl/MessageSender.java index 3ec5c6e4b9da..e362ed7b9db1 100644 --- a/eventhubs/data-plane/azure-eventhubs/src/main/java/com/microsoft/azure/eventhubs/impl/MessageSender.java +++ b/eventhubs/data-plane/azure-eventhubs/src/main/java/com/microsoft/azure/eventhubs/impl/MessageSender.java @@ -1028,10 +1028,7 @@ public int getPriority() { } } - private static class DeliveryTagComparator implements Comparator, Serializable { - - private static final long serialVersionUID = -7057500582037295635L; - + private static class DeliveryTagComparator implements Comparator { @Override public int compare(WeightedDeliveryTag deliveryTag0, WeightedDeliveryTag deliveryTag1) { return deliveryTag1.getPriority() - deliveryTag0.getPriority(); diff --git a/eventhubs/data-plane/azure-eventhubs/src/main/java/com/microsoft/azure/eventhubs/impl/ReceivePump.java b/eventhubs/data-plane/azure-eventhubs/src/main/java/com/microsoft/azure/eventhubs/impl/ReceivePump.java index 8590de6cebab..67125602db7b 100644 --- a/eventhubs/data-plane/azure-eventhubs/src/main/java/com/microsoft/azure/eventhubs/impl/ReceivePump.java +++ b/eventhubs/data-plane/azure-eventhubs/src/main/java/com/microsoft/azure/eventhubs/impl/ReceivePump.java @@ -163,7 +163,7 @@ public Void apply(final Iterable receivedEvents, final Throwable clie // don't invoke user call back - if stop is already raised / pump is unhealthy if (ReceivePump.this.shouldContinue() && (receivedEvents != null - || ReceivePump.this.invokeOnTimeout)) { + || (receivedEvents == null && ReceivePump.this.invokeOnTimeout))) { ReceivePump.this.onReceiveHandler.onReceive(receivedEvents); } } catch (final Throwable userCodeError) { diff --git a/eventhubs/data-plane/azure-eventhubs/src/main/java/com/microsoft/azure/eventhubs/impl/RequestResponseCloser.java b/eventhubs/data-plane/azure-eventhubs/src/main/java/com/microsoft/azure/eventhubs/impl/RequestResponseCloser.java index 99d56495fccf..a481bf9ca110 100644 --- a/eventhubs/data-plane/azure-eventhubs/src/main/java/com/microsoft/azure/eventhubs/impl/RequestResponseCloser.java +++ b/eventhubs/data-plane/azure-eventhubs/src/main/java/com/microsoft/azure/eventhubs/impl/RequestResponseCloser.java @@ -20,7 +20,17 @@ public void run(OperationResult closeOperationCallback) { if (channelToBeClosed == null) { closeOperationCallback.onComplete(null); } else { - channelToBeClosed.close(new OperationResultBase<>(closeOperationCallback::onComplete, closeOperationCallback::onError)); + channelToBeClosed.close(new OperationResult() { + @Override + public void onComplete(Void result) { + closeOperationCallback.onComplete(result); + } + + @Override + public void onError(Exception error) { + closeOperationCallback.onError(error); + } + }); } } } diff --git a/eventhubs/data-plane/azure-eventhubs/src/main/java/com/microsoft/azure/eventhubs/impl/TimeoutTracker.java b/eventhubs/data-plane/azure-eventhubs/src/main/java/com/microsoft/azure/eventhubs/impl/TimeoutTracker.java index 8a52e6bc2883..eb63d0b4af8d 100644 --- a/eventhubs/data-plane/azure-eventhubs/src/main/java/com/microsoft/azure/eventhubs/impl/TimeoutTracker.java +++ b/eventhubs/data-plane/azure-eventhubs/src/main/java/com/microsoft/azure/eventhubs/impl/TimeoutTracker.java @@ -3,7 +3,6 @@ package com.microsoft.azure.eventhubs.impl; - import java.time.Duration; import java.time.Instant; diff --git a/eventhubs/data-plane/azure-eventhubs/src/main/java/com/microsoft/azure/eventhubs/impl/WebSocketProxyConnectionHandler.java b/eventhubs/data-plane/azure-eventhubs/src/main/java/com/microsoft/azure/eventhubs/impl/WebSocketProxyConnectionHandler.java index 0d7ca7c76828..56b6d536323c 100644 --- a/eventhubs/data-plane/azure-eventhubs/src/main/java/com/microsoft/azure/eventhubs/impl/WebSocketProxyConnectionHandler.java +++ b/eventhubs/data-plane/azure-eventhubs/src/main/java/com/microsoft/azure/eventhubs/impl/WebSocketProxyConnectionHandler.java @@ -28,8 +28,6 @@ import java.util.List; import java.util.Map; -import static java.nio.charset.StandardCharsets.UTF_8; - public class WebSocketProxyConnectionHandler extends WebSocketConnectionHandler { private static final Logger TRACE_LOGGER = LoggerFactory.getLogger(WebSocketProxyConnectionHandler.class); private final String proxySelectorModifiedError = "ProxySelector has been modified."; diff --git a/eventhubs/data-plane/azure-eventhubs/src/test/java/com/microsoft/azure/eventhubs/exceptioncontracts/MsgFactoryOpenCloseTest.java b/eventhubs/data-plane/azure-eventhubs/src/test/java/com/microsoft/azure/eventhubs/exceptioncontracts/MsgFactoryOpenCloseTest.java index edd793a63050..63034912d1ab 100644 --- a/eventhubs/data-plane/azure-eventhubs/src/test/java/com/microsoft/azure/eventhubs/exceptioncontracts/MsgFactoryOpenCloseTest.java +++ b/eventhubs/data-plane/azure-eventhubs/src/test/java/com/microsoft/azure/eventhubs/exceptioncontracts/MsgFactoryOpenCloseTest.java @@ -275,7 +275,7 @@ public void SupplyClosedExecutorServiceThenSenderCloseOperation() throws Excepti @Test(expected = RejectedExecutionException.class) public void SupplyClosedExecutorServiceThenReceiverCloseOperation() throws Exception { - final ExecutorService testClosed = Executors.newWorkStealingPool(); + final ScheduledExecutorService testClosed = Executors.newScheduledThreadPool(1); final PartitionReceiver temp = EventHubClient.createSync( TestContext.getConnectionString().toString(), diff --git a/eventhubs/data-plane/azure-eventhubs/src/test/java/com/microsoft/azure/eventhubs/proxy/ProxySendLargeMessageTest.java b/eventhubs/data-plane/azure-eventhubs/src/test/java/com/microsoft/azure/eventhubs/proxy/ProxySendLargeMessageTest.java index ac82d2ad6def..dedff0202df7 100644 --- a/eventhubs/data-plane/azure-eventhubs/src/test/java/com/microsoft/azure/eventhubs/proxy/ProxySendLargeMessageTest.java +++ b/eventhubs/data-plane/azure-eventhubs/src/test/java/com/microsoft/azure/eventhubs/proxy/ProxySendLargeMessageTest.java @@ -14,7 +14,6 @@ import org.junit.AfterClass; import org.junit.BeforeClass; import org.junit.Test; -import org.jutils.jproxy.ProxyServer; import java.io.IOException; import java.net.InetSocketAddress; diff --git a/eventhubs/data-plane/azure-eventhubs/src/test/java/com/microsoft/azure/eventhubs/sendrecv/SendTest.java b/eventhubs/data-plane/azure-eventhubs/src/test/java/com/microsoft/azure/eventhubs/sendrecv/SendTest.java index c3eb6c394b9e..114cca077839 100644 --- a/eventhubs/data-plane/azure-eventhubs/src/test/java/com/microsoft/azure/eventhubs/sendrecv/SendTest.java +++ b/eventhubs/data-plane/azure-eventhubs/src/test/java/com/microsoft/azure/eventhubs/sendrecv/SendTest.java @@ -44,6 +44,7 @@ public static void initialize() throws Exception { final ConnectionStringBuilder connectionString = TestContext.getConnectionString(); initializeEventHub(connectionString); } + public static void initializeEventHub(final ConnectionStringBuilder connectionString) throws Exception { ehClient = EventHubClient.createSync(connectionString.toString(), TestContext.EXECUTOR_SERVICE); } @@ -178,11 +179,12 @@ public void onReceive(Iterable events) { this.validateSignal.completeExceptionally( new AssertionFailedError(String.format(Locale.US, "received partitionKey: %s, expected partitionKey: %s", event.getSystemProperties().getPartitionKey(), partitionKey))); - this.currentEventCount++; - } + this.currentEventCount++; + } - if (this.currentEventCount == this.eventCount) { - this.validateSignal.complete(null); + if (this.currentEventCount == this.eventCount) { + this.validateSignal.complete(null); + } } } } diff --git a/eventhubs/data-plane/pom.xml b/eventhubs/data-plane/pom.xml index e63a80368774..f23a3854f043 100644 --- a/eventhubs/data-plane/pom.xml +++ b/eventhubs/data-plane/pom.xml @@ -56,12 +56,12 @@ slf4j-simple test - + From d567ad97033827727e7252c83b33b2a64473891e Mon Sep 17 00:00:00 2001 From: Connie Date: Fri, 26 Apr 2019 21:58:50 -0700 Subject: [PATCH 25/42] Fix casing on test names --- .../MsgFactoryOpenCloseTest.java | 20 +++++++++---------- .../exceptioncontracts/ReactorFaultTest.java | 2 +- 2 files changed, 11 insertions(+), 11 deletions(-) diff --git a/eventhubs/data-plane/azure-eventhubs/src/test/java/com/microsoft/azure/eventhubs/exceptioncontracts/MsgFactoryOpenCloseTest.java b/eventhubs/data-plane/azure-eventhubs/src/test/java/com/microsoft/azure/eventhubs/exceptioncontracts/MsgFactoryOpenCloseTest.java index 63034912d1ab..8d048b08dfdf 100644 --- a/eventhubs/data-plane/azure-eventhubs/src/test/java/com/microsoft/azure/eventhubs/exceptioncontracts/MsgFactoryOpenCloseTest.java +++ b/eventhubs/data-plane/azure-eventhubs/src/test/java/com/microsoft/azure/eventhubs/exceptioncontracts/MsgFactoryOpenCloseTest.java @@ -145,7 +145,7 @@ public void verifyThreadReleaseOnMsgFactoryOpenError() throws Exception { } @Test(expected = RejectedExecutionException.class) - public void SupplyClosedExecutorServiceToEventHubClient() throws Exception { + public void supplyClosedExecutorServiceToEventHubClient() throws Exception { final ScheduledExecutorService testClosed = new ScheduledThreadPoolExecutor(1); testClosed.shutdown(); @@ -155,7 +155,7 @@ public void SupplyClosedExecutorServiceToEventHubClient() throws Exception { } @Test(expected = RejectedExecutionException.class) - public void SupplyClosedExecutorServiceToSendOperation() throws Exception { + public void supplyClosedExecutorServiceToSendOperation() throws Exception { final ScheduledExecutorService testClosed = Executors.newScheduledThreadPool(1); final EventHubClient temp = EventHubClient.createSync( @@ -170,7 +170,7 @@ public void SupplyClosedExecutorServiceToSendOperation() throws Exception { } @Test(expected = RejectedExecutionException.class) - public void SupplyClosedExecutorServiceToReceiveOperation() throws Exception { + public void supplyClosedExecutorServiceToReceiveOperation() throws Exception { final ScheduledExecutorService testClosed = new ScheduledThreadPoolExecutor(1); final PartitionReceiver temp = EventHubClient.createSync( @@ -185,7 +185,7 @@ public void SupplyClosedExecutorServiceToReceiveOperation() throws Exception { } @Test(expected = RejectedExecutionException.class) - public void SupplyClosedExecutorServiceToCreateLinkOperation() throws Exception { + public void supplyClosedExecutorServiceToCreateLinkOperation() throws Exception { final ScheduledExecutorService testClosed = Executors.newScheduledThreadPool(1); final EventHubClient temp = EventHubClient.createSync( @@ -200,7 +200,7 @@ public void SupplyClosedExecutorServiceToCreateLinkOperation() throws Exception } @Test(expected = RejectedExecutionException.class) - public void SupplyClosedExecutorServiceToCreateSenderOperation() throws Exception { + public void supplyClosedExecutorServiceToCreateSenderOperation() throws Exception { final ScheduledExecutorService testClosed = new ScheduledThreadPoolExecutor(1); final EventHubClient temp = EventHubClient.createSync( @@ -214,7 +214,7 @@ public void SupplyClosedExecutorServiceToCreateSenderOperation() throws Exceptio } @Test(expected = RejectedExecutionException.class) - public void SupplyClosedExecutorServiceToCreateReceiverOperation() throws Exception { + public void supplyClosedExecutorServiceToCreateReceiverOperation() throws Exception { final ScheduledExecutorService testClosed = Executors.newScheduledThreadPool(1); final EventHubClient temp = EventHubClient.createSync( @@ -228,7 +228,7 @@ public void SupplyClosedExecutorServiceToCreateReceiverOperation() throws Except } @Test(expected = RejectedExecutionException.class) - public void SupplyClosedExecutorServiceThenMgmtOperation() throws Throwable { + public void supplyClosedExecutorServiceThenMgmtOperation() throws Throwable { final ScheduledThreadPoolExecutor testClosed = new ScheduledThreadPoolExecutor(1); final EventHubClient temp = EventHubClient.createSync( @@ -246,7 +246,7 @@ public void SupplyClosedExecutorServiceThenMgmtOperation() throws Throwable { } @Test(expected = RejectedExecutionException.class) - public void SupplyClosedExecutorServiceThenFactoryCloseOperation() throws Exception { + public void supplyClosedExecutorServiceThenFactoryCloseOperation() throws Exception { final ScheduledExecutorService testClosed = Executors.newScheduledThreadPool(1); final EventHubClient temp = EventHubClient.createSync( @@ -260,7 +260,7 @@ public void SupplyClosedExecutorServiceThenFactoryCloseOperation() throws Except } @Test(expected = RejectedExecutionException.class) - public void SupplyClosedExecutorServiceThenSenderCloseOperation() throws Exception { + public void supplyClosedExecutorServiceThenSenderCloseOperation() throws Exception { final ScheduledThreadPoolExecutor testClosed = new ScheduledThreadPoolExecutor(1); final PartitionSender temp = EventHubClient.createSync( @@ -274,7 +274,7 @@ public void SupplyClosedExecutorServiceThenSenderCloseOperation() throws Excepti } @Test(expected = RejectedExecutionException.class) - public void SupplyClosedExecutorServiceThenReceiverCloseOperation() throws Exception { + public void supplyClosedExecutorServiceThenReceiverCloseOperation() throws Exception { final ScheduledExecutorService testClosed = Executors.newScheduledThreadPool(1); final PartitionReceiver temp = EventHubClient.createSync( diff --git a/eventhubs/data-plane/azure-eventhubs/src/test/java/com/microsoft/azure/eventhubs/exceptioncontracts/ReactorFaultTest.java b/eventhubs/data-plane/azure-eventhubs/src/test/java/com/microsoft/azure/eventhubs/exceptioncontracts/ReactorFaultTest.java index f59a5bb783db..d8973a721bcf 100644 --- a/eventhubs/data-plane/azure-eventhubs/src/test/java/com/microsoft/azure/eventhubs/exceptioncontracts/ReactorFaultTest.java +++ b/eventhubs/data-plane/azure-eventhubs/src/test/java/com/microsoft/azure/eventhubs/exceptioncontracts/ReactorFaultTest.java @@ -81,7 +81,7 @@ public void handle(org.apache.qpid.proton.engine.Event e) { } @Test() - public void VerifyTransportAbort() throws Exception { + public void verifyTransportAbort() throws Exception { final EventHubClient eventHubClient = EventHubClient.createSync(connStr.toString(), TestContext.EXECUTOR_SERVICE); try { final PartitionReceiver partitionReceiver = eventHubClient.createEpochReceiverSync( From 6bba56ee57e24e3589295d15ad21b40923d8a1d0 Mon Sep 17 00:00:00 2001 From: Connie Date: Fri, 26 Apr 2019 22:15:34 -0700 Subject: [PATCH 26/42] Fixing checkstyle issues. --- .../microsoft/azure/eventhubs/EventData.java | 2 +- .../azure/eventhubs/EventHubClient.java | 1 - .../azure/eventhubs/impl/EventDataImpl.java | 2 +- .../eventhubs/impl/FaultTolerantObject.java | 6 ++++-- .../azure/eventhubs/impl/MessageReceiver.java | 4 ++-- .../azure/eventhubs/impl/MessageSender.java | 19 +++++++++---------- .../eventhubs/impl/MessagingFactory.java | 4 ++-- .../azure/eventhubs/impl/ReceivePump.java | 8 ++++---- .../azure/eventhubs/impl/SendLinkHandler.java | 2 -- .../azure/eventhubs/impl/TrackingUtil.java | 8 ++++---- .../impl/WebSocketProxyConnectionHandler.java | 6 ------ .../exceptioncontracts/ReactorFaultTest.java | 2 +- .../eventhubs/impl/EventDataOrderTest.java | 2 +- 13 files changed, 29 insertions(+), 37 deletions(-) diff --git a/eventhubs/data-plane/azure-eventhubs/src/main/java/com/microsoft/azure/eventhubs/EventData.java b/eventhubs/data-plane/azure-eventhubs/src/main/java/com/microsoft/azure/eventhubs/EventData.java index f028ec9d0ba3..e2091f2977e6 100755 --- a/eventhubs/data-plane/azure-eventhubs/src/main/java/com/microsoft/azure/eventhubs/EventData.java +++ b/eventhubs/data-plane/azure-eventhubs/src/main/java/com/microsoft/azure/eventhubs/EventData.java @@ -149,7 +149,7 @@ static EventData create(final ByteBuffer buffer) { SystemProperties getSystemProperties(); void setSystemProperties(SystemProperties props); - public class SystemProperties extends HashMap { + class SystemProperties extends HashMap { private static final long serialVersionUID = -2827050124966993723L; public SystemProperties(final HashMap map) { diff --git a/eventhubs/data-plane/azure-eventhubs/src/main/java/com/microsoft/azure/eventhubs/EventHubClient.java b/eventhubs/data-plane/azure-eventhubs/src/main/java/com/microsoft/azure/eventhubs/EventHubClient.java index ae89c987a82b..ea49239ed07e 100644 --- a/eventhubs/data-plane/azure-eventhubs/src/main/java/com/microsoft/azure/eventhubs/EventHubClient.java +++ b/eventhubs/data-plane/azure-eventhubs/src/main/java/com/microsoft/azure/eventhubs/EventHubClient.java @@ -9,7 +9,6 @@ import java.io.IOException; import java.nio.channels.UnresolvedAddressException; import java.util.concurrent.CompletableFuture; -import java.util.concurrent.Executor; import java.util.concurrent.ScheduledExecutorService; /** diff --git a/eventhubs/data-plane/azure-eventhubs/src/main/java/com/microsoft/azure/eventhubs/impl/EventDataImpl.java b/eventhubs/data-plane/azure-eventhubs/src/main/java/com/microsoft/azure/eventhubs/impl/EventDataImpl.java index 0a49ad2c3eca..b4294435f7e0 100755 --- a/eventhubs/data-plane/azure-eventhubs/src/main/java/com/microsoft/azure/eventhubs/impl/EventDataImpl.java +++ b/eventhubs/data-plane/azure-eventhubs/src/main/java/com/microsoft/azure/eventhubs/impl/EventDataImpl.java @@ -166,7 +166,7 @@ public SystemProperties getSystemProperties() { } public void setSystemProperties(EventData.SystemProperties props) { - this.systemProperties = props; + this.systemProperties = props; } // This is intended to be used while sending EventData - so EventData.SystemProperties will not be copied over to the AmqpMessage diff --git a/eventhubs/data-plane/azure-eventhubs/src/main/java/com/microsoft/azure/eventhubs/impl/FaultTolerantObject.java b/eventhubs/data-plane/azure-eventhubs/src/main/java/com/microsoft/azure/eventhubs/impl/FaultTolerantObject.java index 3e8ea4bc8cb4..01e9006950c0 100644 --- a/eventhubs/data-plane/azure-eventhubs/src/main/java/com/microsoft/azure/eventhubs/impl/FaultTolerantObject.java +++ b/eventhubs/data-plane/azure-eventhubs/src/main/java/com/microsoft/azure/eventhubs/impl/FaultTolerantObject.java @@ -56,16 +56,18 @@ public void onEvent() { @Override public void onComplete(T result) { innerObject = result; - for (OperationResult callback : openCallbacks) + for (OperationResult callback : openCallbacks) { callback.onComplete(result); + } openCallbacks.clear(); } @Override public void onError(Exception error) { - for (OperationResult callback : openCallbacks) + for (OperationResult callback : openCallbacks) { callback.onError(error); + } openCallbacks.clear(); } diff --git a/eventhubs/data-plane/azure-eventhubs/src/main/java/com/microsoft/azure/eventhubs/impl/MessageReceiver.java b/eventhubs/data-plane/azure-eventhubs/src/main/java/com/microsoft/azure/eventhubs/impl/MessageReceiver.java index 353b88615bd9..655709389517 100644 --- a/eventhubs/data-plane/azure-eventhubs/src/main/java/com/microsoft/azure/eventhubs/impl/MessageReceiver.java +++ b/eventhubs/data-plane/azure-eventhubs/src/main/java/com/microsoft/azure/eventhubs/impl/MessageReceiver.java @@ -643,8 +643,8 @@ private void sendFlow(final int credits) { } private boolean shouldSendFlow() { - return (this.nextCreditToFlow > 0 && this.nextCreditToFlow >= (this.prefetchCount / 2)) || - (this.nextCreditToFlow >= 100); + return (this.nextCreditToFlow > 0 && this.nextCreditToFlow >= (this.prefetchCount / 2)) + || (this.nextCreditToFlow >= 100); } private void scheduleLinkOpenTimeout(final TimeoutTracker timeout) { diff --git a/eventhubs/data-plane/azure-eventhubs/src/main/java/com/microsoft/azure/eventhubs/impl/MessageSender.java b/eventhubs/data-plane/azure-eventhubs/src/main/java/com/microsoft/azure/eventhubs/impl/MessageSender.java index e362ed7b9db1..fcb73da336aa 100644 --- a/eventhubs/data-plane/azure-eventhubs/src/main/java/com/microsoft/azure/eventhubs/impl/MessageSender.java +++ b/eventhubs/data-plane/azure-eventhubs/src/main/java/com/microsoft/azure/eventhubs/impl/MessageSender.java @@ -33,7 +33,6 @@ import org.slf4j.LoggerFactory; import java.io.IOException; -import java.io.Serializable; import java.nio.BufferOverflowException; import java.security.InvalidKeyException; import java.security.NoSuchAlgorithmException; @@ -225,15 +224,15 @@ private CompletableFuture sendCore( // if the timeoutTask completed with scheduling error - notify sender if (timeoutTimerTask.isCompletedExceptionally()) { timeoutTimerTask.handleAsync( - (unUsed, exception) -> { - if (exception != null && !(exception instanceof CancellationException)) { - onSendFuture.completeExceptionally( - new OperationCancelledException(String.format(Locale.US, - "Entity(%s): send failed while dispatching to Reactor, see cause for more details.", - this.sendPath), exception)); - } - return null; - }, this.executor); + (unUsed, exception) -> { + if (exception != null && !(exception instanceof CancellationException)) { + onSendFuture.completeExceptionally( + new OperationCancelledException(String.format(Locale.US, + "Entity(%s): send failed while dispatching to Reactor, see cause for more details.", + this.sendPath), exception)); + } + return null; + }, this.executor); return onSendFuture; } diff --git a/eventhubs/data-plane/azure-eventhubs/src/main/java/com/microsoft/azure/eventhubs/impl/MessagingFactory.java b/eventhubs/data-plane/azure-eventhubs/src/main/java/com/microsoft/azure/eventhubs/impl/MessagingFactory.java index 0d50dc16a873..b9eb702370fa 100644 --- a/eventhubs/data-plane/azure-eventhubs/src/main/java/com/microsoft/azure/eventhubs/impl/MessagingFactory.java +++ b/eventhubs/data-plane/azure-eventhubs/src/main/java/com/microsoft/azure/eventhubs/impl/MessagingFactory.java @@ -499,8 +499,8 @@ public void onError(Exception error) { } private class RunReactor implements Runnable { - final private Reactor rctr; - final private ScheduledExecutorService executor; + private final Reactor rctr; + private final ScheduledExecutorService executor; volatile boolean hasStarted; diff --git a/eventhubs/data-plane/azure-eventhubs/src/main/java/com/microsoft/azure/eventhubs/impl/ReceivePump.java b/eventhubs/data-plane/azure-eventhubs/src/main/java/com/microsoft/azure/eventhubs/impl/ReceivePump.java index 67125602db7b..0144343cbe05 100644 --- a/eventhubs/data-plane/azure-eventhubs/src/main/java/com/microsoft/azure/eventhubs/impl/ReceivePump.java +++ b/eventhubs/data-plane/azure-eventhubs/src/main/java/com/microsoft/azure/eventhubs/impl/ReceivePump.java @@ -56,8 +56,8 @@ public void run() { } catch (final Exception exception) { if (TRACE_LOGGER.isErrorEnabled()) { TRACE_LOGGER.error( - String.format(Locale.US, "Receive pump for eventHub (%s), consumerGroup (%s), partition (%s) " + - "encountered unrecoverable error and exited with exception %s.", + String.format(Locale.US, "Receive pump for eventHub (%s), consumerGroup (%s), partition (%s) " + + "encountered unrecoverable error and exited with exception %s.", this.eventHubName, this.consumerGroupName, this.receiver.getPartitionId(), exception.toString())); } @@ -112,8 +112,8 @@ private void handleUserCodeExceptions(final Throwable userCodeException) { this.isPumpHealthy = false; if (TRACE_LOGGER.isErrorEnabled()) { TRACE_LOGGER.error( - String.format(Locale.US, "Receive pump for eventHub (%s), consumerGroup (%s), partition (%s) " + - "exiting after user-code exception %s", + String.format(Locale.US, "Receive pump for eventHub (%s), consumerGroup (%s), partition (%s) " + + "exiting after user-code exception %s", this.eventHubName, this.consumerGroupName, this.receiver.getPartitionId(), userCodeException.toString())); } diff --git a/eventhubs/data-plane/azure-eventhubs/src/main/java/com/microsoft/azure/eventhubs/impl/SendLinkHandler.java b/eventhubs/data-plane/azure-eventhubs/src/main/java/com/microsoft/azure/eventhubs/impl/SendLinkHandler.java index 4c09b188be8c..73e723ef249e 100644 --- a/eventhubs/data-plane/azure-eventhubs/src/main/java/com/microsoft/azure/eventhubs/impl/SendLinkHandler.java +++ b/eventhubs/data-plane/azure-eventhubs/src/main/java/com/microsoft/azure/eventhubs/impl/SendLinkHandler.java @@ -13,8 +13,6 @@ import java.util.Locale; import java.util.concurrent.atomic.AtomicBoolean; -import static java.nio.charset.StandardCharsets.UTF_8; - public class SendLinkHandler extends BaseLinkHandler { private static final Logger TRACE_LOGGER = LoggerFactory.getLogger(SendLinkHandler.class); private final AmqpSender msgSender; diff --git a/eventhubs/data-plane/azure-eventhubs/src/main/java/com/microsoft/azure/eventhubs/impl/TrackingUtil.java b/eventhubs/data-plane/azure-eventhubs/src/main/java/com/microsoft/azure/eventhubs/impl/TrackingUtil.java index c1d13cebe1bb..fe40e2eb68a8 100644 --- a/eventhubs/data-plane/azure-eventhubs/src/main/java/com/microsoft/azure/eventhubs/impl/TrackingUtil.java +++ b/eventhubs/data-plane/azure-eventhubs/src/main/java/com/microsoft/azure/eventhubs/impl/TrackingUtil.java @@ -14,9 +14,9 @@ private TrackingUtil() { public static String getLinkName(final Session session) { // LN_1479943074829_ea9cac_8b_G27 final String linkNamePrefix = StringUtil.getRandomString("LN"); - return session.getConnection() != null && !StringUtil.isNullOrEmpty(session.getConnection().getRemoteContainer()) ? - linkNamePrefix.concat(TrackingUtil.TRACKING_ID_TOKEN_SEPARATOR).concat(session.getConnection().getRemoteContainer() - .substring(Math.max(session.getConnection().getRemoteContainer().length() - 7, 0))) : - linkNamePrefix; + return session.getConnection() != null && !StringUtil.isNullOrEmpty(session.getConnection().getRemoteContainer()) + ? linkNamePrefix.concat(TrackingUtil.TRACKING_ID_TOKEN_SEPARATOR).concat(session.getConnection().getRemoteContainer() + .substring(Math.max(session.getConnection().getRemoteContainer().length() - 7, 0))) + : linkNamePrefix; } } diff --git a/eventhubs/data-plane/azure-eventhubs/src/main/java/com/microsoft/azure/eventhubs/impl/WebSocketProxyConnectionHandler.java b/eventhubs/data-plane/azure-eventhubs/src/main/java/com/microsoft/azure/eventhubs/impl/WebSocketProxyConnectionHandler.java index 56b6d536323c..e7d512bcd3a3 100644 --- a/eventhubs/data-plane/azure-eventhubs/src/main/java/com/microsoft/azure/eventhubs/impl/WebSocketProxyConnectionHandler.java +++ b/eventhubs/data-plane/azure-eventhubs/src/main/java/com/microsoft/azure/eventhubs/impl/WebSocketProxyConnectionHandler.java @@ -6,7 +6,6 @@ import com.microsoft.azure.proton.transport.proxy.ProxyHandler; import com.microsoft.azure.proton.transport.proxy.impl.ProxyHandlerImpl; import com.microsoft.azure.proton.transport.proxy.impl.ProxyImpl; - import org.apache.qpid.proton.amqp.transport.ConnectionError; import org.apache.qpid.proton.amqp.transport.ErrorCondition; import org.apache.qpid.proton.engine.Connection; @@ -17,16 +16,11 @@ import org.slf4j.LoggerFactory; import java.io.IOException; -import java.net.Authenticator; import java.net.InetSocketAddress; -import java.net.PasswordAuthentication; import java.net.Proxy; import java.net.ProxySelector; import java.net.URI; -import java.util.Base64; -import java.util.HashMap; import java.util.List; -import java.util.Map; public class WebSocketProxyConnectionHandler extends WebSocketConnectionHandler { private static final Logger TRACE_LOGGER = LoggerFactory.getLogger(WebSocketProxyConnectionHandler.class); diff --git a/eventhubs/data-plane/azure-eventhubs/src/test/java/com/microsoft/azure/eventhubs/exceptioncontracts/ReactorFaultTest.java b/eventhubs/data-plane/azure-eventhubs/src/test/java/com/microsoft/azure/eventhubs/exceptioncontracts/ReactorFaultTest.java index d8973a721bcf..f6069ef6f14d 100644 --- a/eventhubs/data-plane/azure-eventhubs/src/test/java/com/microsoft/azure/eventhubs/exceptioncontracts/ReactorFaultTest.java +++ b/eventhubs/data-plane/azure-eventhubs/src/test/java/com/microsoft/azure/eventhubs/exceptioncontracts/ReactorFaultTest.java @@ -58,7 +58,7 @@ public void run() { handler.add(new BaseHandler() { @Override public void handle(org.apache.qpid.proton.engine.Event e) { - throw new NullPointerException(); + throw new NullPointerException("The test exception. We want this to restart."); } }); } catch (Exception e) { diff --git a/eventhubs/data-plane/azure-eventhubs/src/test/java/com/microsoft/azure/eventhubs/impl/EventDataOrderTest.java b/eventhubs/data-plane/azure-eventhubs/src/test/java/com/microsoft/azure/eventhubs/impl/EventDataOrderTest.java index 377090fc21c5..7aeb67795a96 100644 --- a/eventhubs/data-plane/azure-eventhubs/src/test/java/com/microsoft/azure/eventhubs/impl/EventDataOrderTest.java +++ b/eventhubs/data-plane/azure-eventhubs/src/test/java/com/microsoft/azure/eventhubs/impl/EventDataOrderTest.java @@ -16,7 +16,7 @@ public class EventDataOrderTest { - private EventData constructMessage(long seqNumber) { + private EventData constructMessage(long seqNumber) { HashMap properties = new HashMap<>(); properties.put(AmqpConstants.SEQUENCE_NUMBER, seqNumber); From 49ab1a9cf25a82888405072df8ddd7d82104d0ac Mon Sep 17 00:00:00 2001 From: Connie Date: Fri, 26 Apr 2019 22:41:05 -0700 Subject: [PATCH 27/42] SpotBug fixes. --- .../azure/eventhubs/BatchOptions.java | 4 +-- .../azure/eventhubs/RetryPolicy.java | 2 +- .../azure/eventhubs/impl/CBSChannel.java | 5 ---- .../azure/eventhubs/impl/ExceptionUtil.java | 28 +++++++++---------- .../eventhubs/impl/ManagementChannel.java | 4 --- .../azure/eventhubs/impl/MessageSender.java | 6 +++- .../azure/eventhubs/impl/ReceivePump.java | 2 +- .../azure/eventhubs/impl/SendLinkHandler.java | 3 +- .../azure/eventhubs/impl/SessionHandler.java | 17 ++++++++--- 9 files changed, 37 insertions(+), 34 deletions(-) diff --git a/eventhubs/data-plane/azure-eventhubs/src/main/java/com/microsoft/azure/eventhubs/BatchOptions.java b/eventhubs/data-plane/azure-eventhubs/src/main/java/com/microsoft/azure/eventhubs/BatchOptions.java index e7d080129050..33c52179feeb 100644 --- a/eventhubs/data-plane/azure-eventhubs/src/main/java/com/microsoft/azure/eventhubs/BatchOptions.java +++ b/eventhubs/data-plane/azure-eventhubs/src/main/java/com/microsoft/azure/eventhubs/BatchOptions.java @@ -47,14 +47,14 @@ public final class BatchOptions { * The partitionKey to use for all {@link EventData}s sent in the current {@link EventDataBatch}. * Setting a PartitionKey will deliver the {@link EventData} to a specific Event Hubs partition. */ - public String partitionKey = null; + public String partitionKey; /** * The maximum size in bytes of {@link EventDataBatch} being constructed. * This value cannot exceed the maximum size supported by Event Hubs service. * {@link EventDataBatch#tryAdd(EventData)} API will use this value as the upper limit. */ - public Integer maxMessageSize = null; + public Integer maxMessageSize; public BatchOptions with(Consumer builderFunction) { builderFunction.accept(this); diff --git a/eventhubs/data-plane/azure-eventhubs/src/main/java/com/microsoft/azure/eventhubs/RetryPolicy.java b/eventhubs/data-plane/azure-eventhubs/src/main/java/com/microsoft/azure/eventhubs/RetryPolicy.java index b5d9f02463c6..541f6c716de1 100644 --- a/eventhubs/data-plane/azure-eventhubs/src/main/java/com/microsoft/azure/eventhubs/RetryPolicy.java +++ b/eventhubs/data-plane/azure-eventhubs/src/main/java/com/microsoft/azure/eventhubs/RetryPolicy.java @@ -56,7 +56,7 @@ public void incrementRetryCount(String clientId) { public void resetRetryCount(String clientId) { Integer currentRetryCount = this.retryCounts.get(clientId); if (currentRetryCount != null && currentRetryCount.intValue() != 0) { - this.retryCounts.put(clientId, 0); + this.retryCounts.replace(clientId, 0); } } diff --git a/eventhubs/data-plane/azure-eventhubs/src/main/java/com/microsoft/azure/eventhubs/impl/CBSChannel.java b/eventhubs/data-plane/azure-eventhubs/src/main/java/com/microsoft/azure/eventhubs/impl/CBSChannel.java index 83e4fc49a364..0262257aebba 100644 --- a/eventhubs/data-plane/azure-eventhubs/src/main/java/com/microsoft/azure/eventhubs/impl/CBSChannel.java +++ b/eventhubs/data-plane/azure-eventhubs/src/main/java/com/microsoft/azure/eventhubs/impl/CBSChannel.java @@ -14,17 +14,12 @@ final class CBSChannel { final FaultTolerantObject innerChannel; - final SessionProvider sessionProvider; - final AmqpConnection connectionEventDispatcher; CBSChannel( final SessionProvider sessionProvider, final AmqpConnection connection, final String clientId) { - this.sessionProvider = sessionProvider; - this.connectionEventDispatcher = connection; - RequestResponseCloser closer = new RequestResponseCloser(); this.innerChannel = new FaultTolerantObject<>( new RequestResponseOpener(sessionProvider, clientId, "cbs-session", "cbs", ClientConstants.CBS_ADDRESS, connection), diff --git a/eventhubs/data-plane/azure-eventhubs/src/main/java/com/microsoft/azure/eventhubs/impl/ExceptionUtil.java b/eventhubs/data-plane/azure-eventhubs/src/main/java/com/microsoft/azure/eventhubs/impl/ExceptionUtil.java index 0cdccfc092da..5b57a36060ce 100644 --- a/eventhubs/data-plane/azure-eventhubs/src/main/java/com/microsoft/azure/eventhubs/impl/ExceptionUtil.java +++ b/eventhubs/data-plane/azure-eventhubs/src/main/java/com/microsoft/azure/eventhubs/impl/ExceptionUtil.java @@ -104,7 +104,11 @@ static Exception distinguishNotFound(final String message) { } static void completeExceptionally(CompletableFuture future, Exception exception, ErrorContextProvider contextProvider) { - if (exception != null && exception instanceof EventHubException) { + if (exception == null) { + throw new NullPointerException(); + } + + if (exception instanceof EventHubException) { final ErrorContext errorContext = contextProvider.getContext(); ((EventHubException) exception).setContext(errorContext); } @@ -133,23 +137,17 @@ public static String toStackTraceString(final Throwable exception, final String builder.append(exception.getMessage()); final StackTraceElement[] stackTraceElements = exception.getStackTrace(); - if (stackTraceElements != null) { - for (final StackTraceElement ste : stackTraceElements) { - builder.append(System.lineSeparator()); - builder.append(ste.toString()); - } + for (final StackTraceElement ste : stackTraceElements) { + builder.append(System.lineSeparator()); + builder.append(ste.toString()); } final Throwable innerException = exception.getCause(); - if (innerException != null) { - builder.append("Cause: " + innerException.getMessage()); - final StackTraceElement[] innerStackTraceElements = innerException.getStackTrace(); - if (innerStackTraceElements != null) { - for (final StackTraceElement ste : innerStackTraceElements) { - builder.append(System.lineSeparator()); - builder.append(ste.toString()); - } - } + builder.append("Cause: " + innerException.getMessage()); + final StackTraceElement[] innerStackTraceElements = innerException.getStackTrace(); + for (final StackTraceElement ste : innerStackTraceElements) { + builder.append(System.lineSeparator()); + builder.append(ste.toString()); } return builder.toString(); diff --git a/eventhubs/data-plane/azure-eventhubs/src/main/java/com/microsoft/azure/eventhubs/impl/ManagementChannel.java b/eventhubs/data-plane/azure-eventhubs/src/main/java/com/microsoft/azure/eventhubs/impl/ManagementChannel.java index 1bcd77f25324..070783783d9f 100644 --- a/eventhubs/data-plane/azure-eventhubs/src/main/java/com/microsoft/azure/eventhubs/impl/ManagementChannel.java +++ b/eventhubs/data-plane/azure-eventhubs/src/main/java/com/microsoft/azure/eventhubs/impl/ManagementChannel.java @@ -18,12 +18,8 @@ final class ManagementChannel { final FaultTolerantObject innerChannel; - final SessionProvider sessionProvider; - final AmqpConnection connectionEventDispatcher; ManagementChannel(final SessionProvider sessionProvider, final AmqpConnection connection, final String clientId) { - this.sessionProvider = sessionProvider; - this.connectionEventDispatcher = connection; final RequestResponseCloser closer = new RequestResponseCloser(); this.innerChannel = new FaultTolerantObject<>( diff --git a/eventhubs/data-plane/azure-eventhubs/src/main/java/com/microsoft/azure/eventhubs/impl/MessageSender.java b/eventhubs/data-plane/azure-eventhubs/src/main/java/com/microsoft/azure/eventhubs/impl/MessageSender.java index fcb73da336aa..248643813aab 100644 --- a/eventhubs/data-plane/azure-eventhubs/src/main/java/com/microsoft/azure/eventhubs/impl/MessageSender.java +++ b/eventhubs/data-plane/azure-eventhubs/src/main/java/com/microsoft/azure/eventhubs/impl/MessageSender.java @@ -33,6 +33,7 @@ import org.slf4j.LoggerFactory; import java.io.IOException; +import java.io.Serializable; import java.nio.BufferOverflowException; import java.security.InvalidKeyException; import java.security.NoSuchAlgorithmException; @@ -1027,7 +1028,10 @@ public int getPriority() { } } - private static class DeliveryTagComparator implements Comparator { + private static class DeliveryTagComparator implements Comparator, Serializable { + + private static final long serialVersionUID = -7057500582037295635L; + @Override public int compare(WeightedDeliveryTag deliveryTag0, WeightedDeliveryTag deliveryTag1) { return deliveryTag1.getPriority() - deliveryTag0.getPriority(); diff --git a/eventhubs/data-plane/azure-eventhubs/src/main/java/com/microsoft/azure/eventhubs/impl/ReceivePump.java b/eventhubs/data-plane/azure-eventhubs/src/main/java/com/microsoft/azure/eventhubs/impl/ReceivePump.java index 0144343cbe05..b4c8f5d98088 100644 --- a/eventhubs/data-plane/azure-eventhubs/src/main/java/com/microsoft/azure/eventhubs/impl/ReceivePump.java +++ b/eventhubs/data-plane/azure-eventhubs/src/main/java/com/microsoft/azure/eventhubs/impl/ReceivePump.java @@ -163,7 +163,7 @@ public Void apply(final Iterable receivedEvents, final Throwable clie // don't invoke user call back - if stop is already raised / pump is unhealthy if (ReceivePump.this.shouldContinue() && (receivedEvents != null - || (receivedEvents == null && ReceivePump.this.invokeOnTimeout))) { + || ReceivePump.this.invokeOnTimeout)) { ReceivePump.this.onReceiveHandler.onReceive(receivedEvents); } } catch (final Throwable userCodeError) { diff --git a/eventhubs/data-plane/azure-eventhubs/src/main/java/com/microsoft/azure/eventhubs/impl/SendLinkHandler.java b/eventhubs/data-plane/azure-eventhubs/src/main/java/com/microsoft/azure/eventhubs/impl/SendLinkHandler.java index 73e723ef249e..55949b61306b 100644 --- a/eventhubs/data-plane/azure-eventhubs/src/main/java/com/microsoft/azure/eventhubs/impl/SendLinkHandler.java +++ b/eventhubs/data-plane/azure-eventhubs/src/main/java/com/microsoft/azure/eventhubs/impl/SendLinkHandler.java @@ -10,6 +10,7 @@ import org.slf4j.Logger; import org.slf4j.LoggerFactory; +import java.nio.charset.StandardCharsets; import java.util.Locale; import java.util.concurrent.atomic.AtomicBoolean; @@ -69,7 +70,7 @@ public void onDelivery(Event event) { if (TRACE_LOGGER.isTraceEnabled()) { TRACE_LOGGER.trace(String.format(Locale.US, "onDelivery senderName[%s], linkName[%s], unsettled[%s], credit[%s], deliveryState[%s], delivery.isBuffered[%s], delivery.id[%s]", - this.senderName, sender.getName(), sender.getUnsettled(), sender.getRemoteCredit(), delivery.getRemoteState(), delivery.isBuffered(), new String(delivery.getTag()))); + this.senderName, sender.getName(), sender.getUnsettled(), sender.getRemoteCredit(), delivery.getRemoteState(), delivery.isBuffered(), new String(delivery.getTag(), StandardCharsets.UTF_8))); } msgSender.onSendComplete(delivery); diff --git a/eventhubs/data-plane/azure-eventhubs/src/main/java/com/microsoft/azure/eventhubs/impl/SessionHandler.java b/eventhubs/data-plane/azure-eventhubs/src/main/java/com/microsoft/azure/eventhubs/impl/SessionHandler.java index cecd3545b3e2..3818fcdacb7a 100644 --- a/eventhubs/data-plane/azure-eventhubs/src/main/java/com/microsoft/azure/eventhubs/impl/SessionHandler.java +++ b/eventhubs/data-plane/azure-eventhubs/src/main/java/com/microsoft/azure/eventhubs/impl/SessionHandler.java @@ -64,11 +64,22 @@ public void onSessionLocalOpen(Event e) { } } + if (reactorHandler == null) { + this.onRemoteSessionOpenError.accept( + null, + new EventHubException( + false, + String.format("OnSessionLocalOpen entityName[%s], reactorHandler: NULL POINTER exception.", this.entityName)) + ); + e.getSession().close(); + return; + } + final ReactorDispatcher reactorDispatcher = reactorHandler.getReactorDispatcher(); final Session session = e.getSession(); try { - reactorDispatcher.invoke((int) this.openTimeout.toMillis(), new SessionTimeoutHandler(session, entityName, connectionId)); + reactorDispatcher.invoke((int) this.openTimeout.toMillis(), new SessionTimeoutHandler(entityName, connectionId)); } catch (IOException ioException) { if (TRACE_LOGGER.isWarnEnabled()) { TRACE_LOGGER.warn(String.format(Locale.US, "onSessionLocalOpen connectionId[%s], entityName[%s], reactorDispatcherError[%s]", @@ -151,12 +162,10 @@ public void onSessionFinal(Event e) { private class SessionTimeoutHandler extends DispatchHandler { - private final Session session; private final String entityName; private final String connectionId; - SessionTimeoutHandler(final Session session, final String entityName, final String connectionId) { - this.session = session; + SessionTimeoutHandler(final String entityName, final String connectionId) { this.entityName = entityName; this.connectionId = connectionId; } From a03491c56813cef71826c317c85a0cd1ed02b208 Mon Sep 17 00:00:00 2001 From: Connie Date: Fri, 26 Apr 2019 22:54:14 -0700 Subject: [PATCH 28/42] Last spotbug revert/fixes --- .../AzureStorageCheckpointLeaseManager.java | 7 ++++--- .../azure/eventprocessorhost/EventProcessorHost.java | 11 +++++------ 2 files changed, 9 insertions(+), 9 deletions(-) diff --git a/eventhubs/data-plane/azure-eventhubs-eph/src/main/java/com/microsoft/azure/eventprocessorhost/AzureStorageCheckpointLeaseManager.java b/eventhubs/data-plane/azure-eventhubs-eph/src/main/java/com/microsoft/azure/eventprocessorhost/AzureStorageCheckpointLeaseManager.java index 4c078cdccf83..e44b6d2ccdf6 100644 --- a/eventhubs/data-plane/azure-eventhubs-eph/src/main/java/com/microsoft/azure/eventprocessorhost/AzureStorageCheckpointLeaseManager.java +++ b/eventhubs/data-plane/azure-eventhubs-eph/src/main/java/com/microsoft/azure/eventprocessorhost/AzureStorageCheckpointLeaseManager.java @@ -332,15 +332,16 @@ public CompletableFuture> getAllLeases() { (bp.getLeaseState() == LeaseState.LEASED))); }); future = CompletableFuture.completedFuture(infos); - } catch (Exception e) { + } catch (URISyntaxException | StorageException | NoSuchElementException e) { Throwable effective = e; if (e instanceof NoSuchElementException) { // If there is a StorageException in the forEach, it arrives wrapped in a NoSuchElementException. // Strip the misleading NoSuchElementException to provide a meaningful error for the user. effective = e.getCause(); } - TRACE_LOGGER.warn(this.hostContext.withHost("Failure while getting lease state details"), effective); - future = new CompletableFuture>(); + + TRACE_LOGGER.warn(this.hostContext.withHost("Failure while getting lease state details"), e); + future = new CompletableFuture<>(); future.completeExceptionally(LoggingUtils.wrapException(effective, EventProcessorHostActionStrings.GETTING_LEASE)); } diff --git a/eventhubs/data-plane/azure-eventhubs-eph/src/main/java/com/microsoft/azure/eventprocessorhost/EventProcessorHost.java b/eventhubs/data-plane/azure-eventhubs-eph/src/main/java/com/microsoft/azure/eventprocessorhost/EventProcessorHost.java index 320164d500b2..c9eaf61e266d 100644 --- a/eventhubs/data-plane/azure-eventhubs-eph/src/main/java/com/microsoft/azure/eventprocessorhost/EventProcessorHost.java +++ b/eventhubs/data-plane/azure-eventhubs-eph/src/main/java/com/microsoft/azure/eventprocessorhost/EventProcessorHost.java @@ -269,14 +269,13 @@ public EventProcessorHost( if (leaseManager == null) { throw new IllegalArgumentException("Must provide an object which implements ILeaseManager"); } + // executorService argument is allowed to be null, that is the indication to use an internal threadpool. - if (this.partitionManagerOptions == null) { - // Normally will not be null because we're using the AzureStorage implementation. - // If it is null, we're using user-supplied implementation. Establish generic defaults - // in case the user doesn't provide an options object. - this.partitionManagerOptions = new PartitionManagerOptions(); - } + // Normally will not be null because we're using the AzureStorage implementation. + // If it is null, we're using user-supplied implementation. Establish generic defaults + // in case the user doesn't provide an options object. + this.partitionManagerOptions = new PartitionManagerOptions(); if (executorService != null) { // User has supplied an ExecutorService, so use that. From feefc38c12f5aefda07359137cc1878c8aba8cbf Mon Sep 17 00:00:00 2001 From: Connie Date: Sat, 27 Apr 2019 01:03:45 -0700 Subject: [PATCH 29/42] Creating inner static class. --- .../azure/eventhubs/impl/CBSChannel.java | 69 +++++++++++-------- 1 file changed, 39 insertions(+), 30 deletions(-) diff --git a/eventhubs/data-plane/azure-eventhubs/src/main/java/com/microsoft/azure/eventhubs/impl/CBSChannel.java b/eventhubs/data-plane/azure-eventhubs/src/main/java/com/microsoft/azure/eventhubs/impl/CBSChannel.java index 0262257aebba..271e6e996c2a 100644 --- a/eventhubs/data-plane/azure-eventhubs/src/main/java/com/microsoft/azure/eventhubs/impl/CBSChannel.java +++ b/eventhubs/data-plane/azure-eventhubs/src/main/java/com/microsoft/azure/eventhubs/impl/CBSChannel.java @@ -42,43 +42,52 @@ public void sendToken( request.setApplicationProperties(applicationProperties); request.setBody(new AmqpValue(token)); - this.innerChannel.runOnOpenedObject(dispatcher, - new OperationResult() { + this.innerChannel.runOnOpenedObject(dispatcher, new RequestResponseChannelOperation(request, sendTokenCallback)); + } + + public void close( + final ReactorDispatcher reactorDispatcher, + final OperationResult closeCallback) { + + this.innerChannel.close(reactorDispatcher, closeCallback); + } + + private static class RequestResponseChannelOperation implements OperationResult { + private final Message request; + private final OperationResult sendTokenCallback; + + RequestResponseChannelOperation(Message request, OperationResult callback) { + this.request = request; + this.sendTokenCallback = callback; + } + + @Override + public void onComplete(final RequestResponseChannel result) { + result.request(request, + new OperationResult() { @Override - public void onComplete(final RequestResponseChannel result) { - result.request(request, - new OperationResult() { - @Override - public void onComplete(final Message response) { - - final int statusCode = (int) response.getApplicationProperties().getValue().get(ClientConstants.PUT_TOKEN_STATUS_CODE); - final String statusDescription = (String) response.getApplicationProperties().getValue().get(ClientConstants.PUT_TOKEN_STATUS_DESCRIPTION); - - if (statusCode == AmqpResponseCode.ACCEPTED.getValue() || statusCode == AmqpResponseCode.OK.getValue()) { - sendTokenCallback.onComplete(null); - } else { - this.onError(ExceptionUtil.amqpResponseCodeToException(statusCode, statusDescription)); - } - } - - @Override - public void onError(final Exception error) { - sendTokenCallback.onError(error); - } - }); + public void onComplete(final Message response) { + + final int statusCode = (int) response.getApplicationProperties().getValue().get(ClientConstants.PUT_TOKEN_STATUS_CODE); + final String statusDescription = (String) response.getApplicationProperties().getValue().get(ClientConstants.PUT_TOKEN_STATUS_DESCRIPTION); + + if (statusCode == AmqpResponseCode.ACCEPTED.getValue() || statusCode == AmqpResponseCode.OK.getValue()) { + sendTokenCallback.onComplete(null); + } else { + this.onError(ExceptionUtil.amqpResponseCodeToException(statusCode, statusDescription)); + } } @Override - public void onError(Exception error) { + public void onError(final Exception error) { sendTokenCallback.onError(error); } }); - } + } - public void close( - final ReactorDispatcher reactorDispatcher, - final OperationResult closeCallback) { - - this.innerChannel.close(reactorDispatcher, closeCallback); + @Override + public void onError(Exception error) { + sendTokenCallback.onError(error); + } } } From b86779441b95b06eb2cf62b4b592c7a3cdaa6eae Mon Sep 17 00:00:00 2001 From: Connie Date: Sat, 27 Apr 2019 01:29:02 -0700 Subject: [PATCH 30/42] Redo changes from before. --- .../azure/eventhubs/impl/CBSChannel.java | 46 +++---------------- .../eventhubs/impl/ManagementChannel.java | 42 ++++------------- 2 files changed, 15 insertions(+), 73 deletions(-) diff --git a/eventhubs/data-plane/azure-eventhubs/src/main/java/com/microsoft/azure/eventhubs/impl/CBSChannel.java b/eventhubs/data-plane/azure-eventhubs/src/main/java/com/microsoft/azure/eventhubs/impl/CBSChannel.java index 271e6e996c2a..4dcfcd6c5c38 100644 --- a/eventhubs/data-plane/azure-eventhubs/src/main/java/com/microsoft/azure/eventhubs/impl/CBSChannel.java +++ b/eventhubs/data-plane/azure-eventhubs/src/main/java/com/microsoft/azure/eventhubs/impl/CBSChannel.java @@ -42,7 +42,12 @@ public void sendToken( request.setApplicationProperties(applicationProperties); request.setBody(new AmqpValue(token)); - this.innerChannel.runOnOpenedObject(dispatcher, new RequestResponseChannelOperation(request, sendTokenCallback)); + final MessageOperationResult messageOperation = new MessageOperationResult(response -> sendTokenCallback.onComplete(null), sendTokenCallback::onError); + final OperationResultBase operation = new OperationResultBase<>( + result -> result.request(request, messageOperation), + sendTokenCallback::onError); + + this.innerChannel.runOnOpenedObject(dispatcher, operation); } public void close( @@ -51,43 +56,4 @@ public void close( this.innerChannel.close(reactorDispatcher, closeCallback); } - - private static class RequestResponseChannelOperation implements OperationResult { - private final Message request; - private final OperationResult sendTokenCallback; - - RequestResponseChannelOperation(Message request, OperationResult callback) { - this.request = request; - this.sendTokenCallback = callback; - } - - @Override - public void onComplete(final RequestResponseChannel result) { - result.request(request, - new OperationResult() { - @Override - public void onComplete(final Message response) { - - final int statusCode = (int) response.getApplicationProperties().getValue().get(ClientConstants.PUT_TOKEN_STATUS_CODE); - final String statusDescription = (String) response.getApplicationProperties().getValue().get(ClientConstants.PUT_TOKEN_STATUS_DESCRIPTION); - - if (statusCode == AmqpResponseCode.ACCEPTED.getValue() || statusCode == AmqpResponseCode.OK.getValue()) { - sendTokenCallback.onComplete(null); - } else { - this.onError(ExceptionUtil.amqpResponseCodeToException(statusCode, statusDescription)); - } - } - - @Override - public void onError(final Exception error) { - sendTokenCallback.onError(error); - } - }); - } - - @Override - public void onError(Exception error) { - sendTokenCallback.onError(error); - } - } } diff --git a/eventhubs/data-plane/azure-eventhubs/src/main/java/com/microsoft/azure/eventhubs/impl/ManagementChannel.java b/eventhubs/data-plane/azure-eventhubs/src/main/java/com/microsoft/azure/eventhubs/impl/ManagementChannel.java index 070783783d9f..b6f577165d58 100644 --- a/eventhubs/data-plane/azure-eventhubs/src/main/java/com/microsoft/azure/eventhubs/impl/ManagementChannel.java +++ b/eventhubs/data-plane/azure-eventhubs/src/main/java/com/microsoft/azure/eventhubs/impl/ManagementChannel.java @@ -74,41 +74,17 @@ public void onEvent() { // if there isn't even 5 millis left - request will not make the round-trip // to the event hubs service. so don't schedule the request - let it timeout if (timeoutInMillis > ClientConstants.MGMT_CHANNEL_MIN_RETRY_IN_MILLIS) { - this.innerChannel.runOnOpenedObject(dispatcher, - new OperationResult() { - @Override - public void onComplete(final RequestResponseChannel result) { - result.request(requestMessage, - new OperationResult() { - @Override - public void onComplete(final Message response) { - final int statusCode = (int) response.getApplicationProperties().getValue() - .get(ClientConstants.PUT_TOKEN_STATUS_CODE); - final String statusDescription = (String) response.getApplicationProperties().getValue() - .get(ClientConstants.PUT_TOKEN_STATUS_DESCRIPTION); - - if (statusCode == AmqpResponseCode.ACCEPTED.getValue() - || statusCode == AmqpResponseCode.OK.getValue()) { - if (response.getBody() != null) { - resultFuture.complete((Map) ((AmqpValue) response.getBody()).getValue()); - } - } else { - this.onError(ExceptionUtil.amqpResponseCodeToException(statusCode, statusDescription)); - } - } + final MessageOperationResult messageOperation = new MessageOperationResult(response -> { + if (response.getBody() != null) { + resultFuture.complete((Map) ((AmqpValue) response.getBody()).getValue()); + } + }, resultFuture::completeExceptionally); - @Override - public void onError(final Exception error) { - resultFuture.completeExceptionally(error); - } - }); - } + final OperationResultBase operation = new OperationResultBase<>( + result -> result.request(requestMessage, messageOperation), + resultFuture::completeExceptionally); - @Override - public void onError(Exception error) { - resultFuture.completeExceptionally(error); - } - }); + this.innerChannel.runOnOpenedObject(dispatcher, operation); } return resultFuture; From 61c08985967887a47b2fa7d871a96d3a3f5a67c4 Mon Sep 17 00:00:00 2001 From: Connie Date: Sat, 27 Apr 2019 01:32:53 -0700 Subject: [PATCH 31/42] Undo old change. --- .../eventprocessorhost/InMemoryLeaseManager.java | 16 +++++----------- .../azure/eventhubs/ReceiverOptions.java | 1 - .../eventhubs/impl/RequestResponseCloser.java | 14 +++----------- 3 files changed, 8 insertions(+), 23 deletions(-) diff --git a/eventhubs/data-plane/azure-eventhubs-eph/src/main/java/com/microsoft/azure/eventprocessorhost/InMemoryLeaseManager.java b/eventhubs/data-plane/azure-eventhubs-eph/src/main/java/com/microsoft/azure/eventprocessorhost/InMemoryLeaseManager.java index 3b0dd0a8f5b3..9b95d5457129 100644 --- a/eventhubs/data-plane/azure-eventhubs-eph/src/main/java/com/microsoft/azure/eventprocessorhost/InMemoryLeaseManager.java +++ b/eventhubs/data-plane/azure-eventhubs-eph/src/main/java/com/microsoft/azure/eventprocessorhost/InMemoryLeaseManager.java @@ -14,7 +14,7 @@ import java.util.concurrent.ConcurrentHashMap; /*** - * An ILeaseManager implementation based on an in-memory store. + * An ILeaseManager implementation based on an in-memory store. * * THIS CLASS IS PROVIDED AS A CONVENIENCE FOR TESTING ONLY. All data stored via this class is in memory * only and not persisted in any way. In addition, it is only visible within the same process: multiple @@ -46,11 +46,11 @@ public InMemoryLeaseManager() { public void initialize(HostContext hostContext) { this.hostContext = hostContext; } - + public void setLatency(long milliseconds) { this.millisecondsLatency = milliseconds; } - + private void latency(String caller) { if (this.millisecondsLatency > 0) { try { @@ -91,7 +91,7 @@ public CompletableFuture deleteLeaseStore() { latency("deleteLeaseStore"); return CompletableFuture.completedFuture(null); } - + @Override public CompletableFuture getLease(String partitionId) { TRACE_LOGGER.debug(this.hostContext.withHost("getLease()")); @@ -110,7 +110,7 @@ public CompletableFuture> getAllLeases() { latency("getAllLeasesStateInfo"); return CompletableFuture.completedFuture(infos); } - + @Override public CompletableFuture createAllLeasesIfNotExists(List partitionIds) { ArrayList> createFutures = new ArrayList>(); @@ -402,12 +402,6 @@ void setExpirationTime(long expireAtMillis) { public boolean isExpiredSync() { boolean hasExpired = (System.currentTimeMillis() >= this.expirationTimeMillis); - // if (hasExpired) { - // CHANGE TO MATCH BEHAVIOR OF AzureStorageCheckpointLeaseManager - // An expired lease can be renewed by the previous owner. In order to implement that behavior for - // InMemory, the owner field has to remain unchanged. - //setOwner(""); - // } TRACE_LOGGER.debug("isExpired(" + this.getPartitionId() + (hasExpired ? ") expired " : ") leased ") + (this.expirationTimeMillis - System.currentTimeMillis())); return hasExpired; } diff --git a/eventhubs/data-plane/azure-eventhubs/src/main/java/com/microsoft/azure/eventhubs/ReceiverOptions.java b/eventhubs/data-plane/azure-eventhubs/src/main/java/com/microsoft/azure/eventhubs/ReceiverOptions.java index 315927bf8e67..5dae17cc69f4 100644 --- a/eventhubs/data-plane/azure-eventhubs/src/main/java/com/microsoft/azure/eventhubs/ReceiverOptions.java +++ b/eventhubs/data-plane/azure-eventhubs/src/main/java/com/microsoft/azure/eventhubs/ReceiverOptions.java @@ -79,7 +79,6 @@ public String getIdentifier() { * EventHubs service will throw {@link QuotaExceededException} and will include this identifier. * So, its very critical to choose a value, which can uniquely identify the whereabouts of {@link PartitionReceiver}. *

- *

* * @param value string to identify {@link PartitionReceiver} */ diff --git a/eventhubs/data-plane/azure-eventhubs/src/main/java/com/microsoft/azure/eventhubs/impl/RequestResponseCloser.java b/eventhubs/data-plane/azure-eventhubs/src/main/java/com/microsoft/azure/eventhubs/impl/RequestResponseCloser.java index a481bf9ca110..1403a700cbb2 100644 --- a/eventhubs/data-plane/azure-eventhubs/src/main/java/com/microsoft/azure/eventhubs/impl/RequestResponseCloser.java +++ b/eventhubs/data-plane/azure-eventhubs/src/main/java/com/microsoft/azure/eventhubs/impl/RequestResponseCloser.java @@ -20,17 +20,9 @@ public void run(OperationResult closeOperationCallback) { if (channelToBeClosed == null) { closeOperationCallback.onComplete(null); } else { - channelToBeClosed.close(new OperationResult() { - @Override - public void onComplete(Void result) { - closeOperationCallback.onComplete(result); - } - - @Override - public void onError(Exception error) { - closeOperationCallback.onError(error); - } - }); + channelToBeClosed.close(new OperationResultBase<>( + closeOperationCallback::onComplete, + closeOperationCallback::onError)); } } } From dee4f2e95b01b2da010d0b51a326ca0483e8b59d Mon Sep 17 00:00:00 2001 From: Connie Date: Sat, 27 Apr 2019 22:03:33 -0700 Subject: [PATCH 32/42] Ignore testcases that hang. --- .../exceptioncontracts/MsgFactoryOpenCloseTest.java | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/eventhubs/data-plane/azure-eventhubs/src/test/java/com/microsoft/azure/eventhubs/exceptioncontracts/MsgFactoryOpenCloseTest.java b/eventhubs/data-plane/azure-eventhubs/src/test/java/com/microsoft/azure/eventhubs/exceptioncontracts/MsgFactoryOpenCloseTest.java index 8d048b08dfdf..ddbc087dad3e 100644 --- a/eventhubs/data-plane/azure-eventhubs/src/test/java/com/microsoft/azure/eventhubs/exceptioncontracts/MsgFactoryOpenCloseTest.java +++ b/eventhubs/data-plane/azure-eventhubs/src/test/java/com/microsoft/azure/eventhubs/exceptioncontracts/MsgFactoryOpenCloseTest.java @@ -169,6 +169,7 @@ public void supplyClosedExecutorServiceToSendOperation() throws Exception { testClosed.awaitTermination(60, TimeUnit.SECONDS); } + @Ignore("TODO: Investigate testcase. This hangs.") @Test(expected = RejectedExecutionException.class) public void supplyClosedExecutorServiceToReceiveOperation() throws Exception { final ScheduledExecutorService testClosed = new ScheduledThreadPoolExecutor(1); @@ -184,6 +185,7 @@ public void supplyClosedExecutorServiceToReceiveOperation() throws Exception { temp.receiveSync(20); } + @Ignore("TODO: Investigate testcase. This hangs.") @Test(expected = RejectedExecutionException.class) public void supplyClosedExecutorServiceToCreateLinkOperation() throws Exception { final ScheduledExecutorService testClosed = Executors.newScheduledThreadPool(1); @@ -199,6 +201,7 @@ public void supplyClosedExecutorServiceToCreateLinkOperation() throws Exception temp.sendSync(EventData.create("test data - string".getBytes())); } + @Ignore("TODO: Investigate testcase. This hangs.") @Test(expected = RejectedExecutionException.class) public void supplyClosedExecutorServiceToCreateSenderOperation() throws Exception { final ScheduledExecutorService testClosed = new ScheduledThreadPoolExecutor(1); @@ -213,6 +216,7 @@ public void supplyClosedExecutorServiceToCreateSenderOperation() throws Exceptio temp.createPartitionSenderSync(PARTITION_ID); } + @Ignore("TODO: Investigate testcase. This hangs.") @Test(expected = RejectedExecutionException.class) public void supplyClosedExecutorServiceToCreateReceiverOperation() throws Exception { final ScheduledExecutorService testClosed = Executors.newScheduledThreadPool(1); @@ -227,6 +231,7 @@ public void supplyClosedExecutorServiceToCreateReceiverOperation() throws Except temp.createReceiverSync(TestContext.getConsumerGroupName(), PARTITION_ID, EventPosition.fromEndOfStream()); } + @Ignore("TODO: Investigate testcase. This hangs.") @Test(expected = RejectedExecutionException.class) public void supplyClosedExecutorServiceThenMgmtOperation() throws Throwable { final ScheduledThreadPoolExecutor testClosed = new ScheduledThreadPoolExecutor(1); @@ -245,6 +250,7 @@ public void supplyClosedExecutorServiceThenMgmtOperation() throws Throwable { } } + @Ignore("TODO: Investigate testcase. This hangs.") @Test(expected = RejectedExecutionException.class) public void supplyClosedExecutorServiceThenFactoryCloseOperation() throws Exception { final ScheduledExecutorService testClosed = Executors.newScheduledThreadPool(1); @@ -259,6 +265,7 @@ public void supplyClosedExecutorServiceThenFactoryCloseOperation() throws Except temp.closeSync(); } + @Ignore("TODO: Investigate testcase. This hangs.") @Test(expected = RejectedExecutionException.class) public void supplyClosedExecutorServiceThenSenderCloseOperation() throws Exception { final ScheduledThreadPoolExecutor testClosed = new ScheduledThreadPoolExecutor(1); @@ -273,6 +280,7 @@ public void supplyClosedExecutorServiceThenSenderCloseOperation() throws Excepti temp.closeSync(); } + @Ignore("TODO: Investigate testcase. This hangs.") @Test(expected = RejectedExecutionException.class) public void supplyClosedExecutorServiceThenReceiverCloseOperation() throws Exception { final ScheduledExecutorService testClosed = Executors.newScheduledThreadPool(1); From 6ca1460a39ff1bb778023c495f100f1ffb52fe55 Mon Sep 17 00:00:00 2001 From: Connie Date: Sun, 28 Apr 2019 11:53:35 -0700 Subject: [PATCH 33/42] Add Ignore to another failing test. --- .../azure/eventhubs/exceptioncontracts/ReactorFaultTest.java | 2 ++ 1 file changed, 2 insertions(+) diff --git a/eventhubs/data-plane/azure-eventhubs/src/test/java/com/microsoft/azure/eventhubs/exceptioncontracts/ReactorFaultTest.java b/eventhubs/data-plane/azure-eventhubs/src/test/java/com/microsoft/azure/eventhubs/exceptioncontracts/ReactorFaultTest.java index f6069ef6f14d..f3cb525cb257 100644 --- a/eventhubs/data-plane/azure-eventhubs/src/test/java/com/microsoft/azure/eventhubs/exceptioncontracts/ReactorFaultTest.java +++ b/eventhubs/data-plane/azure-eventhubs/src/test/java/com/microsoft/azure/eventhubs/exceptioncontracts/ReactorFaultTest.java @@ -19,6 +19,7 @@ import org.apache.qpid.proton.reactor.Reactor; import org.junit.Assert; import org.junit.BeforeClass; +import org.junit.Ignore; import org.junit.Test; import java.lang.reflect.Field; @@ -34,6 +35,7 @@ public static void initialize() { connStr = TestContext.getConnectionString(); } + @Ignore("TODO: Investigate testcase. This fails.") @Test() public void verifyReactorRestartsOnProtonBugs() throws Exception { final EventHubClient eventHubClient = EventHubClient.createSync(connStr.toString(), TestContext.EXECUTOR_SERVICE); From be9e486a12b052e49201d1dabc6853b83b8b76aa Mon Sep 17 00:00:00 2001 From: Connie Date: Sun, 28 Apr 2019 11:57:05 -0700 Subject: [PATCH 34/42] Removing commented out dependency. --- eventhubs/data-plane/pom.xml | 6 ------ 1 file changed, 6 deletions(-) diff --git a/eventhubs/data-plane/pom.xml b/eventhubs/data-plane/pom.xml index f23a3854f043..aa4bb91091c0 100644 --- a/eventhubs/data-plane/pom.xml +++ b/eventhubs/data-plane/pom.xml @@ -56,12 +56,6 @@ slf4j-simple test - From cdcdebf45e2bb173a1d5b3f6118a7ee8f8b59575 Mon Sep 17 00:00:00 2001 From: Connie Date: Sun, 28 Apr 2019 14:03:26 -0700 Subject: [PATCH 35/42] Moving increment out of if statement. --- .../microsoft/azure/eventhubs/sendrecv/SendTest.java | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/eventhubs/data-plane/azure-eventhubs/src/test/java/com/microsoft/azure/eventhubs/sendrecv/SendTest.java b/eventhubs/data-plane/azure-eventhubs/src/test/java/com/microsoft/azure/eventhubs/sendrecv/SendTest.java index 114cca077839..3006234578c9 100644 --- a/eventhubs/data-plane/azure-eventhubs/src/test/java/com/microsoft/azure/eventhubs/sendrecv/SendTest.java +++ b/eventhubs/data-plane/azure-eventhubs/src/test/java/com/microsoft/azure/eventhubs/sendrecv/SendTest.java @@ -178,13 +178,13 @@ public void onReceive(Iterable events) { if (!partitionKey.equals(event.getSystemProperties().getPartitionKey())) { this.validateSignal.completeExceptionally( new AssertionFailedError(String.format(Locale.US, "received partitionKey: %s, expected partitionKey: %s", event.getSystemProperties().getPartitionKey(), partitionKey))); - - this.currentEventCount++; } - if (this.currentEventCount == this.eventCount) { - this.validateSignal.complete(null); - } + this.currentEventCount++; + } + + if (this.currentEventCount == this.eventCount) { + this.validateSignal.complete(null); } } } From c976035c722fdcdd755f8f76d7d69b62d67e2cb9 Mon Sep 17 00:00:00 2001 From: Connie Date: Sun, 28 Apr 2019 14:56:11 -0700 Subject: [PATCH 36/42] Fix NullPointerException when there is no inner exception --- .../azure/eventhubs/impl/ExceptionUtil.java | 12 +++++++----- 1 file changed, 7 insertions(+), 5 deletions(-) diff --git a/eventhubs/data-plane/azure-eventhubs/src/main/java/com/microsoft/azure/eventhubs/impl/ExceptionUtil.java b/eventhubs/data-plane/azure-eventhubs/src/main/java/com/microsoft/azure/eventhubs/impl/ExceptionUtil.java index 5b57a36060ce..621c582d2af3 100644 --- a/eventhubs/data-plane/azure-eventhubs/src/main/java/com/microsoft/azure/eventhubs/impl/ExceptionUtil.java +++ b/eventhubs/data-plane/azure-eventhubs/src/main/java/com/microsoft/azure/eventhubs/impl/ExceptionUtil.java @@ -143,11 +143,13 @@ public static String toStackTraceString(final Throwable exception, final String } final Throwable innerException = exception.getCause(); - builder.append("Cause: " + innerException.getMessage()); - final StackTraceElement[] innerStackTraceElements = innerException.getStackTrace(); - for (final StackTraceElement ste : innerStackTraceElements) { - builder.append(System.lineSeparator()); - builder.append(ste.toString()); + if (innerException != null) { + builder.append("Cause: ").append(innerException.getMessage()); + final StackTraceElement[] innerStackTraceElements = innerException.getStackTrace(); + for (final StackTraceElement ste : innerStackTraceElements) { + builder.append(System.lineSeparator()); + builder.append(ste.toString()); + } } return builder.toString(); From 461a2ac642536eea5bc98a48659cf5141fc7ad96 Mon Sep 17 00:00:00 2001 From: Connie Date: Sun, 28 Apr 2019 14:57:53 -0700 Subject: [PATCH 37/42] Enable fixed tests. --- .../exceptioncontracts/MsgFactoryOpenCloseTest.java | 8 -------- 1 file changed, 8 deletions(-) diff --git a/eventhubs/data-plane/azure-eventhubs/src/test/java/com/microsoft/azure/eventhubs/exceptioncontracts/MsgFactoryOpenCloseTest.java b/eventhubs/data-plane/azure-eventhubs/src/test/java/com/microsoft/azure/eventhubs/exceptioncontracts/MsgFactoryOpenCloseTest.java index ddbc087dad3e..8d048b08dfdf 100644 --- a/eventhubs/data-plane/azure-eventhubs/src/test/java/com/microsoft/azure/eventhubs/exceptioncontracts/MsgFactoryOpenCloseTest.java +++ b/eventhubs/data-plane/azure-eventhubs/src/test/java/com/microsoft/azure/eventhubs/exceptioncontracts/MsgFactoryOpenCloseTest.java @@ -169,7 +169,6 @@ public void supplyClosedExecutorServiceToSendOperation() throws Exception { testClosed.awaitTermination(60, TimeUnit.SECONDS); } - @Ignore("TODO: Investigate testcase. This hangs.") @Test(expected = RejectedExecutionException.class) public void supplyClosedExecutorServiceToReceiveOperation() throws Exception { final ScheduledExecutorService testClosed = new ScheduledThreadPoolExecutor(1); @@ -185,7 +184,6 @@ public void supplyClosedExecutorServiceToReceiveOperation() throws Exception { temp.receiveSync(20); } - @Ignore("TODO: Investigate testcase. This hangs.") @Test(expected = RejectedExecutionException.class) public void supplyClosedExecutorServiceToCreateLinkOperation() throws Exception { final ScheduledExecutorService testClosed = Executors.newScheduledThreadPool(1); @@ -201,7 +199,6 @@ public void supplyClosedExecutorServiceToCreateLinkOperation() throws Exception temp.sendSync(EventData.create("test data - string".getBytes())); } - @Ignore("TODO: Investigate testcase. This hangs.") @Test(expected = RejectedExecutionException.class) public void supplyClosedExecutorServiceToCreateSenderOperation() throws Exception { final ScheduledExecutorService testClosed = new ScheduledThreadPoolExecutor(1); @@ -216,7 +213,6 @@ public void supplyClosedExecutorServiceToCreateSenderOperation() throws Exceptio temp.createPartitionSenderSync(PARTITION_ID); } - @Ignore("TODO: Investigate testcase. This hangs.") @Test(expected = RejectedExecutionException.class) public void supplyClosedExecutorServiceToCreateReceiverOperation() throws Exception { final ScheduledExecutorService testClosed = Executors.newScheduledThreadPool(1); @@ -231,7 +227,6 @@ public void supplyClosedExecutorServiceToCreateReceiverOperation() throws Except temp.createReceiverSync(TestContext.getConsumerGroupName(), PARTITION_ID, EventPosition.fromEndOfStream()); } - @Ignore("TODO: Investigate testcase. This hangs.") @Test(expected = RejectedExecutionException.class) public void supplyClosedExecutorServiceThenMgmtOperation() throws Throwable { final ScheduledThreadPoolExecutor testClosed = new ScheduledThreadPoolExecutor(1); @@ -250,7 +245,6 @@ public void supplyClosedExecutorServiceThenMgmtOperation() throws Throwable { } } - @Ignore("TODO: Investigate testcase. This hangs.") @Test(expected = RejectedExecutionException.class) public void supplyClosedExecutorServiceThenFactoryCloseOperation() throws Exception { final ScheduledExecutorService testClosed = Executors.newScheduledThreadPool(1); @@ -265,7 +259,6 @@ public void supplyClosedExecutorServiceThenFactoryCloseOperation() throws Except temp.closeSync(); } - @Ignore("TODO: Investigate testcase. This hangs.") @Test(expected = RejectedExecutionException.class) public void supplyClosedExecutorServiceThenSenderCloseOperation() throws Exception { final ScheduledThreadPoolExecutor testClosed = new ScheduledThreadPoolExecutor(1); @@ -280,7 +273,6 @@ public void supplyClosedExecutorServiceThenSenderCloseOperation() throws Excepti temp.closeSync(); } - @Ignore("TODO: Investigate testcase. This hangs.") @Test(expected = RejectedExecutionException.class) public void supplyClosedExecutorServiceThenReceiverCloseOperation() throws Exception { final ScheduledExecutorService testClosed = Executors.newScheduledThreadPool(1); From eb1fdf29c9e11c8f6507c0c3a3173e6b62a4aa07 Mon Sep 17 00:00:00 2001 From: Connie Date: Mon, 29 Apr 2019 11:48:10 -0700 Subject: [PATCH 38/42] Move parent node to the top of the file. --- eventhubs/data-plane/azure-eventhubs-eph/pom.xml | 14 +++++++------- .../data-plane/azure-eventhubs-extensions/pom.xml | 14 +++++++------- eventhubs/data-plane/azure-eventhubs/pom.xml | 14 +++++++------- eventhubs/data-plane/pom.xml | 14 +++++++------- 4 files changed, 28 insertions(+), 28 deletions(-) diff --git a/eventhubs/data-plane/azure-eventhubs-eph/pom.xml b/eventhubs/data-plane/azure-eventhubs-eph/pom.xml index 8e7475e23862..649dc2322e69 100644 --- a/eventhubs/data-plane/azure-eventhubs-eph/pom.xml +++ b/eventhubs/data-plane/azure-eventhubs-eph/pom.xml @@ -4,6 +4,13 @@ xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd"> + + com.microsoft.azure + azure-eventhubs-clients + 2.3.0 + ../pom.xml + + 4.0.0 com.microsoft.azure azure-eventhubs-eph @@ -13,13 +20,6 @@ EPH is built on top of the Azure Event Hubs Client and provides a number of features not present in that lower layer https://github.com/Azure/azure-sdk-for-java - - com.microsoft.azure - azure-eventhubs-clients - 2.3.0 - ../pom.xml - - azure-java-build-docs diff --git a/eventhubs/data-plane/azure-eventhubs-extensions/pom.xml b/eventhubs/data-plane/azure-eventhubs-extensions/pom.xml index d081ac35b562..45bbd35f6b58 100644 --- a/eventhubs/data-plane/azure-eventhubs-extensions/pom.xml +++ b/eventhubs/data-plane/azure-eventhubs-extensions/pom.xml @@ -4,6 +4,13 @@ xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd"> + + com.microsoft.azure + azure-eventhubs-clients + 2.3.0 + ../pom.xml + + 4.0.0 com.microsoft.azure azure-eventhubs-extensions @@ -12,13 +19,6 @@ Extensions built on Microsoft Azure Event Hubs https://github.com/Azure/azure-sdk-for-java - - com.microsoft.azure - azure-eventhubs-clients - 2.3.0 - ../pom.xml - - azure-java-build-docs diff --git a/eventhubs/data-plane/azure-eventhubs/pom.xml b/eventhubs/data-plane/azure-eventhubs/pom.xml index 2c250acce9c6..c7a1e80f3f5a 100644 --- a/eventhubs/data-plane/azure-eventhubs/pom.xml +++ b/eventhubs/data-plane/azure-eventhubs/pom.xml @@ -4,6 +4,13 @@ xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd"> + + com.microsoft.azure + azure-eventhubs-clients + 2.3.0 + ../pom.xml + + 4.0.0 com.microsoft.azure azure-eventhubs @@ -12,13 +19,6 @@ Libraries built on Microsoft Azure Event Hubs https://github.com/Azure/azure-sdk-for-java - - com.microsoft.azure - azure-eventhubs-clients - 2.3.0 - ../pom.xml - - azure-java-build-docs diff --git a/eventhubs/data-plane/pom.xml b/eventhubs/data-plane/pom.xml index aa4bb91091c0..93d1e09126b5 100644 --- a/eventhubs/data-plane/pom.xml +++ b/eventhubs/data-plane/pom.xml @@ -4,6 +4,13 @@ xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd"> + + com.azure + azure-client-sdk-parent + 1.0.0 + ../../pom.client.xml + + 4.0.0 com.microsoft.azure azure-eventhubs-clients @@ -14,13 +21,6 @@ Java libraries for talking to Windows Azure Event Hubs https://github.com/Azure/azure-sdk-for-java - - com.azure - azure-client-sdk-parent - 1.0.0 - ../../pom.client.xml - - azure-java-build-docs From 4fb29e3d0947d3b8b090d840310cc54697dd27f5 Mon Sep 17 00:00:00 2001 From: Connie Date: Mon, 29 Apr 2019 11:51:13 -0700 Subject: [PATCH 39/42] Update version numbers in spotbugs-reporting --- eng/spotbugs-aggregate-report/pom.xml | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/eng/spotbugs-aggregate-report/pom.xml b/eng/spotbugs-aggregate-report/pom.xml index ec012ce84e0d..dbc497d34c77 100644 --- a/eng/spotbugs-aggregate-report/pom.xml +++ b/eng/spotbugs-aggregate-report/pom.xml @@ -15,9 +15,10 @@ 1.0.0 - 1.2.0 5.0.1 - 2.0.0 + 2.3.0 + 2.5.0 + 1.2.0 10.5.0 @@ -67,7 +68,7 @@ com.microsoft.azure azure-eventhubs-eph - ${azure-eventhubs.version} + ${azure-eventhubs-eph.version} com.microsoft.azure From 56829c5fcdbd3b8bbec29abfe0cfdf4a7f903f59 Mon Sep 17 00:00:00 2001 From: Connie Date: Mon, 29 Apr 2019 12:25:46 -0700 Subject: [PATCH 40/42] Increasing wait time until event hub scheduler is completed. --- .../exceptioncontracts/MsgFactoryOpenCloseTest.java | 11 +++++++---- 1 file changed, 7 insertions(+), 4 deletions(-) diff --git a/eventhubs/data-plane/azure-eventhubs/src/test/java/com/microsoft/azure/eventhubs/exceptioncontracts/MsgFactoryOpenCloseTest.java b/eventhubs/data-plane/azure-eventhubs/src/test/java/com/microsoft/azure/eventhubs/exceptioncontracts/MsgFactoryOpenCloseTest.java index 8d048b08dfdf..1c4a1690fc79 100644 --- a/eventhubs/data-plane/azure-eventhubs/src/test/java/com/microsoft/azure/eventhubs/exceptioncontracts/MsgFactoryOpenCloseTest.java +++ b/eventhubs/data-plane/azure-eventhubs/src/test/java/com/microsoft/azure/eventhubs/exceptioncontracts/MsgFactoryOpenCloseTest.java @@ -3,6 +3,7 @@ package com.microsoft.azure.eventhubs.exceptioncontracts; +import com.microsoft.azure.eventhubs.CommunicationException; import com.microsoft.azure.eventhubs.ConnectionStringBuilder; import com.microsoft.azure.eventhubs.EventData; import com.microsoft.azure.eventhubs.EventHubClient; @@ -20,6 +21,7 @@ import org.junit.Ignore; import org.junit.Test; +import java.time.Duration; import java.time.Instant; import java.util.concurrent.CompletableFuture; import java.util.concurrent.ExecutionException; @@ -115,7 +117,6 @@ public void onError(Throwable error) { } } - @Ignore("TODO: Investigate testcase failure.") @Test() public void verifyThreadReleaseOnMsgFactoryOpenError() throws Exception { @@ -133,12 +134,14 @@ public void verifyThreadReleaseOnMsgFactoryOpenError() throws Exception { openFuture.get(); Assert.fail(); } catch (ExecutionException error) { - Assert.assertEquals(EventHubException.class, error.getCause().getClass()); + Assert.assertEquals(CommunicationException.class, error.getCause().getClass()); } - Thread.sleep(1000); // for reactor to transition from cleanup to complete-stop + // Waiting for reactor to transition from cleanup to complete-stop, this requires at least 60 seconds until + // the items are emptied. + Thread.sleep(Duration.ofSeconds(90).toMillis()); - Assert.assertEquals(((ScheduledThreadPoolExecutor) executor).getQueue().size(), 0); + Assert.assertEquals(0, ((ScheduledThreadPoolExecutor) executor).getQueue().size()); } finally { executor.shutdown(); } From 9955374e87a757e751dfc72af3d56b88b1521666 Mon Sep 17 00:00:00 2001 From: Connie Date: Mon, 29 Apr 2019 12:49:35 -0700 Subject: [PATCH 41/42] Rearrange imports. --- .../com/microsoft/azure/eventhubs/impl/MessagingFactory.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/eventhubs/data-plane/azure-eventhubs/src/main/java/com/microsoft/azure/eventhubs/impl/MessagingFactory.java b/eventhubs/data-plane/azure-eventhubs/src/main/java/com/microsoft/azure/eventhubs/impl/MessagingFactory.java index b9eb702370fa..2509288948c0 100644 --- a/eventhubs/data-plane/azure-eventhubs/src/main/java/com/microsoft/azure/eventhubs/impl/MessagingFactory.java +++ b/eventhubs/data-plane/azure-eventhubs/src/main/java/com/microsoft/azure/eventhubs/impl/MessagingFactory.java @@ -10,7 +10,6 @@ import com.microsoft.azure.eventhubs.OperationCancelledException; import com.microsoft.azure.eventhubs.RetryPolicy; import com.microsoft.azure.eventhubs.TimeoutException; -import java.util.function.BiConsumer; import org.apache.qpid.proton.amqp.Symbol; import org.apache.qpid.proton.amqp.transport.ErrorCondition; import org.apache.qpid.proton.engine.BaseHandler; @@ -37,6 +36,7 @@ import java.util.concurrent.RejectedExecutionException; import java.util.concurrent.ScheduledExecutorService; import java.util.concurrent.TimeUnit; +import java.util.function.BiConsumer; import java.util.function.Consumer; /** From 6064875f95ac70dff59db7060557a59b38ade291 Mon Sep 17 00:00:00 2001 From: Connie Date: Mon, 29 Apr 2019 13:55:39 -0700 Subject: [PATCH 42/42] Remove unused imports. --- .../eventhubs/exceptioncontracts/MsgFactoryOpenCloseTest.java | 2 -- .../eventhubs/exceptioncontracts/SendLargeMessageTest.java | 1 - 2 files changed, 3 deletions(-) diff --git a/eventhubs/data-plane/azure-eventhubs/src/test/java/com/microsoft/azure/eventhubs/exceptioncontracts/MsgFactoryOpenCloseTest.java b/eventhubs/data-plane/azure-eventhubs/src/test/java/com/microsoft/azure/eventhubs/exceptioncontracts/MsgFactoryOpenCloseTest.java index 1c4a1690fc79..ecb3278fafd2 100644 --- a/eventhubs/data-plane/azure-eventhubs/src/test/java/com/microsoft/azure/eventhubs/exceptioncontracts/MsgFactoryOpenCloseTest.java +++ b/eventhubs/data-plane/azure-eventhubs/src/test/java/com/microsoft/azure/eventhubs/exceptioncontracts/MsgFactoryOpenCloseTest.java @@ -7,7 +7,6 @@ import com.microsoft.azure.eventhubs.ConnectionStringBuilder; import com.microsoft.azure.eventhubs.EventData; import com.microsoft.azure.eventhubs.EventHubClient; -import com.microsoft.azure.eventhubs.EventHubException; import com.microsoft.azure.eventhubs.EventPosition; import com.microsoft.azure.eventhubs.PartitionReceiveHandler; import com.microsoft.azure.eventhubs.PartitionReceiver; @@ -18,7 +17,6 @@ import com.microsoft.azure.eventhubs.lib.TestContext; import org.junit.Assert; import org.junit.BeforeClass; -import org.junit.Ignore; import org.junit.Test; import java.time.Duration; diff --git a/eventhubs/data-plane/azure-eventhubs/src/test/java/com/microsoft/azure/eventhubs/exceptioncontracts/SendLargeMessageTest.java b/eventhubs/data-plane/azure-eventhubs/src/test/java/com/microsoft/azure/eventhubs/exceptioncontracts/SendLargeMessageTest.java index db5473b26097..dee6bcbc38ed 100644 --- a/eventhubs/data-plane/azure-eventhubs/src/test/java/com/microsoft/azure/eventhubs/exceptioncontracts/SendLargeMessageTest.java +++ b/eventhubs/data-plane/azure-eventhubs/src/test/java/com/microsoft/azure/eventhubs/exceptioncontracts/SendLargeMessageTest.java @@ -20,7 +20,6 @@ import java.time.Instant; import java.util.Locale; -import java.util.concurrent.ExecutionException; public class SendLargeMessageTest extends ApiTestBase { private static final String PARTITION_ID = "0";