Q-1). What is Google Cloud Pub/Sub, and how does it differ from traditional message brokers?

A-1). The differences between Google Cloud Pub/Sub with traditional message brokers are as follows:

Google Cloud Pub/SubTraditional Message Brokers
It is a fully managed service handled entirely by GoogleIt often requires setup, maintenance, and management by the user
It is a global service, offering automatic scaling and high availability across multiple regionsIt needs manual configuration to achieve similar levels of scalability and availability
Pub/Sub operates on a publish-subscribe model with no central message broker infrastructure, enabling better performance and scalabilityTraditional message brokers require a central message broker
It focuses on delivering messages to subscribers efficiently and doesn’t offer advanced features like message transformations, complex routing rules, or message queuesIt offers certain advanced features like message transformations, complex routing rules, or message queues
It is designed for asynchronous communication, ideal for microservices and distributed systems without direct coupling between the servicesIt is also designed for asynchronous communication, but it offers a direct coupling between the services
Q-2). How do you integrate Google Cloud Pub/Sub with a Spring Boot application?

A-2). The steps to integrate Google Cloud Pub/Sub with a Spring Boot application are as follows:

  • Setup a Google Cloud Pub/Sub
    • Create a Google Cloud Project
    • Enable the Pub/Sub API for the project
    • Create a Pub/Sub Topic and Subscription in the Google Cloud Console
  • Add the Spring Cloud GCP Pub/Sub starter dependency

Define the dependency in the pom.xml file

<dependency>
    <groupId>org.springframework.cloud</groupId>
    <artifactId>spring-cloud-gcp-starter-pubsub</artifactId>
</dependency>
  • Configure Google Cloud Pub/Sub Properties

Define the configuration-related properties in the application.properties file

spring.cloud.gcp.pubsub.project-id=your-project-id
spring.cloud.gcp.pubsub.subscription-id=your-subscription-id

Replace the your-project-id with the Google Cloud project ID and your-subscription-id with the name of the Pub/Sub Subscription

  • Create a Message Receiver

MessageReceiver class is provided by com.google.cloud.pubsub.v1 package.

@Component
public class SpringGCPPubSubMessageReceiver implements MessageReceiver {
	
	private static final Logger LOGGER = LoggerFactory.getLogger(SpringGCPPubSubMessageReceiver.class);

	@Override
	public void receiveMessage(PubsubMessage message, AckReplyConsumer consumer) {
		String payLoad = message.getData().toString();
		LOGGER.info("SpringGCPPubSubMessageReceiver -> receiveMessage() -> Message Payload : {}", payLoad);
		consumer.ack();
	}
}
  • Configure Message Listener
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.cloud.gcp.pubsub.core.subscriber.PubSubSubscriberOperations;
import org.springframework.cloud.gcp.pubsub.support.BasicAcknowledgeablePubsubMessage;

@SpringBootApplication
public class MyApp {

    public static void main(String[] args) {
        SpringApplication.run(MyApp.class, args);
    }

    @Bean
    public MessageReceiver messageReceiver() {
        return new PubSubMessageReceiver();
    }

    @Bean
    public MessageChannel pubsubInputChannel() {
        return new DirectChannel();
    }

    @Bean
    public PubSubInboundChannelAdapter messageChannelAdapter(
            @Qualifier("pubsubInputChannel") MessageChannel inputChannel,
            PubSubSubscriberOperations pubSubSubscriberOperations) {

        PubSubInboundChannelAdapter adapter =
                new PubSubInboundChannelAdapter(pubSubSubscriberOperations, "your-subscription-id");
        adapter.setOutputChannel(inputChannel);
        adapter.setAckMode(AckMode.MANUAL);
        return adapter;
    }
}

Replace “your-subscription-id” with the name of the Pub/Sub Subscription.

  • Publish message to Pub/Sub

To publish a message in Google Cloud Pub/Sub, use the PubSubTemplate provided by Spring Cloud GCP.

import org.springframework.cloud.gcp.pubsub.core.PubSubTemplate;
import org.springframework.stereotype.Component;

@Component
public class PubSubMessagePublisher {

