DEV Community

Cover image for Publish-Subscribe: How Modern Systems Scale Without Becoming a Monolith
Anik Sikder
Anik Sikder

Posted on • Originally published at aniksikder.hashnode.dev

Publish-Subscribe: How Modern Systems Scale Without Becoming a Monolith

When an online order is placed, the customer sees a simple message:

"Your order has been confirmed."

Behind that message, however, an entire chain of events begins.

The inventory must be updated.

The payment must be recorded.

The customer should receive an email.

Analytics dashboards need updating.

Fraud detection systems may need to run.

Loyalty points might need to be awarded.

Shipping labels may need to be generated.

In small systems, developers often connect these actions directly.

Order Service
 ├── Update Inventory
 ├── Send Email
 ├── Update Analytics
 ├── Create Invoice
 └── Start Shipping
Enter fullscreen mode Exit fullscreen mode

At first, this seems perfectly reasonable.

Then the business grows.

And everything starts breaking.


The Architecture That Works Until It Doesn't

Imagine an e-commerce platform processing 50 orders per day.

A customer places an order.

The Order Service directly calls:

Inventory Service
Email Service
Analytics Service
Billing Service
Shipping Service
Enter fullscreen mode Exit fullscreen mode

Everything succeeds.

Everyone is happy.

The architecture appears simple.

The problem is that simplicity is deceptive.

The Order Service now depends on every downstream service.

If any one of them is slow, the entire workflow becomes slow.

If any one of them fails, the customer experience can fail.

The more business capabilities added, the larger this dependency chain becomes.

Over time the Order Service quietly transforms into the center of the entire company.

Every new feature adds another dependency.

Every new dependency increases risk.


A Real Failure Scenario

Consider this order workflow:

Customer
    ↓
Order Service
    ↓
Inventory Service
    ↓
Email Service
    ↓
Analytics Service
Enter fullscreen mode Exit fullscreen mode

One day the Email Service experiences an outage.

Now what happens?

Many systems accidentally end up with behavior like this:

create_order()

reserve_inventory()

send_confirmation_email()

update_analytics()
Enter fullscreen mode Exit fullscreen mode

Email fails.

The transaction stops.

Analytics never updates.

The customer may not even receive order confirmation.

A problem in one subsystem cascades across the platform.

This is known as tight coupling.

The services are technically separate.

Operationally, they are not.


The Postmortem Nobody Wants to Write

A common production incident looks something like this:

What happened?

A third-party email provider experienced elevated latency.

Impact

Order creation response times increased from:

200ms
Enter fullscreen mode Exit fullscreen mode

to

8-15 seconds
Enter fullscreen mode Exit fullscreen mode

Business Impact

Customers abandoned checkout.

Conversion rates dropped.

Support tickets increased.

Revenue was affected.

Root Cause

The Order Service was waiting for Email Service completion before responding.

Architectural Problem

The platform treated a non-critical operation as a critical dependency.


Notice something important.

The email system wasn't actually required to create the order.

The order should have succeeded regardless.

The architecture created the outage.

Not the email provider.


Enter Publish-Subscribe

Instead of directly calling every service, the Order Service publishes an event.

Order Service
      ↓
Order Created Event
      ↓
Message Broker
      ↓
Inventory
Email
Analytics
Billing
Shipping
Enter fullscreen mode Exit fullscreen mode

Now the Order Service only has one responsibility:

Create Order
Publish Event
Done
Enter fullscreen mode Exit fullscreen mode

It no longer cares who needs the information.

It simply announces:

Order Created
Enter fullscreen mode Exit fullscreen mode

Anyone interested can react.

This changes everything.


Thinking in Events Instead of Calls

Traditional systems think:

Do this.
Then do that.
Then do another thing.
Enter fullscreen mode Exit fullscreen mode

Event-driven systems think:

Something happened.
Whoever cares can respond.
Enter fullscreen mode Exit fullscreen mode

That shift sounds small.

Architecturally, it is enormous.

The producer no longer knows:

  • Who consumes the event

  • How many consumers exist

  • When consumers process it

  • What consumers do with it

The producer simply publishes facts.


The Message Broker Becomes the Traffic Controller

A message broker sits between producers and consumers.

Examples include:

  • Apache Kafka

  • RabbitMQ

  • Amazon SNS

  • Amazon SQS

The broker receives events and distributes them to interested systems.

Publisher
    ↓
Broker
 ├── Inventory
 ├── Email
 ├── Billing
 ├── Analytics
 └── Fraud Detection
Enter fullscreen mode Exit fullscreen mode

Services no longer communicate directly.

The broker acts as the central nervous system.


Why Business Leaders Should Care

Most architectural decisions eventually become business decisions.

