Tutorialsteacher

Follow Us

Articles
  • C#
  • ASP.NET Core
  • ASP.NET MVC
  • LINQ
  • Inversion of Control (IoC)
  • Web API
  • JavaScript
  • TypeScript
  • jQuery
  • Angular 11
  • Node.js
  • D3.js
  • Sass
  • Python
  • Go lang
  • HTTPS (SSL)
  • Regex
  • SQL
  • SQL Server
  • PostgreSQL
  • MongoDB
Entity Framework Extensions - Boost EF Core 9
  Bulk Insert
  Bulk Delete
  Bulk Update
  Bulk Merge
  • All
  • C#
  • MVC
  • Web API
  • Azure
  • IIS
  • JavaScript
  • Angular
  • Node.js
  • Java
  • Python
  • SQL Server
  • SEO
  • Entrepreneur
  • Productivity

Implementing the Publisher Subscriber Pattern in Node.js with Redis

A REST call waits. That's the deal - Service A asks, Service B answers, nothing moves until the response lands. Fine at low traffic. Push it to ten thousand requests a second and one slow dependency starts dragging everything else down with it. Microservices need some way to talk without every single one of them staying awake and responsive at the exact same moment. Publisher-Subscriber is that way. What follows: the theory behind it, why Node.js and Redis make an unusually good pair for it, and a working build.

Pub/Sub vs REST: Rethinking the Conversation Between Services

REST is a conversation where one side has to shut up and wait. Service A calls B, B is busy, A sits there burning a connection slot until something happens. String a dozen services together in a request chain and a single sluggish node can stall the entire path. That's the real cost of synchronous coupling — not that it's slow exactly, but that it links the fate of unrelated services together.

Pub/Sub cuts that link. A publisher drops an event and walks away. It has no idea who's listening, doesn't count subscribers, doesn't wait for a response. Whoever's subscribed picks the message up on their own schedule. Telecom networks lean on this constantly - call records, billing triggers, network status pings, all flowing continuously and unpredictably. It's part of why IT solutions for telecom industry providers like DXC build around event-driven pipelines rather than chains of direct calls: a stalled billing service shouldn't be able to freeze call routing.

Same pressure shows up anywhere traffic spikes without warning — flash sales, IoT fleets, transaction bursts in fintech. What Pub/Sub actually buys:

  • Loose coupling: publisher and subscriber never need to know each other exist.
  • Scale sideways: add subscribers without touching the publisher.
  • Isolation: one crashed subscriber doesn't take down the rest.
  • Event-native workflows: order placed, payment confirmed, email sent, each step independent.

Simple on paper. The real work is picking infrastructure that's actually fast enough to make the whole exercise worth it.

Why Node.js and Redis Pair So Naturally

Neither of these tools was built with waiting in mind. Node doesn't spin up a thread every time a connection opens — its event loop just queues up callbacks and fires them off the second I/O wraps up. A subscriber written in Node isn't sitting there checking for new messages every few seconds. It hands off a callback once, and the loop wakes that callback the moment something lands. Nothing spinning idle in the background.

Redis covers the other half. Its Pub/Sub lives entirely in memory, so, a published message can reach a subscriber in microseconds. Compare that to the milliseconds (sometimes worse) a disk-backed broker needs, and the gap starts to matter at scale. Every channel exists inside Redis itself, and each client subscribed to it gets handed its own copy the moment something's published.

A handful of things are worth knowing going in, though:

  • No persistence. Nobody subscribed when a message fires? It's gone.
  • At-most-once delivery. No acknowledgment system, no retry.
  • Fast. Thousands of messages per second without much overhead.
  • Tiny API. PUBLISH, SUBSCRIBE, UNSUBSCRIBE — that's most of it.

Why does that combination matter so much? Because teams reaching for something event-driven (live notifications, chat, cache invalidation, a dashboard that updates itself) usually try Redis first, and a lot of them never end up needing anything more.

Building It: A Minimal Working Example

Client Setup

One thing that trips people up early: a Redis client sitting in subscribe mode can't run anything else. Publishing and subscribing each need their own client instance — trying to share one just breaks.

Example: Arguments Object
// redisClient.js
const { createClient } = require('redis');
 
