Class ServiceBusClientBuilder

java.lang.Object
com.azure.messaging.servicebus.ServiceBusClientBuilder
All Implemented Interfaces:
AmqpTrait<ServiceBusClientBuilder>, com.azure.core.client.traits.AzureNamedKeyCredentialTrait<ServiceBusClientBuilder>, com.azure.core.client.traits.AzureSasCredentialTrait<ServiceBusClientBuilder>, com.azure.core.client.traits.ConfigurationTrait<ServiceBusClientBuilder>, com.azure.core.client.traits.ConnectionStringTrait<ServiceBusClientBuilder>, com.azure.core.client.traits.TokenCredentialTrait<ServiceBusClientBuilder>

public final class ServiceBusClientBuilder extends Object implements com.azure.core.client.traits.TokenCredentialTrait<ServiceBusClientBuilder>, com.azure.core.client.traits.AzureNamedKeyCredentialTrait<ServiceBusClientBuilder>, com.azure.core.client.traits.ConnectionStringTrait<ServiceBusClientBuilder>, com.azure.core.client.traits.AzureSasCredentialTrait<ServiceBusClientBuilder>, AmqpTrait<ServiceBusClientBuilder>, com.azure.core.client.traits.ConfigurationTrait<ServiceBusClientBuilder>

This class provides a fluent builder API to aid the instantiation of clients to send and receive messages to/from Service Bus entities.

Credentials are required to perform operations against Azure Service Bus. They can be set by using one of the following methods:

The credential used in the following samples is DefaultAzureCredential for authentication. It is appropriate for most scenarios, including local development and production environments. Additionally, we recommend using managed identity for authentication in production environments. You can find more information on different ways of authenticating and their corresponding credential types in the Azure Identity documentation".

Clients and sub-builders

ServiceBusClientBuilder can instantiate several clients. The client to instantiate depends on whether users are publishing or receiving messages and if the entity has Service Bus sessions enabled.

Sending messages

Sample: Instantiate a synchronous sender and send a message

The following code sample demonstrates the creation of the synchronous client ServiceBusSenderClient and sending a message. The fullyQualifiedNamespace is the Service Bus namespace's host name. It is listed under the "Essentials" panel after navigating to the Service Bus namespace via Azure Portal. The credential used is DefaultAzureCredential because it combines commonly used credentials in deployment and development and chooses the credential to used based on its running environment. When performance is important, consider using ServiceBusMessageBatch to publish multiple messages at once.

 TokenCredential credential = new DefaultAzureCredentialBuilder().build();

 // 'fullyQualifiedNamespace' will look similar to "{your-namespace}.servicebus.windows.net"
 ServiceBusSenderClient sender = new ServiceBusClientBuilder()
     .credential(fullyQualifiedNamespace, credential)
     .sender()
     .queueName(queueName)
     .buildClient();

 sender.sendMessage(new ServiceBusMessage("Foo bar"));
 

Consuming messages

There are multiple clients for consuming messages from a Service Bus entity (that is not have Service Bus sessions enabled).

Sample: Instantiate an asynchronous receiver

The code example below demonstrates creating an async receiver. The credential used is DefaultAzureCredential for authentication. It is appropriate for most scenarios, including local development and production environments. ServiceBusReceiveMode.PEEK_LOCK and disableAutoComplete() are strongly recommended so users have control over message settlement.

 TokenCredential credential = new DefaultAzureCredentialBuilder().build();

 // 'fullyQualifiedNamespace' will look similar to "{your-namespace}.servicebus.windows.net"
 // 'disableAutoComplete' indicates that users will explicitly settle their message.
 ServiceBusReceiverAsyncClient asyncReceiver = new ServiceBusClientBuilder()
     .credential(fullyQualifiedNamespace, credential)
     .receiver()
     .disableAutoComplete()
     .queueName(queueName)
     .buildAsyncClient();

 // When users are done with the receiver, dispose of the receiver.
 // Clients should be long-lived objects as they require resources
 // and time to establish a connection to the service.
 asyncReceiver.close();
 

Sample: Instantiate ServiceBusProcessorClient