    private final PubSubTemplate pubSubTemplate;

    public PubSubMessagePublisher(PubSubTemplate pubSubTemplate) {
        this.pubSubTemplate = pubSubTemplate;
    }

    public void publishMessage(String topicName, String message) {
        this.pubSubTemplate.publish(topicName, message);
    }
}
Q-3). Explain the role of the PubSubTemplate Spring Cloud GCP Pub/Sub integration.

A-3). The role of PubSubTemplate in Spring Cloud GCP Pub/Sub integration is as follows:

  1. Message Publishing – it allows you to publish messages in Google Cloud Pub/Sub Subscription.
  2. Synchronous and Asynchronous Operations – It provides methods for both synchronous and asynchronous message publishing. You can choose to publish messages synchronously, which will block until the message is successfully published, or asynchronously, where the publishing operation is performed on a separate thread, and the method returns immediately.
  3. Error Handling and Retry Logic – It handles error scenarios and retries, publishing messages if necessary.
  4. Integration with Spring Messaging – It integrates seamlessly with Spring’s messaging framework.
  5. Serialization and Deserialization – It automatically handles the serialization and deserialization of message payloads. It converts Java objects to the required format while publishing in a Topic, and converts incoming Pub/Sub messages back to Java objects when receiving them.
  6. Customization and Configuration – It can be customized with various settings, including the TopicNameResolver for dynamic topic name resolution and PublisherFactory for customizing the underlying Publisher used for publishing messages.
Q-4). How can you publish messages to a Pub/Sub topic using Spring Boot?

A-4). The following steps are provided below:

  • Add the Spring Cloud GCP Pub/Sub Starter Dependency – Add the dependency in the pom.xml file
<dependency>
    <groupId>org.springframework.cloud</groupId>
    <artifactId>spring-cloud-gcp-starter-pubsub</artifactId>
</dependency>
  • Configure Google Cloud Pub/Sub properties – Add the below property in the application.properties file
spring.cloud.gcp.pubsub.project-id=your-project-id

Replace “your-project-id” with the GCP Project ID

  • Create a PubSubTemplate Bean – Create a PubSubTemplate bean
import org.springframework.cloud.gcp.pubsub.core.PubSubTemplate;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;

@Configuration
public class PubSubConfig {

    @Bean
    public PubSubTemplate pubSubTemplate() {
        return new PubSubTemplate();
    }
}
  • Publish Message – Using the PubSubTemplate bean publish messages in Google Cloud Pub/Sub
import org.springframework.cloud.gcp.pubsub.core.PubSubTemplate;
import org.springframework.stereotype.Service;

@Service
public class PubSubMessagePublisher {

    private final PubSubTemplate pubSubTemplate;

    public PubSubMessagePublisher(PubSubTemplate pubSubTemplate) {
        this.pubSubTemplate = pubSubTemplate;
    }

    public void publishMessage(String topicName, String message) {
        this.pubSubTemplate.publish(topicName, message);
    }
}

In the above code PubSubMessagePublisher service uses the PubSubTemplate to publish messages to the specified Pub/Sub Topic topicName. The message content is provided in the message parameter.

To publish the message, call the publishMessage method of the PubSubMessagePublisher service:

pubSubMessagePublisher.publishMessage("your-topic-name", "Hi! Welcometo Google Cloud Pub/Sub!");

Replace “your-topic-name” with the name of the Google Pub/Sub Topic created in Google Cloud Console.

Q-5). What is the purpose of a Dead-Letter Queue (DLQ) in Google Cloud Pub/Sub, and how do you implement it?

A-5). Dead-Letter Queue stores those messages that repeatedly fail to be processed by the main message processing flow. When a message repeatedly fails to be processed multiple times due to errors, exceptions, or other issues, Google Cloud Pub/Sub can move those messages to a Dead-Letter Queue.

