Many resources are needed to download a project. Please understand that we have to compensate our server costs. Thank you in advance. Project price only 1 $
You can buy this project and download/modify it how often you want.
/*
* 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.eventprocessorhost;
import java.io.IOException;
import java.time.Instant;
import java.util.ArrayList;
import java.util.concurrent.CompletableFuture;
import java.util.concurrent.ExecutionException;
import java.util.logging.Level;
import com.microsoft.azure.eventhubs.EventData;
import com.microsoft.azure.eventhubs.EventHubClient;
import com.microsoft.azure.eventhubs.PartitionReceiveHandler;
import com.microsoft.azure.eventhubs.PartitionReceiver;
import com.microsoft.azure.eventhubs.ReceiverOptions;
import com.microsoft.azure.servicebus.ReceiverDisconnectedException;
import com.microsoft.azure.servicebus.ServiceBusException;
class EventHubPartitionPump extends PartitionPump
{
private CompletableFuture> internalOperationFuture = null;
private EventHubClient eventHubClient = null;
private PartitionReceiver partitionReceiver = null;
private InternalReceiveHandler internalReceiveHandler = null;
EventHubPartitionPump(EventProcessorHost host, Pump pump, Lease lease)
{
super(host, pump, lease);
}
@Override
void specializedStartPump()
{
boolean openedOK = false;
int retryCount = 0;
Exception lastException = null;
do
{
try
{
openClients();
openedOK = true;
}
catch (Exception e)
{
lastException = e;
if ((e instanceof ExecutionException) && (e.getCause() instanceof ReceiverDisconnectedException))
{
// TODO Assuming this is due to a receiver with a higher epoch.
// Is there a way to be sure without checking the exception text?
this.host.logWithHostAndPartition(Level.WARNING, this.partitionContext, "Receiver disconnected on create, bad epoch?", e);
// If it's a bad epoch, then retrying isn't going to help.
break;
}
else
{
this.host.logWithHostAndPartition(Level.WARNING, this.partitionContext, "Failure creating client or receiver, retrying", e);
retryCount++;
}
}
} while (!openedOK && (retryCount < 5));
if (!openedOK)
{
// IEventProcessor.onOpen is called from the base PartitionPump and must have returned in order for execution to reach here,
// so we can report this error to it instead of the general error handler.
this.processor.onError(this.partitionContext, lastException);
this.pumpStatus = PartitionPumpStatus.PP_OPENFAILED;
}
if (this.pumpStatus == PartitionPumpStatus.PP_OPENING)
{
this.internalReceiveHandler = new InternalReceiveHandler();
// IEventProcessor.onOpen is called from the base PartitionPump and must have returned in order for execution to reach here,
// meaning it is safe to set the handler and start calling IEventProcessor.onEvents.
// Set the status to running before setting the javaClient handler, so the IEventProcessor.onEvents can never race and see status != running.
this.pumpStatus = PartitionPumpStatus.PP_RUNNING;
this.partitionReceiver.setReceiveHandler(this.internalReceiveHandler, this.host.getEventProcessorOptions().getInvokeProcessorAfterReceiveTimeout());
}
if (this.pumpStatus == PartitionPumpStatus.PP_OPENFAILED)
{
this.pumpStatus = PartitionPumpStatus.PP_CLOSING;
cleanUpClients();
this.pumpStatus = PartitionPumpStatus.PP_CLOSED;
}
}
private void openClients() throws ServiceBusException, IOException, InterruptedException, ExecutionException
{
// Create new client
this.host.logWithHostAndPartition(Level.FINER, this.partitionContext, "Opening EH client");
this.internalOperationFuture = EventHubClient.createFromConnectionString(this.host.getEventHubConnectionString());
this.eventHubClient = (EventHubClient) this.internalOperationFuture.get();
this.internalOperationFuture = null;
// Create new receiver and set options
ReceiverOptions options = new ReceiverOptions();
options.setReceiverRuntimeMetricEnabled(this.host.getEventProcessorOptions().getReceiverRuntimeMetricEnabled());
Object startAt = this.partitionContext.getInitialOffset();
long epoch = this.lease.getEpoch();
this.host.logWithHostAndPartition(Level.FINER, this.partitionContext, "Opening EH receiver with epoch " + epoch + " at location " + startAt);
if (startAt instanceof String)
{
this.internalOperationFuture = this.eventHubClient.createEpochReceiver(this.partitionContext.getConsumerGroupName(), this.partitionContext.getPartitionId(),
(String)startAt, epoch, options);
}
else if (startAt instanceof Instant)
{
this.internalOperationFuture = this.eventHubClient.createEpochReceiver(this.partitionContext.getConsumerGroupName(), this.partitionContext.getPartitionId(),
(Instant)startAt, epoch, options);
}
else
{
String errMsg = "Starting offset is not String or Instant, is " + ((startAt != null) ? startAt.getClass().toString() : "null");
this.host.logWithHostAndPartition(Level.SEVERE, this.partitionContext, errMsg);
throw new RuntimeException(errMsg);
}
this.lease.setEpoch(epoch);
if (this.internalOperationFuture != null)
{
this.partitionReceiver = (PartitionReceiver) this.internalOperationFuture.get();
}
else
{
this.host.logWithHostAndPartition(Level.SEVERE, this.partitionContext, "createEpochReceiver failed with null");
throw new RuntimeException("createEpochReceiver failed with null");
}
this.partitionReceiver.setPrefetchCount(this.host.getEventProcessorOptions().getPrefetchCount());
this.partitionReceiver.setReceiveTimeout(this.host.getEventProcessorOptions().getReceiveTimeOut());
this.internalOperationFuture = null;
this.host.logWithHostAndPartition(Level.FINER, this.partitionContext, "EH client and receiver creation finished");
}
private void cleanUpClients() // swallows all exceptions
{
if (this.partitionReceiver != null)
{
// Taking the lock means that there is no onEvents call in progress.
synchronized (this.processingSynchronizer)
{
// Disconnect the processor from the receiver we're about to close.
// Fortunately this is idempotent -- setting the handler to null when it's already been
// nulled by code elsewhere is harmless!
this.partitionReceiver.setReceiveHandler(null);
}
this.host.logWithHostAndPartition(Level.FINER, this.partitionContext, "Closing EH receiver");
this.partitionReceiver.close();
this.partitionReceiver = null;
}
if (this.eventHubClient != null)
{
this.host.logWithHostAndPartition(Level.FINER, this.partitionContext, "Closing EH client");
this.eventHubClient.close();
this.eventHubClient = null;
}
}
@Override
void specializedShutdown(CloseReason reason)
{
// If an open operation is stuck, this lets us shut down anyway.
CompletableFuture> captured = this.internalOperationFuture;
if (captured != null)
{
captured.cancel(true);
}
if (this.partitionReceiver != null)
{
// Disconnect any processor from the receiver so the processor won't get
// any more calls. But a call could be in progress right now.
this.partitionReceiver.setReceiveHandler(null);
// Close the EH clients. Errors are swallowed, nothing we could do about them anyway.
cleanUpClients();
}
}
private class InternalReceiveHandler extends PartitionReceiveHandler
{
InternalReceiveHandler()
{
super(EventHubPartitionPump.this.host.getEventProcessorOptions().getMaxBatchSize());
}
@Override
public void onReceive(Iterable events)
{
if (EventHubPartitionPump.this.host.getEventProcessorOptions().getReceiverRuntimeMetricEnabled())
{
EventHubPartitionPump.this.partitionContext.setRuntimeInformation(EventHubPartitionPump.this.partitionReceiver.getRuntimeInformation());
}
// This method is called on the thread that the Java EH client uses to run the pump.
// There is one pump per EventHubClient. Since each PartitionPump creates a new EventHubClient,
// using that thread to call onEvents does no harm. Even if onEvents is slow, the pump will
// get control back each time onEvents returns, and be able to receive a new batch of messages
// with which to make the next onEvents call. The pump gains nothing by running faster than onEvents.
// The underlying client returns null if there are no events, but the contract for IEventProcessor
// is different and is expecting an empty iterable if there are no events (and invoke processor after
// receive timeout is turned on).
Iterable effectiveEvents = events;
if (effectiveEvents == null)
{
effectiveEvents = new ArrayList();
}
EventHubPartitionPump.this.onEvents(effectiveEvents);
}
@Override
public void onError(Throwable error)
{
EventHubPartitionPump.this.pumpStatus = PartitionPumpStatus.PP_ERRORED;
if (error == null)
{
error = new Throwable("No error info supplied by EventHub client");
}
if (error instanceof ReceiverDisconnectedException)
{
EventHubPartitionPump.this.host.logWithHostAndPartition(Level.WARNING, EventHubPartitionPump.this.partitionContext,
"EventHub client disconnected, probably another host took the partition");
}
else
{
EventHubPartitionPump.this.host.logWithHostAndPartition(Level.SEVERE, EventHubPartitionPump.this.partitionContext, "EventHub client error: " + error.toString());
if (error instanceof Exception)
{
EventHubPartitionPump.this.host.logWithHostAndPartition(Level.SEVERE, EventHubPartitionPump.this.partitionContext, "EventHub client error continued", (Exception)error);
}
}
EventHubPartitionPump.this.onError(error);
}
}
}