ResourcesData

Understanding the Pub/Sub Pattern for Event-Driven Architectures

Explore the publish-subscribe (pub/sub) pattern, its components, and how it enables decoupled, scalable systems. Learn to orchestrate real-time pub/sub workflows with Kestra, handling streaming data and event-driven logic.

TL;DR — The publish-subscribe (Pub/Sub) pattern is a messaging architecture where message senders (publishers) broadcast messages to an intermediary channel (topic), without knowing the receivers (subscribers). Subscribers express interest in specific topics and receive messages asynchronously, enabling decoupled, scalable, and resilient communication in distributed systems.

Building modern distributed systems means navigating a landscape of interconnected services, each needing to communicate efficiently without becoming tightly coupled. The challenge often lies in ensuring that one component’s state or failure doesn’t ripple across the entire architecture, leading to brittle, hard-to-maintain systems.

This is where the publish-subscribe (Pub/Sub) pattern provides a powerful solution. By decoupling message senders from receivers, Pub/Sub allows components to operate independently, react to events, and scale with unprecedented flexibility. This article will explain how Pub/Sub works, its core benefits, and how Kestra can orchestrate these event-driven workflows to build resilient, real-time applications.

How the Publish-Subscribe Pattern Works

The Pub/Sub pattern is an asynchronous communication model that enables services to exchange messages without direct knowledge of each other. This is achieved through an intermediary component, the message broker, which manages the distribution of messages.

The core components of the Pub/Sub pattern are:

  • Publishers: These are the components that create and send messages. A publisher does not send messages directly to a specific receiver. Instead, it categorizes each message into a specific class known as a topic. The publisher’s responsibility ends once the message is sent to the message broker; it has no awareness of who, if anyone, is listening.
  • Subscribers: These components express interest in one or more topics. When a subscriber “subscribes” to a topic, it registers with the message broker to receive all messages published to that topic. A subscriber can be interested in multiple topics, and multiple subscribers can listen to the same topic.
  • Message Broker (or Topic/Channel): This is the central hub of the Pub/Sub system. It receives messages from publishers and routes them to all interested subscribers. The broker is responsible for filtering messages based on topics and ensuring they are delivered. This intermediary layer is what enforces the decoupling between publishers and subscribers.

This model forms the foundation of event-driven orchestration, where system behavior is determined by the production, detection, and consumption of events.

Why Event-Driven Architectures Need Pub/Sub Orchestration

The Pub/Sub pattern is more than just a communication mechanism; it’s a foundational element for building robust, scalable, and maintainable distributed systems.

  • Enhanced Scalability and Flexibility: Because publishers and subscribers are independent, you can scale them separately. If message volume increases, you can add more subscribers to process the load without any changes to the publishers. New services can be added to the system by simply subscribing to relevant topics, allowing the architecture to evolve with minimal friction.
  • Improved System Resilience: The decoupling provided by the message broker acts as a buffer. If a subscriber service fails, messages can be retained by the broker and delivered once the service recovers. Publishers can continue sending messages even if some subscribers are offline, preventing cascading failures across the system.
  • Simplified Integrations: Pub/Sub simplifies the integration of disparate systems. A single event, like a new user registration, can be published to a topic and consumed by multiple services simultaneously—an analytics service, a welcome email service, and a CRM update service—all without the registration service needing to know about or integrate with each of them directly.

However, implementing this pattern in a production environment introduces its own set of challenges. You need to handle message retries, manage data transformations, ensure idempotent processing to prevent duplicate data, and alert on failures. This is where an orchestration platform becomes essential, providing the control and visibility needed to manage these complex, real-time data flows reliably. The choice between batch vs. streaming processing also becomes a critical design decision managed by the orchestrator.

Orchestrate Real-Time Pub/Sub Workflows with Kestra: An Example

Let’s consider a practical scenario: a service publishes an event for every new user signup to a Google Cloud Pub/Sub topic. We need a workflow that listens to this topic in real time, extracts user data, and inserts it into a PostgreSQL customer database. If the database operation fails, an alert should be sent to a Slack channel.

Kestra can orchestrate this entire process with a declarative YAML workflow.

