Build a Cloud‑Native Redis Pub/Sub App with Dapr, Docker Compose, and NestJS
This step‑by‑step guide shows how to create a distributed Redis Pub/Sub application using Dapr, Docker Compose, and NestJS, covering project setup, Dapr placement, Redis publisher, component definition, sidecars, subscription configuration, testing, and CloudEvents JSON handling.
Overview
Dapr (Distributed Application Runtime) is a portable, event‑driven runtime that enables resilient stateless or stateful applications to run on cloud or edge platforms and supports multiple languages and frameworks.
Step‑by‑step implementation
1. Create project directory
mkdir dapr-nestjs-redis-pub-sub2. Initialise Docker Compose
Create docker-compose.yml in the project root.
version: "3.5"
services:
dapr-placement:
image: "daprio/dapr"
command: ["./placement","-port","50006"]The placement service manages Dapr actor routing and acts as a message broker for the runtime.
3. Add Redis publisher service
redis-publisher:
image: redis
restart: always
depends_on:
- dapr-placement4. Define Dapr Pub/Sub component
mkdir -p dapr/components
cd dapr/components
cat > redis-pubsub.yaml <<'EOF'
apiVersion: dapr.io/v1alpha1
kind: Component
metadata:
name: redis-pubsub
namespace: default
spec:
type: pubsub.redis
version: v1
metadata:
- name: redisHost
value: redis-publisher:6379
- name: redisPassword
value: ""
EOFThis component tells Dapr to use the Redis instance at redis-publisher:6379 for Pub/Sub.
5. Add Redis Dapr sidecar
redis-dapr-sidecar:
image: "daprio/daprd:edge"
command: [
"./daprd",
"-app-id","redis-publisher",
"-app-port","6379",
"-dapr-http-port","5000",
"-components-path","/components",
"-placement-host-address","dapr-placement:50006"
]
volumes:
- "./dapr/components/:/components"
depends_on:
- redis-publisher
network_mode: "service:redis-publisher"The sidecar forwards traffic from the Redis container to Dapr and registers the component.
6. Create NestJS subscriber service
npm i -g @nestjs/cli
nest new nest-subscriberUse yarn as the package manager. Replace src/app.controller.ts with:
import { Controller, Post, Body } from '@nestjs/common';
import { AppService } from './app.service';
@Controller()
export class AppController {
constructor(private readonly appService: AppService) {}
@Post('/redis-publisher')
async postRedisPub(@Body() reqBody) {
console.log(`Redis published ${JSON.stringify(reqBody)}`);
return `NestJS subscriber received ${reqBody} publish`;
}
}7. Dockerfile for NestJS server
FROM node:16.13.0-alpine
WORKDIR "/app"
COPY ./nest-subscriber/package.json ./
RUN yarn install
COPY ./nest-subscriber .
RUN yarn run build
EXPOSE 3000
CMD ["yarn","start:prod"]8. Add NestJS service to Docker Compose
nest-subscriber:
image: "nest-subscriber:latest"
depends_on:
- redis-publisher
- dapr-placement
restart: always9. Create Dapr subscription
mkdir -p dapr/subscriptions
cd dapr/subscriptions
cat > redis-subscription.yaml <<'EOF'
apiVersion: dapr.io/v1alpha1
kind: Subscription
metadata:
name: nest-redis-sub
spec:
topic: nest-redis-pub-topic
route: /redis-publisher
pubsubname: redis-pubsub
scopes:
- nest-subscriber
EOFThe subscription instructs Dapr to invoke /redis-publisher on the NestJS service whenever the topic nest-redis-pub-topic is published.
10. Add sidecar for NestJS subscriber
nest-subscriber-dapr-sidecar:
image: "daprio/daprd:edge"
command: [
"./daprd",
"-app-id","nest-subscriber",
"-app-port","3000",
"-components-path","/components",
"-placement-host-address","dapr-placement:50006"
]
volumes:
- "./dapr/components/:/components"
depends_on:
- nest-subscriber
network_mode: "service:nest-subscriber"11. Test the flow
curl --location --request POST 'http://localhost:5001/v1.0/publish/redis-pubsub/nest-redis-pub-topic' \
--header 'Content-Type: application/json' \
--data-raw '{"hello":"world"}'Dapr forwards the request to the Redis sidecar, which publishes the message. Initially the NestJS subscriber receives an empty JSON object ( {}).
12. Enable NestJS to parse CloudEvents JSON
yarn add body-parser import * as bodyParser from 'body-parser';
...
app.use(bodyParser.json({ type: 'application/cloudevents+json' }));
app.use(bodyParser.json());After adding the parser, the subscriber correctly processes the CloudEvents payload and logs the received message.
13. Full docker‑compose.yaml
version: "3.5"
services:
dapr-placement:
image: "daprio/dapr"
command: ["./placement","-port","50006"]
redis-publisher:
image: redis
depends_on:
- dapr-placement
restart: always
ports:
- 5001:5000
redis-dapr-sidecar:
image: "daprio/daprd:edge"
command: [
"./daprd",
"-app-id","redis-publisher",
"-app-port","6379",
"-dapr-http-port","5000",
"-components-path","/components",
"-placement-host-address","dapr-placement:50006"
]
volumes:
- "./dapr/components/:/components"
depends_on:
- redis-publisher
network_mode: "service:redis-publisher"
nest-subscriber:
image: "nest-subscriber:latest"
depends_on:
- redis-publisher
- dapr-placement
restart: always
nest-subscriber-dapr-sidecar:
image: "daprio/daprd:edge"
command: [
"./daprd",
"-app-id","nest-subscriber",
"-app-port","3000",
"-components-path","/components",
"-placement-host-address","dapr-placement:50006"
]
volumes:
- "./dapr/components/:/components"
depends_on:
- nest-subscriber
network_mode: "service:nest-subscriber"Source code
https://github.com/Hacker-Linner/dapr-nestjs-redis-pub-sub.git
Signed-in readers can open the original source through BestHub's protected redirect.
This article has been distilled and summarized from source material, then republished for learning and reference. If you believe it infringes your rights, please contactand we will review it promptly.
How this landed with the community
Was this worth your time?
0 Comments
Thoughtful readers leave field notes, pushback, and hard-won operational detail here.