The implementation steps of Dead-Letter Queue are as follows:

  1. Create a Dead-Letter Topic – Create a Google Cloud Pub/Sub Topic which will be served as a Dead-Letter Queue.
  2. Configure the Main Subscription – While creating a Subscription, set up a retry policy to specify the maximum no. of delivery attempts for messages. You can define the minimum and maximum time between redelivery attempts as well.
  3. Set up the Dead-Letter Subscription – Create a separate subscription in the Dead-Letter Queue topic. It will have a different acknowledgment deadline and retry policy suitable for handling problematic messages.
    Acknowledgment Deadline is the time given to the Subscriber to acknowledge a message before it is considered unacknowledged and retried.
    Retry Policy determines how many times the Pub/Sub service should attempt to redeliver the unacknowledged messages before moving them to Dead-Letter Queue.
  4. Handle the Dead-Letter message – In your application, create a separate message receiver for the Dead-Letter Queue Subscription. When the messages are moved to the Dead-Letter Queue, this receiver will handle them separately and take appropriate actions such as logging, notifying administrators, or attempting to process the messages differently.

Please find a demo code for the above implementation.

import org.springframework.cloud.gcp.pubsub.core.subscriber.MessageReceiver;
import org.springframework.stereotype.Component;
import com.google.cloud.pubsub.v1.AckReplyConsumer;

@Component
public class DeadLetterMessageReceiver implements MessageReceiver {

    @Override
    public void receiveMessage(Message<?> message) {
        String payload = (String) message.getPayload();
        LOGGER.info("Dead-letter message received: {}", payload);
        AckReplyConsumer consumer = (AckReplyConsumer) message.getHeaders().get(GcpPubSubHeaders.ACKNOWLEDGEMENT);
        consumer.ack();
    }
}
Q-6). How can you ensure message ordering in Google Cloud Pub/Sub when using Spring Boot?

A-6). Message ordering is performed by following 3 simple steps are as follows:

  1. Message Grouping → You can create a grouping mechanism so that the messages need to be processed in order to be grouped together. When publishing a message to Pub/Sub, use the attribute groupId that represents the group to which the messages belong.
  2. Create Ordered Queues → Create multiple separate subscription-based message listeners to process messages from each queue. Each worker will listen to a specific subscription representing a message group.
  3. Use a Partition Key → You can use a partition key when creating the Pub/Sub topic. This will ensure that the messages with the same key are sent to the same partition.

A small code walkthrough in support of the above discussions

Publishing Messages

import com.google.cloud.pubsub.v1.Publisher;
import com.google.pubsub.v1.PubsubMessage;
import com.google.protobuf.ByteString;

@Autowired
private Publisher publisher;

public void publishOrderedMessage(String topicName, String message, String groupId) {
    PubsubMessage pubsubMessage =
        PubsubMessage.newBuilder()
                     .setData(ByteString.copyFromUtf8(message))
                     .putAttributes("groupId", groupId) // Add the groupId as an attribute
                     .build();

    ApiFuture<String> messageIdFuture = publisher.publish(pubsubMessage);
}

Consuming Messages

import org.springframework.cloud.gcp.pubsub.core.subscriber.MessageReceiver;
import org.springframework.messaging.Message;
import org.springframework.stereotype.Component;
import com.google.cloud.pubsub.v1.AckReplyConsumer;

@Component
public class PubSubMessageReceiver implements MessageReceiver {

    @Override
    public void receiveMessage(Message<?> message) {
        String payload = (String) message.getPayload();
        LOGGER.info("Received message: {}", payload);
        AckReplyConsumer consumer = (AckReplyConsumer) message.getHeaders().get(GcpPubSubHeaders.ACKNOWLEDGEMENT);
        consumer.ack();
    }
}

The last 2 lines provide a clear idea after consuming the message we are acknowledging it, otherwise, it will still be there in the Topic.

Q-7). What is the significance of the MessageReceiver interface in Spring Cloud GCP Pub/Sub integration?