The code example below demonstrates creating a processor client. The processor client is recommended for most production scenarios because it offers connection recovery. The credential used is DefaultAzureCredential for authentication. It is appropriate for most scenarios, including local development and production environments. ServiceBusReceiveMode.PEEK_LOCK and disableAutoComplete() are strongly recommended so users have control over message settlement.

 // Function that gets called whenever a message is received.
 Consumer<ServiceBusReceivedMessageContext> processMessage = context -> {
     final ServiceBusReceivedMessage message = context.getMessage();
     // Randomly complete or abandon each message. Ideally, in real-world scenarios, if the business logic
     // handling message reaches desired state such that it doesn't require Service Bus to redeliver
     // the same message, then context.complete() should be called otherwise context.abandon().
     final boolean success = Math.random() < 0.5;
     if (success) {
         try {
             context.complete();
         } catch (RuntimeException error) {
             System.out.printf("Completion of the message %s failed.%n Error: %s%n",
                 message.getMessageId(), error);
         }
     } else {
         try {
             context.abandon();
         } catch (RuntimeException error) {
             System.out.printf("Abandoning of the message %s failed.%nError: %s%n",
                 message.getMessageId(), error);
         }
     }
 };

 // Sample code that gets called if there's an error
 Consumer<ServiceBusErrorContext> processError = errorContext -> {
     if (errorContext.getException() instanceof ServiceBusException) {
         ServiceBusException exception = (ServiceBusException) errorContext.getException();

         System.out.printf("Error source: %s, reason %s%n", errorContext.getErrorSource(),
             exception.getReason());
     } else {
         System.out.printf("Error occurred: %s%n", errorContext.getException());
     }
 };

 TokenCredential tokenCredential = new DefaultAzureCredentialBuilder().build();

 // Create the processor client via the builder and its sub-builder
 // 'fullyQualifiedNamespace' will look similar to "{your-namespace}.servicebus.windows.net"
 ServiceBusProcessorClient processorClient = new ServiceBusClientBuilder()
     .credential(fullyQualifiedNamespace, tokenCredential)
     .processor()
     .queueName(queueName)
     .receiveMode(ServiceBusReceiveMode.PEEK_LOCK)
     .disableAutoComplete()  // Make sure to explicitly opt in to manual settlement (e.g. complete, abandon).
     .processMessage(processMessage)
     .processError(processError)
     .disableAutoComplete()
     .buildProcessorClient();

 // Starts the processor in the background. Control returns immediately.
 processorClient.start();

 // Stop processor and dispose when done processing messages.
 processorClient.stop();
 processorClient.close();
 

Consuming messages from a session-enabled Service Bus entity

Service Bus supports joint and ordered handling of unbounded sequences of messages through Service Bus sessions. Sessions can be used as a first in, first out (FIFO) processing of messages. Queues and topics/subscriptions support Service Bus sessions, however, it must be enabled at the time of entity creation.

Sample: Sending a message to a session-enabled queue

The snippet below demonstrates sending a message to a Service Bus sessions enabled queue. Setting ServiceBusMessage.setMessageId(String) property to "greetings" will send the message to a Service Bus session with an id of "greetings".

 // 'fullyQualifiedNamespace' will look similar to "{your-namespace}.servicebus.windows.net"
 ServiceBusSenderClient sender = new ServiceBusClientBuilder()
     .credential(fullyQualifiedNamespace, new DefaultAzureCredentialBuilder().build())
     .sender()
     .queueName(sessionEnabledQueueName)
     .buildClient();

 // Setting sessionId publishes that message to a specific session, in this case, "greeting".
 ServiceBusMessage message = new ServiceBusMessage("Hello world")
     .setSessionId("greetings");

 sender.sendMessage(message);

 // Dispose of the sender.
 sender.close();
 

Sample: Receive messages from first available session

To process messages from the first available session, switch to ServiceBusClientBuilder.ServiceBusSessionReceiverClientBuilder and build the session receiver client. Use acceptNextSession() to find the first available session to process messages from.

 TokenCredential credential = new DefaultAzureCredentialBuilder().build();

 // 'fullyQualifiedNamespace' will look similar to "{your-namespace}.servicebus.windows.net"
 // 'disableAutoComplete' indicates that users will explicitly settle their message.
 ServiceBusSessionReceiverAsyncClient sessionReceiver = new ServiceBusClientBuilder()
     .credential(fullyQualifiedNamespace, credential)
     .sessionReceiver()
     .disableAutoComplete()
     .queueName(sessionEnabledQueueName)
     .buildAsyncClient();

 // Creates a client to receive messages from the first available session. It waits until
 // AmqpRetryOptions.getTryTimeout() elapses. If no session is available within that operation timeout, it
 // completes with a retriable error. Otherwise, a receiver is returned when a lock on the session is acquired.
 Mono<ServiceBusReceiverAsyncClient> receiverMono = sessionReceiver.acceptNextSession();

 Flux<Void> receiveMessagesFlux = Flux.usingWhen(receiverMono,
     receiver -> receiver.receiveMessages().flatMap(message -> {
         System.out.println("Received message: " + message.getBody());

         // Explicitly settle the message via complete, abandon, defer, dead-letter, etc.
         if (isMessageProcessed) {
             return receiver.complete(message);
         } else {
             return receiver.abandon(message);
         }
     }),
     receiver -> Mono.fromRunnable(() -> {
         // Dispose of the receiver and sessionReceiver when done receiving messages.
         receiver.close();
         sessionReceiver.close();
     }));

 // This is a non-blocking call that moves onto the next line of code after setting up and starting the receive
 // operation. Customers can keep a reference to `subscription` and dispose of it when they want to stop
 // receiving messages.
 Disposable subscription = receiveMessagesFlux.subscribe(unused -> {
 }, error -> System.out.println("Error occurred: " + error),
     () -> System.out.println("Receiving complete."));
 

