The Digital Post Office: A Guide to Cloud Pub/Sub

Let’s start with a common scenario. You’re building an e-commerce application. When a user finalizes an order, several things need to happen: the inventory service must be updated, a shipping label needs to be created, and a confirmation email must be sent.

The simple approach is to have your main “order” service make direct, sequential API calls to the “inventory,” “shipping,” and “email” services. This is called synchronous communication. The user clicks “Confirm Order,” and their browser waits… and waits… until all three backend services have responded.

But what happens if the email service is slow or temporarily down? The entire order process hangs, and eventually, the user gets an error. Your whole system is brittle. The services are tightly coupled; the failure of one can cause a cascade failure across the entire system. We need a way to decouple them. We need a digital post office.

The Decoupling Revolution

Instead of making direct phone calls, what if our services could communicate by sending letters? The order service’s only job would be to write three letters: “Update inventory for order #123,” “Create shipping label for order #123,” and “Send email for order #123.” It drops them off at a post office and immediately tells the user, “Success! Your order is being processed.”

The order service doesn’t know or care if the email service is busy. It trusts that the post office will hold the letter and deliver it when the email service is ready. This is asynchronous messaging, and it’s the key to building resilient, scalable, and modern applications. In Google Cloud, this post office is Cloud Pub/Sub.

Meet the Digital Postmaster: Cloud Pub/Sub

Cloud Pub/Sub is a fully managed, global, real-time messaging service. It allows you to send and receive messages between independent applications. It’s the central nervous system for many Google services and can scale to handle millions of messages per second.

Let’s look inside this post office and meet its key staff.

The Mailbox (The Topic)

A publisher doesn’t send a message directly to a subscriber. It sends it to a named channel called a Topic. A topic is a simple, named resource that acts as the central hub for a specific type of message. For our e-commerce app, we might create topics like order-confirmations, inventory-updates, and shipping-requests.

Bash

gcloud pubsub topics create order-confirmations

Sending the Mail (The Publisher)

Any application that sends messages to a topic is a Publisher. Our “order” service is a publisher. When an order is confirmed, it creates a message (the “letter”) and sends it to the order-confirmations topic.

Bash

gcloud pubsub topics publish order-confirmations \
    --message="{'orderId': 123, 'userId': 456, 'total': 99.99}"

Subscribing to Mail (The Subscription)

The “email” service needs to receive these order confirmations. It expresses its interest by creating a Subscription to the order-confirmations topic. A subscription is a named resource that represents a stream of messages from a single topic. Think of it as your personal P.O. box for a specific magazine.

Bash

gcloud pubsub subscriptions create email-service-subscriber \
    --topic=order-confirmations

The brilliant part is that multiple, different services can subscribe to the same topic. The “shipping” service can also create its own subscription to the order-confirmations topic. When a single message is published, Pub/Sub delivers a copy of that message to each subscription independently.

Reading the Mail (The Subscriber)

An application that receives messages from a subscription is a Subscriber. Our “email” service and “shipping” service are subscribers. They connect to their respective subscriptions and start processing messages.

Getting Your Mail Delivered: Push vs. Pull

How does a subscriber actually receive the messages? There are two models.

Pull (The Standard Model)

This is the most common and robust method for backend services. The subscriber application actively polls the subscription, asking “Do you have any new messages for me?” This gives the subscriber full control over the rate of message consumption. If it’s busy, it can slow down; if it’s idle, it can ask for more. This is like going to the post office to check your P.O. box.

Push (The Webhook Model)

In this model, Pub/Sub becomes the mail carrier. You provide Pub/Sub with a publicly accessible HTTP endpoint (a webhook). When a message arrives in the topic, Pub/Sub immediately makes an HTTP POST request to your endpoint with the message in the request body. This is simpler for certain use cases, especially for triggering stateless services like Cloud Functions, but can be problematic if you have a sudden burst of messages that could overwhelm your endpoint.

The Certified Mail Guarantee: Acknowledgments & At-Least-Once Delivery