A-7). The significance of MessageReceiver interface in Spring Cloud GCP Pub/Sub integration is to receive and process messages from the Topic. The key significances are as follows:

  1. Asynchronous Message Processing → Google Cloud Pub/Sub is an asynchronous messaging service, and Spring Cloud enriched that design by implementing MessageReceiverinterface. When a message gets published in the Subscription of a Topic, the receiveMessage method is invoked asynchronously, thus not blocking the execution of the main thread.
  2. Decoupling Message Processing Logic → With the help of this interface, you can decouple the message processing logic and message handling infrastructure.
  3. Custom Message Handling → You can define your own custom logic to handle the data you are consuming from the Topic. With that, you can perform various actions such as data transformation, validation, persistence, or integration with other systems.
  4. Message AcknowledgmentMessageReceiver use one class named AckReplyConsumer which allows you to acknowledge or reject a message.
  5. Integration with Spring messaging → It integrates smoothly with the Spring messaging framework and thus allows to use Spring’s messaging entities as channels, message converters, and message handlers.

MessageReceiver demo code

import org.springframework.cloud.gcp.pubsub.core.subscriber.MessageReceiver;
import org.springframework.messaging.Message;
import org.springframework.stereotype.Component;
import com.google.cloud.pubsub.v1.AckReplyConsumer;

@Component
public class PubSubMessageReceiver implements MessageReceiver {

    @Override
    public void receiveMessage(Message<?> message) {
        String payload = (String) message.getPayload();
        LOGGER.info("Received message: {}", payload);
        AckReplyConsumer consumer = (AckReplyConsumer) message.getHeaders().get(GcpPubSubHeaders.ACKNOWLEDGEMENT);
        consumer.ack();
    }
}
Q-8). How do you handle concurrent message processing in Google Cloud Pub/Sub with Spring Boot?

A-8). The steps that are required to handle the concurrent message processing are as follows:

  1. Thread-safe Message Processing Logic → Multiple threads can execute the processing logic concurrently without causing any issues. Don’t use global variables, rather use synchronized block or local variables to protect shared resources.
  2. Limit the no. of Concurrent Messages → You can limit the no. of concurrent messages, specifying that at a time the consumer will consume this no. of messages and not more than that. And it can be achieved by defining the concurrency property.
  3. Throttle Processing Logic → Implement a throttling mechanism to control the rate at which messages are processed. This helps prevent overloading your application when there’s a sudden surge in message traffic.
  4. Idempotent Processing → It means that don’t process the same message again which you have already processed. And it is essential as message delivery in Pub/Sub is not guaranteed to be exactly once.
  5. Use Spring’s Asynchronous Processing → Annotating your message processing logic with @Asynch annotation, Spring will automatically execute the method on a separate thread from a pool of threads managed by Spring.
  6. Sharding and Partitioning → Sharding and Partitioning allows you to process messages concurrently without contention. This approach can be beneficial when you need to process large volumes of data.
  7. Monitor and Adjust -> Monitor the performance and resource usage of your application and adjust the configurations based on the system’s capabilities and your message processing requirements.

A dummy code to picturesque the above justifications

import org.springframework.scheduling.annotation.Async;
import org.springframework.stereotype.Component;

@Component
public class PubSubMessageProcessor {

    @Async
    public void processMessage(String message) {
        LOGGER.info("Processing message: {}", message);
        try {
            Thread.sleep(1000);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
    }
}
Q-9). What are the potential challenges you might face when integrating Google Cloud Pub/Sub with Spring Boot?

A-9). The potential challenges that you might face while integrating with Google Cloud Pub/Sub are as follows:

  • Asynchronous Communication
  • Message Ordering
  • Message Loss
  • Authentication and Permissions
  • Concurrency and Stability
  • Dead-Letter Queue Management
  • Handling Large Messages
  • Monitoring and Logging
  • Testing with Emulator against Production Setup
  • Understanding Pub/Sub Concepts
Q-10). How do you ensure the security of your Spring Boot application when interacting with Google Cloud Pub/Sub?

