Использование Redis Streams с NestJS: Часть 1 — Настройка
22 февраля 2023 г.Это первая часть серии из трех частей, в которой мы рассмотрим, как использовать потоки Redis с NestJS.
Он состоит из 3 частей:
- Настройка приложения NestJS и подключение к Redis
- Заполнение потоков Redis и чтение из них в режиме разветвления
- Использование групп потребителей для обработки одного потока от нескольких участников таким образом, что одно сообщение отправляется и обрабатывается только одним участником (потребителем)
К концу этой серии вы будете обладать знаниями и инструментами, необходимыми для создания собственного приложения NestJS, использующего потоки Redis для обработки данных в реальном времени.
Полный код доступен на github
.Предполагаемые предварительные знания
Прежде чем углубляться в этот пост, предполагается, что вы имеете общее представление о NestJS и Redis. Также рекомендуется ознакомиться с генераторами JavaScript, так как они будут использоваться в примерах для непрерывного прослушивания потока Redis.
Мы также будем использовать Docker и Docker Compose для создания и запуска нашего сервера и приложения Redis.
NestJS — это фреймворк машинописного текста, поэтому вы тоже должны с ним ознакомиться.
Чтобы ознакомиться с этими вещами, я рекомендую:
- документы NestJS
- TypeScript
- Редис:
- Введение в потоки Redis
- Учебник
- Генераторы:
- Справочник по генераторам JavaScript
- Др. Разделы книги Акселя Раушмайера «JavaScript для нетерпеливых программистов», посвященные синхронному и асинхронные генераторы (доступны бесплатно в Интернете)
- Докер:
- Докер
- Docker Compose
:::подсказка Также важно отметить, что, хотя в этом посте явно рассматривается интеграция потоков Redis с NestJS, обсуждаемые здесь концепции и методы также могут применяться к другим платформам и языкам. Потоки Redis — это универсальный инструмент, который можно использовать в самых разных приложениях и архитектурах. Поэтому, даже если вы не используете NestJS, общие концепции и подходы, изложенные в этом посте, могут применяться к вашим проектам и стеку.
:::
Настройка
Создание нового приложения NestJS
Для начала нам нужно создать новое приложение NestJS. Это можно сделать с помощью интерфейса командной строки NestJS, который можно установить через npm, запустив npm i -g @nestjs/cli
. После установки вы можете создать новое приложение, запустив nest new redis-streams
, где «redis-streams» — это имя вашего приложения.
При этом будет создан новый каталог с тем же именем, содержащий базовую структуру приложения NestJS.
Настройка Docker
Для упрощения мы собираемся использовать файл docker-compose.yml
, чтобы включить как наше приложение, так и сервер Redis:
# docker-compose.yml
version: '3'
services:
app:
container_name: app
image: node:18
environment:
HTTPS_METHOD: noredirect
ports:
- 8081:3000
volumes:
- ./:/usr/src/app/
working_dir: /usr/src/app
command: npm run start:dev
redis:
container_name: redis
image: redis:7
restart: always
Теперь вы можете запустить docker-compose up -d
для сборки и запуска ваших сервисов. Чтобы просмотреть вывод консоли, используйте журналы создания докеров
Вы должны увидеть следующее сообщение:
LOG [NestApplication] Nest application successfully started +7ms
Подключение к Redis
Настройка клиентской библиотеки node-redis
Для вызова Redis мы будем использовать официальную клиентскую библиотеку NodeJS Redis node-redis
$ npm i redis
Есть и другие библиотеки, например. ioredis
— достойная внимания альтернатива. Вы можете увидеть список клиентов на веб-сайте Redis
Модуль Redis
Наконец-то мы можем начать работать с Redis из нашего приложения.
Сначала будет создан новый модуль для сервисов, связанных с Redis.
$ nest g module redis
Вы должны увидеть это:
// redis.module.ts
import { Module } from '@nestjs/common';
@Module({
providers: [],
exports: [],
})
export class RedisModule {}
Фабрика RedisClient
Чтобы использовать RedisClient
из библиотеки node-redis
, мы создадим для него фабричный провайдер:
// redis-client.factory.ts
import { FactoryProvider } from '@nestjs/common';
import { createClient } from 'redis';
import { RedisClient, REDIS_CLIENT } from './redis-client.type';
export const redisClientFactory: FactoryProvider<Promise<RedisClient>> = {
provide: REDIS_CLIENT,
useFactory: async () => {
const client = createClient({ url: 'redis://redis:6379/0' });
await client.connect();
return client;
},
};
Давайте сломаем это.
Мы создаем FactoryProvider
, который будет вызывать асинхронную функцию, предоставленную в useFactory
:
// redis-client.factory.ts
// --snip--
useFactory: async () => {
const client = createClient({ url: 'redis://redis:6379/0' });
await client.connect();
return client;
},
// --snip--
-
Мы вызываем функцию
createClient
из библиотекиredis
и передаем ей URL, состоящий из{protocol}://{host}:{port}/{ база данных
, где: -
протокол=
redis
- host =
redis
— это указано вdocker-compose.yml
с помощьюcontainer_host: redis
. Обычно вы создаете переменную среды с вашим IP-адресом экземпляра Redis и используете ее здесь. - port =
6379
— порт Redis по умолчанию -
база данных =
0
база данных по умолчанию -
Подключаемся к серверу Redis
await client.connect();
- Вернуть созданный & подключенный клиент.
Возможно, вы заметили, что мы предоставили не экземпляр типа RedisClient
, а REDIS_CLIENT
, который является нашим токеном внедрения. Кроме того, RedisClient
— это наш собственный тип, а не redis
.
Это связано с тем, что node-redis
в v4 не экспортирует тип RedisClient
, поэтому нам нужно создать свой собственный в /redis-client.type.ts код> файл:
export type RedisClient = ReturnType<typeof createClient>;
export const REDIS_CLIENT = Symbol('REDIS_CLIENT');
Осталось только добавить это в наш модуль:
// redis.module.ts
// --snip--
@Module({
providers: [redisClientFactory],
})
export class RedisModule {}
Создание RedisService
Затем добавим RedisService
, который создаст уровень абстракции от RedisClient
.
$ nest g service redis
Туда мы вставим наш RedisClient
// redis.service.ts
// --snip--
@Injectable()
export class RedisService implements OnModuleDestroy {
public constructor(
@Inject(REDIS_CLIENT) private readonly redis: RedisClient,
) {}
onModuleDestroy() {
this.redis.quit();
}
}
Чтобы не оставлять зависшие соединения, мы собираемся закрыть соединение с Redis, вызвав this.redis.quit()
в событии жизненного цикла OnModuleDestroy
.
Ping для сервера Redis
Чтобы убедиться, что мы успешно подключились к Redis, добавим конечную точку API, которая вызывает call Redis ping
// redis.service.ts
ping() {
return this.redis.ping();
}
Давайте экспортируем RedisService, чтобы мы могли использовать его в других модулях:
// redis.module.ts
// --snip--
exports: [RedisService],
// --snip--
Теперь мы импортируем его в AppService
и пропустим через наш вызов ping redis:
// app.service.ts
@Injectable()
export class AppService {
// --snip--
constructor(
private readonly redisService: RedisService,
) {}
redisPing() {
return this.redisService.ping();
}
// --snip--
Наконец, мы можем добавить новую конечную точку в AppController, которая будет выполнять эхо-запрос на сервер Redis и отправлять ответ пользователю:
// app.controller.ts
// --snip--
@Controller()
export class AppController {
constructor(private readonly appService: AppService) {}
@Get('redis-ping')
redisPing() {
return this.appService.redisPing();
}
}
Теперь, когда наше приложение и сервер Redis запущены, мы можем открыть нашу конечную точку /redis-ping
http://localhost: 8081/redis-ping, и вы должны увидеть ответ:
Поздравляем! Мы завершили первую часть серии из трех частей и создали приложение NestJS с рабочим подключением к нашему серверу Redis! Во второй части мы собираемся создавать, заполнять и читать потоки Redis.
Оригинал