id: gcp-pubsub-to-postgres
namespace: company.team.production
tasks:
- id: log_message
type: io.kestra.plugin.core.log.Log
message: "Received message with ID: {{ trigger.messageId }}"
- id: insert_user
type: io.kestra.plugin.jdbc.postgresql.Query
url: "{{ secret('POSTGRES_URL') }}"
username: "{{ secret('POSTGRES_USER') }}"
password: "{{ secret('POSTGRES_PASSWORD') }}"
sql: |
INSERT INTO users (id, email, created_at)
VALUES ('{{ trigger.data.id }}', '{{ trigger.data.email }}', NOW())
ON CONFLICT (id) DO NOTHING;
fetch: ONE
errors:
- id: slack_alert_on_failure
type: io.kestra.plugin.notifications.slack.SlackIncomingWebhook
url: "{{ secret('SLACK_WEBHOOK_URL') }}"
payload: |
{
"text": "Failed to process Pub/Sub message for execution `{{ execution.id }}`.",
"blocks": [
{
"type": "section",
"text": {
"type": "mrkdwn",
"text": "*Pub/Sub to Postgres Workflow Failed* :x:\nExecution: `{{ execution.id }}`\nNamespace: `{{ flow.namespace }}`\nFlow: `{{ flow.id }}`"
}
},
{
"type": "section",
"text": {
"type": "mrkdwn",
"text": "Error in task `{{ taskrun.id }}`: ```{{ error.message }}```"
}
}
]
}
triggers:
- id: listen_for_signups
type: io.kestra.plugin.gcp.pubsub.RealtimeTrigger
topic: "projects/your-gcp-project/topics/user-signups"
subscription: "kestra-user-signups-sub"
serviceAccount: "{{ secret('GCP_SERVICE_ACCOUNT') }}"

A few things are worth noticing in this workflow:

  • Real-Time Execution: The io.kestra.plugin.gcp.pubsub.RealtimeTrigger listens continuously and starts a new workflow execution the moment a message arrives, enabling millisecond-level event processing. You can find more details in the Realtime Trigger documentation.
  • Robust Error Handling: The errors block automatically catches any failure in the main tasks (like the database being unavailable) and executes the Slack notification task, providing immediate visibility into problems.
  • Declarative Data Handling: The workflow uses Pebble expressions like {{ trigger.data.id }} to directly access the JSON payload from the Pub/Sub message, simplifying data transformation and integration.
  • Idempotent Inserts: The SQL query uses ON CONFLICT DO NOTHING to ensure that if the same message is accidentally processed twice, it won’t create duplicate records, making the pipeline more resilient. For more complex logic, you could use a Switch task to handle different event types.

This example demonstrates how Kestra elevates a simple Pub/Sub message into a fully orchestrated, reliable, and observable data pipeline. You can explore a similar pattern in the Process Pub/Sub Messages into Postgres in Real Time blueprint.

Deciding Between Real-time and Batch Pub/Sub Processing

While real-time processing is powerful, it’s not always the optimal choice. Kestra supports both real-time and micro-batching patterns for Pub/Sub.

  • Choose real-time processing when your use case demands immediate action and low latency, such as fraud detection, real-time bidding, or instant user notifications. The RealtimeTrigger is designed for these scenarios.
  • Choose micro-batching when you need to optimize for cost and resource usage, and a slight delay is acceptable. For example, you can use a standard PubSub trigger on a short schedule (e.g., every minute) to pull all available messages and process them as a single batch. This is highly efficient for loading data into data warehouses. A great example of this is the blueprint to Stream Pub/Sub Events into BigQuery with Micro-Batching.

As a rule of thumb, if the business value is tied to the immediacy of the event, use real-time. If it’s tied to the completeness of data over a short period, micro-batching is often more efficient.

Where the Pub/Sub Pattern Excels

The Pub/Sub pattern is versatile and foundational to many modern applications. Its primary use cases include:

  • Real-time Analytics: Ingesting and processing high-volume event streams from IoT devices, user activity logs, or financial markets to power live dashboards and analytics.
  • Event-Driven Microservices: Enabling communication between microservices without creating direct dependencies, allowing them to evolve and scale independently.
  • Notification Systems: Distributing notifications (e.g., email, SMS, push notifications) to a large number of users efficiently. A single event can trigger notifications across multiple channels.
  • Data Synchronization: Keeping data consistent across multiple distributed databases or caches. A change in one system can be published as an event and consumed by others to update their state.

By leveraging Pub/Sub, you can create data pipelines that are not only powerful but also inherently scalable and resilient, a key reason why Kestra is becoming a real-time orchestration platform.

Ready to implement robust, event-driven architectures? Explore Kestra’s open-source orchestration capabilities and start building your first Pub/Sub workflow today.

Frequently asked questions

Find answers to your questions right here, and don't hesitate to Contact Us if you couldn't find what you're looking for.