Sample: Process messages from all sessions

The following code sample demonstrates the creation the ServiceBusProcessorClient that processes all available sessions in the queue. ServiceBusClientBuilder.ServiceBusSessionProcessorClientBuilder.maxConcurrentSessions(int) indicates how many sessions the processor will process at the same time. The credential used is DefaultAzureCredential for authentication. It is appropriate for most scenarios, including local development and production environments. ServiceBusReceiveMode.PEEK_LOCK and disableAutoComplete() are strongly recommended so users have control over message settlement.

 // Function that gets called whenever a message is received.
 Consumer<ServiceBusReceivedMessageContext> onMessage = context -> {
     ServiceBusReceivedMessage message = context.getMessage();
     System.out.printf("Processing message. Session: %s, Sequence #: %s. Contents: %s%n",
         message.getSessionId(), message.getSequenceNumber(), message.getBody());
 };

 Consumer<ServiceBusErrorContext> onError = context -> {
     System.out.printf("Error when receiving messages from namespace: '%s'. Entity: '%s'%n",
         context.getFullyQualifiedNamespace(), context.getEntityPath());

     if (context.getException() instanceof ServiceBusException) {
         ServiceBusException exception = (ServiceBusException) context.getException();

         System.out.printf("Error source: %s, reason %s%n", context.getErrorSource(),
             exception.getReason());
     } else {
         System.out.printf("Error occurred: %s%n", context.getException());
     }
 };

 TokenCredential tokenCredential = new DefaultAzureCredentialBuilder().build();

 // Create the processor client via the builder and its sub-builder
 // 'fullyQualifiedNamespace' will look similar to "{your-namespace}.servicebus.windows.net"
 ServiceBusProcessorClient sessionProcessor = new ServiceBusClientBuilder()
     .credential(fullyQualifiedNamespace, tokenCredential)
     .sessionProcessor()
     .queueName(sessionEnabledQueueName)
     .receiveMode(ServiceBusReceiveMode.PEEK_LOCK)
     .disableAutoComplete()
     .maxConcurrentSessions(2)
     .processMessage(onMessage)
     .processError(onError)
     .buildProcessorClient();

 // Starts the processor in the background. Control returns immediately.
 sessionProcessor.start();

 // Stop processor and dispose when done processing messages.
 sessionProcessor.stop();
 sessionProcessor.close();
 

Connection sharing

The creation of a connection to Service Bus requires resources. If your architecture allows, an application should share connection between clients which can be achieved by sharing the top level builder as shown below.

Sharing a connection between clients

 TokenCredential credential = new DefaultAzureCredentialBuilder().build();

 // 'fullyQualifiedNamespace' will look similar to "{your-namespace}.servicebus.windows.net"
 // Any clients created from this builder will share the underlying connection.
 ServiceBusClientBuilder sharedConnectionBuilder = new ServiceBusClientBuilder()
     .credential(fullyQualifiedNamespace, credential);

 // Create receiver and sender which will share the connection.
 ServiceBusReceiverClient receiver = sharedConnectionBuilder
     .receiver()
     .receiveMode(ServiceBusReceiveMode.PEEK_LOCK)
     .queueName(queueName)
     .buildClient();
 ServiceBusSenderClient sender = sharedConnectionBuilder
     .sender()
     .queueName(queueName)
     .buildClient();

 // Use the clients and finally close them.
 try {
     sender.sendMessage(new ServiceBusMessage("payload"));
     receiver.receiveMessages(1);
 } finally {
     // Clients should be long-lived objects as they require resources
     // and time to establish a connection to the service.
     sender.close();
     receiver.close();
 }