What if your email service pulls a message, and then the VM crashes before it can send the email? Is the message lost forever? No, and the mechanism that prevents this is the most critical concept in Pub/Sub.

When a subscriber receives a message, a timer starts. This is the Acknowledgment (ack) deadline. Your subscriber has this much time (e.g., 60 seconds) to process the message and then send an acknowledgment (ack) back to Pub/Sub, basically saying “I’m done with this one.”

  • If Pub/Sub receives the ack in time, it marks the message as delivered and deletes it from the subscription’s queue.
  • If Pub/Sub does not receive an ack before the deadline expires, it assumes the subscriber failed and redelivers the message.

This leads to a powerful guarantee: at-least-once delivery. Pub/Sub guarantees your message will be delivered, but it also means that in some rare network failure scenarios, it might be delivered more than once.

This has a profound implication for your subscriber design: subscribers must be idempotent. An idempotent operation is one that can be performed multiple times with the same input and have the same result as if it were performed only once. For our email service, it might mean checking a database to see if the email for order #123 has already been sent before trying to send it again.

Handling Problem Mail: Dead-Letter Topics

What happens if a message is malformed and causes your subscriber to crash every single time it tries to process it? Without intervention, Pub/Sub would redeliver that message forever, clogging up your queue.

The solution is a Dead-Letter Topic (DLT). You can configure a subscription to say, “If you’ve tried to deliver a message 5 times and it still hasn’t been acknowledged, stop trying and move it to this other topic.” This gets the poison message out of your main workflow and allows you to inspect it later to debug the problem.

Special Delivery Instructions: Ordering and Filtering

By default, Pub/Sub does not guarantee the order in which messages are delivered. For many use cases, this is fine. But what if you need to process all updates for a specific user in the exact order they happened?

You can enable message ordering on a subscription. When publishing, you provide an ordering key (e.g., the userId). Pub/Sub guarantees that all messages published with the same ordering key will be delivered to a single subscriber in the order they were received.

Additionally, you can create a Subscription with a filter. This allows a subscriber to receive only a subset of messages from a topic. For example, you could add an attribute like priority: "high" to your messages and create a subscription that only receives high-priority orders.

Common Pitfalls & Best Practices

  • Pitfall: Assuming exactly-once delivery and not making your subscribers idempotent. This will lead to duplicate processing and bugs.
  • Best Practice: Always design your subscribers to be idempotent. This is the golden rule of working with Pub/Sub.
  • Pitfall: Setting the ack deadline too short. If your processing takes longer than the deadline, Pub/Sub will think your subscriber failed and redeliver the message, causing an infinite loop.
  • Best Practice: Set your ack deadline to be longer than the expected time it takes to process a message. Your subscriber can also extend the deadline for a specific message if it knows it will take longer.
  • Pitfall: Not using a Dead-Letter Topic for important production workloads. A single poison message can halt your entire processing pipeline.
  • Best Practice: Always configure a DLT on subscriptions that handle critical data.
  • Pitfall: Choosing the Push model for a service that can’t handle sudden, large bursts of traffic.
  • Best Practice: Default to the Pull model for most backend services, as it provides better flow control. Use Push for simple, stateless integrations like triggering Cloud Functions.

Quick Reference Command Center

Here’s a cheatsheet of gcloud commands for managing Pub/Sub.

ActionCommand
Create a Topicgcloud pubsub topics create [TOPIC_NAME]
List Topicsgcloud pubsub topics list
Create a Subscriptiongcloud pubsub subscriptions create [SUB_NAME] --topic=[TOPIC_NAME]
Publish a Messagegcloud pubsub topics publish [TOPIC_NAME] --message="Hello"
Pull Messagesgcloud pubsub subscriptions pull [SUB_NAME] --auto-ack --limit=5
Create Subscription with DLTgcloud pubsub subscriptions create [SUB_NAME] --topic=[TOPIC] --dead-letter-topic=[DLT_TOPIC]
Create Subscription with Filtergcloud pubsub subscriptions create [SUB_NAME] --topic=[TOPIC] --message-filter="attributes.priority = 'high'"
error: Content is protected !!