A-10). Security is the main factor in whether to access Google Cloud Pub/Sub locally or from the Spring Boot application, the necessary steps are as follows:

  • Authentication and Authorization
    • Use of Service Accounts by which you will access the Google Cloud Pub/Sub from your Spring Boot application locally.
    • Restrict the permissions by granting the least possible privilege to the service accounts.
  • Secure Credential handling
    • Store credentials securely, not to do hard-coding in code or in the properties file, but rather fetch it from the environment variables or configuration management tools to store and manage credentials securely.
    • Use a secret management solution to securely store and retrieve sensitive data, such as service account private keys.
  • Transport Security
    • Use HTTPS, which is a secure protocol
    • Enable Application-level encryption, and encrypt the data before publishing the messages in the Topic.
  • Messages Validation and Sanitization
    • Implement proper validation of data to protect from injection attacks.
    • If your application allows users to provide data in messages, sanitize the input to prevent security vulnerabilities like Cross Side Scripting (XSS).
  • Dead-Letter Queue Security
    • If you are using DLQ for problematic messages, then be sure that only authorized personnel only has access to DLQ.
  • Monitoring and Auditing
    • Implement logging and auditing of interactions between your Spring Boot application with Google Cloud Pub/Sub.
  • Enable Security Features in GCP
    • Configure network firewall rules in GCP to limit access to Pub/Sub and other GCP services from specific IP addresses or networks.
    • Consider using VPC Service Controls to define a security perimeter around your resources, preventing data exfiltration from GCP services.
  • Regular Security Assessments
    • Conduct regular security assessments and code reviews to identify and address potential security vulnerabilities in your Spring Boot application.
Q-11). Explain the concept of acknowledgment deadlines in Google Cloud Pub/Sub and their importance in message processing.

A-11). Whenever you consume a message from Google Cloud Pub/Sub, it is a good practice that you acknowledged the message. Please find below some points that how the acknowledgment deadline works:

  1. At-Least-Once Delivery Semantics → Google Cloud Pub/Sub guarantees at least once delivery of messages. This means that messages are delivered to subscribers one or more times, but they are not duplicated within the Pub/Sub service.
  2. Preventing Message Loss → Pub/Sub ensures that messages are not lost if a subscriber crashes or becomes unresponsive during message processing. If the subscriber does not acknowledge the message, Pub/Sub will redeliver it to another subscriber to ensure that it is processed.
  3. Handling Message Processing Failures → If a subscriber encounters an error or exception during message processing and cannot acknowledge the message, Pub/Sub will redeliver it, allowing the application to retry the processing until it is successful.
  4. Idempotent Processing → Acknowledgment deadlines encourage idempotent message processing. Since messages may be redelivered if not acknowledged, subscribers must implement idempotent processing to avoid duplicate processing of the same message.
  5. Configurable Acknowledgment Deadlines → Pub/Sub allows you to configure the acknowledgment deadline when creating a subscription. Longer acknowledgment deadlines provide more time for processing but may delay message redelivery in case of processing failures.
  6. Dead-Letter Queue Handling → If a message repeatedly fails to be acknowledged within its deadline, Pub/Sub can move the message to a Dead-Letter Queue (DLQ). This DLQ allows developers to handle problematic messages separately and investigate and resolve any underlying issues.
Q-12). How do you monitor and troubleshoot issues related to Google Cloud Pub/Sub integration in a Spring Boot application?

A-12). The points need to follow to monitor and troubleshoot issues related to a Google Cloud Pub/Sub integration are as follows:

  • Logging and Error Handling – Use structured logging to include essential details such as message IDs, timestamps, and processing status.
    Handle errors gracefully and log any exceptions that occur during message processing.
  • Cloud Monitoring and Logging – Enable Google Cloud Monitoring and Google Cloud Logging to monitor and collect logs related to your Pub/Sub topics and subscriptions.
    Use Stackdriver logging to review and analyze application logs and diagnose any issues related to message processing.
  • Dead-Letter Queue – Utilize a Dead-Letter Queue to isolate problematic messages that repeatedly fail to be processed.
  • Error Reporting and Alerting – Set up error reporting and alerting to receive notifications when critical errors or exceptions occur in your application.
  • Monitoring Dashboards – Monitor and analyze these metrics regularly to identify trends and potential performance issues.
  • Performance Profiling – Use performance profiling tools to analyze the performance of your application during message processing.
  • Testing in a Production-like environment – Test your Pub/Sub integration in a production-like environment to identify any issues that may only manifest in real-world scenarios.
  • Request Tracing – Enable distributed tracing to trace the flow of messages and identify the processing path across your Spring Boot application.
    Use tools like OpenTelemetry or Zipkin to capture trace data and diagnose performance issues.
  • Version Control and Rollback Plans – Use of Version Control of your Spring Boot application to facilitate easier rollback in case of issues came for new changes. There should be a rollback plan as well to quickly revert to the working version if necessary.