Publish-Subscribe creates advantages that executives feel directly.

Faster Feature Delivery

Imagine marketing wants a loyalty points system.

In a tightly coupled architecture:

Modify Order Service
Retest Order Service
Redeploy Order Service
Risk Order Service
Enter fullscreen mode Exit fullscreen mode

In Pub/Sub:

Create Loyalty Consumer
Subscribe to Order Created
Deploy Independently
Enter fullscreen mode Exit fullscreen mode

The order system remains untouched.

New business capabilities can be added safely.


Reduced Revenue Risk

If Analytics fails:

Orders continue.
Payments continue.
Customers continue.
Enter fullscreen mode Exit fullscreen mode

Only analytics is affected.

The failure is isolated.

This dramatically reduces blast radius.


Better Organizational Scaling

As companies grow:

Payments Team
Inventory Team
Data Team
Growth Team
Customer Team
Enter fullscreen mode Exit fullscreen mode

Each team can consume events independently.

Teams become less dependent on one another.

This increases development velocity.


Why Developers Love Event-Driven Systems

Developers eventually discover a painful truth:

The hardest part of scaling is not traffic.

It's dependencies.

Pub/Sub removes many of them.


Loose Coupling

Without Pub/Sub:

Order Service
    ↓
Inventory
    ↓
Email
    ↓
Analytics
Enter fullscreen mode Exit fullscreen mode

With Pub/Sub:

Order Service
      ↓
Broker
      ↓
Consumers
Enter fullscreen mode Exit fullscreen mode

The producer has one dependency.

Instead of ten.


Independent Deployments

A team can deploy:

Recommendation Engine
Fraud Detection
Customer Segmentation
Enter fullscreen mode Exit fullscreen mode

without touching the ordering system.

This dramatically reduces deployment risk.


Better Resilience

Suppose Billing Service crashes.

The broker stores events.

When Billing returns:

Order Created Event #1001
Order Created Event #1002
Order Created Event #1003
Enter fullscreen mode Exit fullscreen mode

can still be processed.

The platform recovers automatically.


But Publish-Subscribe Creates New Problems

Many architecture articles stop at benefits.

Production systems do not.

Every architectural gain introduces tradeoffs.


Problem #1: Eventual Consistency

In synchronous systems:

Order Created
Inventory Updated
Response Returned
Enter fullscreen mode Exit fullscreen mode

Everything happens immediately.

In Pub/Sub:

Order Created
Response Returned

Inventory Updated Later
Enter fullscreen mode Exit fullscreen mode

There is now a time gap.

Systems may temporarily disagree.

This is called:

Eventual Consistency

One of the most misunderstood realities of distributed systems.


Problem #2: Duplicate Events

Networks fail.

Retries happen.

Consumers crash.

The same event may arrive twice.

Order Created #123
Order Created #123
Enter fullscreen mode Exit fullscreen mode

Consumers must be idempotent.

Otherwise:

Inventory reduced twice
Customer charged twice
Enter fullscreen mode Exit fullscreen mode

Production incidents happen.


Problem #3: Observability Becomes Hard

In monolithic workflows:

Request → Response
Enter fullscreen mode Exit fullscreen mode

Easy to trace.

In event-driven systems:

Order Created
    ↓
Inventory Updated
    ↓
Billing Created
    ↓
Email Sent
    ↓
Analytics Updated
Enter fullscreen mode Exit fullscreen mode

A single customer action can generate dozens of events.

Tracking failures becomes significantly harder.

This is why mature organizations invest heavily in:

  • Distributed tracing

  • Correlation IDs

  • Event monitoring

  • Audit logs


How Large Platforms Actually Think

The most successful architectures do not ask:

"Which service should call which?"

Instead they ask:

"What business events exist?"

Examples:

Order Created
Payment Authorized
Shipment Created
Invoice Generated
User Registered
Subscription Renewed
Enter fullscreen mode Exit fullscreen mode

These events become the language of the business.

Systems are then built around reacting to those events.

The result is an architecture that grows with the company instead of fighting it.


The Real Lesson

Publish-Subscribe is not primarily about messaging.

It is about organizational scalability.

It allows systems to evolve without every team depending on every other team.

It reduces blast radius.

It improves resilience.

It accelerates feature delivery.

But it also introduces complexity, eventual consistency, and operational challenges that teams must be prepared to handle.

The companies that scale successfully are rarely the ones with the most services.

They are the ones with the clearest events.

Because once systems start speaking in events instead of direct dependencies, growth becomes far easier to sustain.


Key Takeaway

A mature architecture doesn't ask:

"Who should I call next?"

It asks:

"What happened?"

That single shift from commands to events is one of the biggest architectural transitions in modern software systems.

Top comments (0)