Example: Redis
Learning objectives
- You know how to use publish subscribe with Redis.
Here, we'll briefly look into creating a simple project that utilizes Redis for realizing the publish-subscribe pattern. The structure of the project will be as follows.
tree --dirsfirst
.
├── consumer
│ ├── app.js
│ └── Dockerfile
├── nginx
│ └── nginx.conf
├── producer
│ ├── app.js
│ └── Dockerfile
├── redis
│ └── redis.conf
└── docker-compose.yml
Docker compose file
For the purposes of the project, we create a docker-compose.yml
file that defines four services: NGINX, Redis, producer, and consumer. The producer and consumer services are Deno applications, while Nginx and Redis are otherwise already familiar to us.
The docker-compose.yml
file is as follows:
version: "3.4"
services:
nginx:
image: nginx:latest
volumes:
- ./nginx/nginx.conf:/etc/nginx/nginx.conf:ro
depends_on:
- producer
ports:
- 7800:7800
redis:
image: redis:latest
command: redis-server /usr/local/etc/redis/redis.conf
volumes:
- ./redis/redis.conf:/usr/local/etc/redis/redis.conf
expose:
- 6379
producer:
build: producer
image: producer
restart: "no"
volumes:
- ./producer/:/app
- ./app-cache/:/app-cache
expose:
- 7777
consumer:
build: consumer
image: consumer
restart: "no"
volumes:
- ./consumer/:/app
- ./app-cache/:/app-cache
Redix and NGINX
The redis.conf
file in the redis
folder is the same that we have used in the past, i.e.
maxmemory 5mb
maxmemory-policy allkeys-lru
save ""
appendonly no
Similarly, the nginx.conf
in the nginx
folder is very similar to what we have previously seen.
worker_processes 1;
events {
worker_connections 1024;
}
http {
upstream producer {
server producer:7777;
}
server {
listen 7800;
location / {
proxy_pass http://producer;
}
}
}
Producer and consumer
The producer and consumer have their own responsibilities. The producer creates content that it pushes to Redis, while the consumer receives content from Redis. Both of them use Deno and their Dockerfile
s are as follows. For simplicity, caching of dependencies has also been omitted.
FROM denoland/deno:alpine-1.42.2
EXPOSE 7777
WORKDIR /app
COPY . .
CMD [ "run", "--unstable", "--watch", "--allow-net", "app.js" ]
For fun, let's use the node-redis library through Deno's support for NodeJS libraries. To use the node-redis
library, we import the library with the npm:
-prefix and create a client as follows.
import { createClient } from "npm:redis@4.6.4";
const client = createClient({
url: "redis://redis:6379",
pingInterval: 1000,
});
Consumer
Consuming messages from redis is straightforward. To consume messages, we connect to Redis using the client, and subscribe to messages that are sent to specific channel(s). In the following example, which outlines the full contents of app.js
in the folder consumer
, we subscribe to a channel called "secret-channel".
import { createClient } from "npm:redis@4.6.4";
const client = createClient({
url: "redis://redis:6379",
pingInterval: 1000,
});
await client.connect();
await client.subscribe(
"secret-channel",
(message, channel) => console.log(message, channel),
);
Producer
Producing content to Redis is done with the method publish
of the Redis client. To be able to easily publish content, we'll add a web server for the producer, allowing producing content whenever a request is made to the path /publish
. The full app.js
in the folder producer
looks as follows.
import { createClient } from "npm:redis@4.6.4";
import { serve } from "https://deno.land/std@0.222.1/http/server.ts";
const client = createClient({
url: "redis://redis:6379",
pingInterval: 1000,
})
await client.connect();
const handleRequest = async (request) => {
const url = new URL(request.url);
if (url.pathname == "/publish") {
client.publish("secret-channel", "hello!");
return new Response("Data published!");
}
return new Response("Hello!");
};
serve(handleRequest, { port: 7777 });
Running the application
When we launch the application using docker compose up
, we can access the application at the port localhost:7800
. Making a request to the path /publish
leads to a message being shown in the console logs of the application.
docker compose up
// ..
// ..
demo-consumer-1 | hello! secret-channel
// ..