Q-13). Can you explain the benefits and use cases of Google Cloud Pub/Sub’s pull and push subscriptions?

A-13). Google Cloud Pub/Sub offers 2 types of subscriptions, which are as follows: Push and Pull Subscriptions

  • Push Subscriptions:
    • Benefits:
      • Automatic Delivery → With push subscriptions, Google Cloud Pub/Sub automatically delivers messages to a predefined endpoint (HTTP/HTTPS) in near real-time as soon as they are published.
      • Low Latency → Push subscriptions offer lower latency for message delivery since the messages are immediately pushed to the subscriber without any additional polling delay.
      • Reduced Overhead → Push subscriptions eliminate the need for the subscriber to continuously poll the Pub/Sub service for new messages, reducing network and processing overhead.
    • Use Cases:
      • Real-Time Applications → Push subscriptions are ideal for real-time applications where low message latency is crucial, such as real-time analytics, event-driven systems, or instant notifications.
      • WebHooks and APIs → Push subscriptions are often used with WebHooks and APIs to deliver data to external systems and services in real-time.
      • Stateless Subscribers → Push subscriptions work well with stateless subscribers that don’t need to maintain long-lived connections with the Pub/Sub service.
  • Pull Subscriptions:
    • Benefits:
      • Manual Control → With pull subscriptions, subscribers have full control over when and how to retrieve messages. They explicitly pull messages from the Pub/Sub service at their desired pace.
      • Load Balancing → Multiple subscribers can share a pull subscription, and the messages are evenly distributed among the subscribers, allowing for load balancing across multiple instances of the subscriber application.
      • Decoupled Processing → Pull subscriptions enable a decoupled architecture, where the subscriber can consume messages independently of the rate at which messages are produced.
    • Use Cases:
      • Batching → Pull subscriptions are suitable for scenarios where you want to batch-process messages or control the size of the message batch.
      • Variable Processing Time → If the processing time of each message varies significantly, pull subscriptions provide more flexibility for subscribers to handle messages as needed.
      • Dynamic Scaling → Pull subscriptions allow you to dynamically scale the number of subscriber instances based on the workload and message processing rate.
Q-14). How can you handle large message payloads in Google Cloud Pub/Sub with Spring Boot?

A-14). In Google Cloud Pub/Sub, handling large messages with Spring Boot requires consideration of the message size limitation imposed by Pub/Sub. Currently, the maximum size of a single message payload is 10 MB. If your application deals with larger payloads, then you have several options to handle this limitation:

  1. Message Chunking → Divide the large payload into smaller chunks (messages) that are within the size limit and publish them to Pub/Sub individually. On the subscriber side, reassemble the message chunks to reconstruct the original payload.
  2. Message Reference → Instead of sending the entire payload in the message, store the large payload in an external storage service, such as Google Cloud Storage (GCS) or Google Cloud Firestore. In the Pub/Sub message, include a reference or identifier to the external storage location. The subscriber can then retrieve the complete payload from the storage service using the reference.
  3. Compression → Compress the payload before publishing it to Pub/Sub, and decompress it on the subscriber side. Compression reduces the message size, enabling you to work with larger payloads while staying within the 10 MB limit.
  4. Data Preprocessing → If the payload contains large binary files or attachments, consider processing and storing them separately, and include references or links to these files in the Pub/Sub message.
  5. Use Multiple Messages → If the payload cannot be divided into chunks, consider splitting it into multiple smaller logical messages, each containing a portion of the data. Process these messages individually on the subscriber side.

A small snippet of code in support of Message Chunking

import com.google.cloud.pubsub.v1.Publisher;
import com.google.pubsub.v1.PubsubMessage;
import com.google.protobuf.ByteString;

