Your checkout service should not have to wait for analytics, email, inventory, and fraud-detection systems before responding to a customer. Google Cloud Pub/Sub helps these systems communicate asynchronously without tightly coupling them together.
Modern applications generate a constant stream of events: orders are placed, files are uploaded, devices report measurements, and users click buttons. Processing every event synchronously can make an application slow and fragile.
Google Cloud Pub/Sub is a managed messaging service for exchanging these events reliably and at scale.
What is Pub/Sub?
Pub/Sub follows the publish-subscribe pattern:
- A publisher produces a message.
- The publisher sends it to a topic.
- A subscription represents a consumer's interest in that topic.
- A subscriber receives and processes messages through the subscription.
The publisher does not need to know which services consume the event or whether they are currently online. This separation is called decoupling.
Each subscription receives its own copy of a topic's messages. If multiple subscriber instances consume from the same subscription, they share the work instead of each receiving a copy.
How does it work?
Consider an online store:
- The order service publishes an
order.createdevent. - Pub/Sub stores and routes the message to subscriptions attached to the topic.
- Email, inventory, and analytics subscribers process the event independently.
- Each subscriber acknowledges successful processing.
If the analytics system is temporarily unavailable, checkout can still succeed. Pub/Sub retains the unacknowledged message and attempts delivery again.
A typical message contains a payload plus optional attributes:
{
"data": {
"orderId": "ORD-1042",
"customerId": "C-51",
"total": 89.99
},
"attributes": {
"eventType": "order.created",
"source": "checkout-service"
}
}
Attributes are useful for metadata and subscription filtering, while the data field carries the main event payload.
Pull versus push subscriptions
Pub/Sub supports different delivery approaches, but pull and push are the most common.
| Type | How delivery starts | Good fit |
|---|---|---|
| Pull | The subscriber requests messages | Workers that need control over concurrency, batching, and processing rate |
| Push | Pub/Sub sends an HTTPS request to an endpoint | Webhooks, Cloud Run services, and simple serverless consumers |
Google's high-level client libraries commonly use StreamingPull, maintaining an open connection and delivering messages asynchronously.
With push delivery, a successful HTTP response acknowledges the message. A failure response or no successful response before the deadline causes Pub/Sub to retry.
ACK: Processing succeeded
An ACK, or acknowledgment, tells Pub/Sub:
I successfully processed this message. It no longer needs to be delivered on this subscription.
For a Python pull subscriber, the essential pattern looks like this:
def callback(message):
try:
process_order(message.data)
message.ack()
except Exception:
message.nack()
The important rule is: ACK only after the required work succeeds.
Acknowledging before writing to a database or calling a required downstream service can cause data loss from the application's perspective. If the process crashes after the early ACK, Pub/Sub considers the message complete.
NACK: Try this again
A NACK, or negative acknowledgment, tells Pub/Sub that processing did not complete and the message should become eligible for redelivery.
Useful reasons to NACK include:
- A database is temporarily unavailable.
- A dependency returns a retryable error.
- The subscriber is shutting down before processing finishes.
A NACK does not mean discard this message. It normally means redeliver it. In the lower-level API, a NACK is represented by setting the message's acknowledgment deadline to zero.
What is the acknowledgment deadline?
After delivering a message, Pub/Sub gives the subscriber a limited period called the acknowledgment deadline.
During that time, the message is considered outstanding. If it is not acknowledged before the deadline expires, Pub/Sub can deliver it again possibly to another subscriber instance using the same subscription.
High-level client libraries can automatically extend the deadline while a callback is still processing. Even so, subscribers should avoid unbounded work and should monitor expired acknowledgment deadlines.
Because redelivery can occur, handlers should be idempotent: processing the same message more than once should not create an incorrect result.
For example, use orderId as an idempotency key before charging a card or creating a shipment.
Pub/Sub also offers an exactly-once delivery option for pull subscriptions, but application-level idempotency remains a valuable defense against failures outside the messaging service.
Retries and poison messages
Not every failure is temporary. A malformed event may fail every time it is delivered. Repeatedly NACKing it can waste resources and delay useful work.
For production systems:
- Configure an exponential-backoff retry policy for temporary failures.
- Configure a dead-letter topic for messages that exceed the allowed delivery attempts.
- Alert on growing subscription backlogs and expired ACK deadlines.
- ACK intentionally ignored messages instead of repeatedly NACKing them.
A dead-letter subscriber can inspect failed events without blocking the main processing path.
Where is Pub/Sub useful?
1. Event-driven microservices
An order event can trigger inventory, notifications, loyalty points, and analytics without adding direct dependencies to the checkout service.
2. Streaming data ingestion
Applications and IoT devices can publish events that are processed by Dataflow or loaded into analytics systems such as BigQuery.
3. Background work and burst absorption
A service can publish work faster than workers can briefly process it. The subscription backlog acts as a buffer while workers scale out or catch up.
Why choose it over alternatives?
Choose Pub/Sub when you want a managed, scalable event bus, asynchronous communication, and easy one-to-many fan-out without managing messaging servers.
However, it is not automatically the best choice for every asynchronous task:
- Choose Cloud Tasks when the producer must target a specific endpoint and needs task-level scheduling or delivery-rate control.
- Consider Apache Kafka when your architecture requires direct control over partitions, brokers, or log-oriented consumption patterns and your team accepts the added operational model.
- Use a synchronous API when the caller needs an immediate result before it can continue.
The key question is not Which tool is most powerful? It is Which delivery and ownership model matches the problem?
Final takeaway
Pub/Sub creates a reliable boundary between event producers and consumers:
- Topics receive messages.
- Subscriptions create independent delivery streams.
- ACK confirms successful processing.
- NACK requests redelivery after a failure.
- Ack deadlines, retries, idempotency, and dead-letter topics make failure handling explicit.
Once ACK and NACK behavior is clear, Pub/Sub becomes much easier to reason about and event-driven systems become easier to scale without turning every service into a dependency of every other service.