async function createRedisClient() {
  const client = createClient({ url: 'redis://localhost:6379' });
  client.on('error', (err) => console.error('Redis error:', err));
  await client.connect();
  return client;
}
 
module.exports = createRedisClient;

Publisher

Example: Arguments Object
// publisher.js
const createRedisClient = require('./redisClient');
 
(async () => {
  const publisher = await createRedisClient();
  let orderId = 1000;
 
  setInterval(async () => {
    const order = { id: orderId++, amount: (Math.random() * 200).toFixed(2) };
    await publisher.publish('orders.new', JSON.stringify(order));
    console.log('Published:', order);
  }, 2000);
})();

Publisher

Example: Arguments Object
// subscriber.js
const createRedisClient = require('./redisClient');
 
(async () => {
  const subscriber = await createRedisClient();
  await subscriber.subscribe('orders.new', (message) => {
    const order = JSON.parse(message);
    console.log(`Order #${order.id} — $${order.amount}`);
  });
})();

Fire up subscriber.js in one terminal window, then publisher.js in a second. Within a couple seconds, orders should start printing on the subscriber's side. Now try the opposite — start the subscriber a beat late, once the publisher's already pushed a few events out. Those earlier ones? Gone. Never show up, no backlog waiting to be delivered. That's the fire-and-forget nature of the whole system showing itself early, and honestly, it ends up steering most of the decisions that come later.

Production Notes: What Actually Breaks

Everything looks fine on a laptop. Production has a way of finding the parts that don't hold up. A grab bag of the usual suspects:

  • Connections drop. Not a maybe — it will happen. Network blips, server restarts, a load balancer timing out on an idle socket. Hook into the error and reconnecting events, because from the outside a silently dropped connection looks exactly like one that's just quietly idle.
  • This isn't a durable queue, and it's easy to forget that. Probably the single most common mistake — no subscriber connected at the moment a message fires means that message is gone for good. If losing data isn't an option (payments, order fulfillment, anything that gets audited), Redis Streams or an actual broker like Kafka is the right tool. Pub/Sub belongs somewhere lower-stakes: typing indicators, live cursor positions, cache invalidation, a counter ticking up on a dashboard.
  • Ordering isn't as solid as it seems. Redis holds order per channel, per client but that guarantee falls apart the moment two publishers hit the same channel at once, or a subscriber processes messages asynchronously without lining them up first. Timestamp the payload if getting the sequence right actually matters.
  • A slow subscriber just misses things. There's no buffer sitting behind each subscriber waiting to catch it up. If a callback takes too long, it doesn't get a second chance at what fired while it was busy — that data's simply gone. Keep the callback itself light; hand off anything heavy to a job queue instead of running it right there inline.
  • Channel names turn into a mess fast. A flat pile of channel strings gets unmanageable the moment an app grows past a handful of event types. Namespacing helps (orders.created, orders.cancelled, users.updated) and PSUBSCRIBE with a wildcard like orders.* lets a subscriber catch an entire category without hardcoding every channel by hand.
  • One bad payload can take every subscriber down with it. Redis just moves raw strings — there's no schema check built in anywhere. A single malformed JSON message from a misbehaving publisher will throw an unhandled exception in every subscriber that isn't guarding against it.
Example: Arguments Object
try {
  const data = JSON.parse(message);
} catch {
  console.error('Bad payload, skipping');
}

Redis Pub/Sub was never meant to cover every messaging scenario — it gives up durability in exchange for speed, plain and simple. But for anything real-time that doesn't need those guarantees, Node.js paired with Redis still holds up well: fast to set up, holds together under load, and stays small enough that tracking down a bug doesn't turn into a whole afternoon lost.

TUTORIALSTEACHER.COM

TutorialsTeacher.com is your authoritative source for comprehensive technologies tutorials, tailored to guide you through mastering various web and other technologies through a step-by-step approach.

Our content helps you to learn technologies easily and quickly for learners of all levels. By accessing this platform, you acknowledge that you have reviewed and consented to abide by our Terms of Use and Privacy Policy, designed to safeguard your experience and privacy rights.

[email protected]

ABOUT USTERMS OF USEPRIVACY POLICY
copywrite-symbol

2024 TutorialsTeacher.com. (v 1.2) All Rights Reserved.