@Autowired
private Publisher publisher;

public void publishLargeMessage(String topicName, byte[] largePayload) {
    int chunkSize = 1024 * 1024; // 1 MB chunk size
    // Split the large payload into smaller chunks
    for (int i = 0; i < largePayload.length; i += chunkSize) {
        int endIndex = Math.min(i + chunkSize, largePayload.length);
        byte[] chunk = Arrays.copyOfRange(largePayload, i, endIndex);
        PubsubMessage pubsubMessage =
            PubsubMessage.newBuilder()
                         .setData(ByteString.copyFrom(chunk))
                         .build(); // Publish each chunk as a separate message
        publisher.publish(pubsubMessage); // Publish the chunk to Pub/Sub
    }
}

On the subscriber side, you would reassemble the chunks to reconstruct the original payload based on the order of the received messages.

Q-15). What are the different retry policies available in Google Cloud Pub/Sub, and how can you configure them in your Spring Boot application?

A-15). In Google Cloud Pub/Sub, there are 2 types of retry policies as follows:

  1. Acknowledgment (ACK) Deadline Exceeded
    • When a subscriber receives a message from a subscription, it has a specific amount of time to acknowledge the message before the acknowledgment deadline expires.
    • If the subscriber does not acknowledge the message within the deadline, Pub/Sub assumes that the message processing was not successful, and it will attempt to redeliver the message to another subscriber.
    • By default, the acknowledgment deadline is set to 10 seconds.
  2. Retry on NACK
    • If a subscriber explicitly rejects (NACKs) a message (by sending a negative acknowledgment), Pub/Sub can be configured to redeliver the message to the same or another subscriber for retry.
    • You can set the maximum number of retry attempts for NACKed messages, allowing Pub/Sub to retry the message processing multiple times before giving up.

Now let’s see to configure the above 2 properties in the Spring Boot application using the Spring Cloud Pub/Sub integration:

  • Configuring Acknowledgment Deadline Exceeded
import com.google.cloud.pubsub.v1.SubscriptionAdminClient;
import com.google.cloud.pubsub.v1.SubscriptionAdminSettings;
import com.google.pubsub.v1.Subscription;
import com.google.pubsub.v1.TopicName;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.cloud.gcp.pubsub.core.PubSubTemplate;

@Autowired
private PubSubTemplate pubSubTemplate;

public void createSubscriptionWithAckDeadline(String subscriptionName, String topicName, int ackDeadlineSeconds) {
    TopicName topic = TopicName.of("your-project-id", topicName);
    SubscriptionAdminClient subscriptionAdminClient = SubscriptionAdminClient.create(SubscriptionAdminSettings.newBuilder().build());
    Subscription subscription =
        subscriptionAdminClient.createSubscription(
            Subscription.newBuilder()
                .setName(subscriptionName)
                .setTopic(topic.toString())
                .setAckDeadlineSeconds(ackDeadlineSeconds)
                .build()
        );
    subscriptionAdminClient.close();
    pubSubTemplate.subscribe(subscriptionName, this::processMessage);
}
  • Configuring retry on NACK
import org.springframework.cloud.gcp.pubsub.core.subscriber.PubSubSubscriberOperations;
import org.springframework.cloud.gcp.pubsub.integration.inbound.PubSubInboundChannelAdapter;

@Autowired
private PubSubSubscriberOperations pubSubSubscriberOperations;

public void configureSubscriptionWithRetryOnNACK(String subscriptionName, String topicName, int maxAttempts) {
    PubSubInboundChannelAdapter adapter =
        pubSubSubscriberOperations.inboundAdapter(subscriptionName, (message, acknowledgment) -> {
            try {
                // Your message processing logic here
                // If processing fails, throw an exception to trigger NACK
                throw new RuntimeException("Processing failed");
            } catch (Exception e) {
                // Handle exceptions and trigger NACK
                acknowledgment.nack();
            }
        });
    adapter.setMaxAttempts(maxAttempts); // Set the maximum number of retry attempts for NACKed messages
}