Кэширование информации в Redis на NestJS

от автора

Предыдущая статья: Интеграция внешнего файлового сервера https://min.io в фулстек приложение на NestJS и Angular

На каждом фронтенд запросе к бэкенду запрашивается информация по профилю пользователя из базы данных, это создает дополнительную нагрузку на базу данных и увеличивает время ответа бэкенда, для ускорения подобных запросов можно кэшировать ответ базы данных.

В этом посте я подключу Redis к проекту и настрою кэширование данных через @nestjs-mod/cache-manager.

Проект можно запускать в Docker Compose и Kubernetes.

1. Устанавливаем дополнительные библиотеки

Устанавливаем JS-клиент и NestJS-модуль для работы с cache-manager и Redis.

Команды

npm install --save redis cache-manager-redis-yet cache-manager @nestjs-mod/cache-manager 
Вывод консоли
$ npm install --save redis cache-manager-redis-yet cache-manager @nestjs-mod/cache-manager npm warn deprecated cache-manager-redis-yet@5.1.5: With cache-manager v6 we now are using Keyv  added 17 packages, removed 2 packages, and audited 2934 packages in 19s  360 packages are looking for funding   run `npm fund` for details  41 vulnerabilities (19 low, 7 moderate, 15 high)  To address issues that do not require attention, run:   npm audit fix  To address all issues possible (including breaking changes), run:   npm audit fix --force  Some issues need review, and may require choosing a different dependency.  Run `npm audit` for details. 

2. Подключаем новые модули в бэкенд

Обновляем файл apps/server/src/main.ts

 import {   DOCKER_COMPOSE_FILE,   DockerCompose,   DockerComposeAuthorizer,   DockerComposeMinio,   DockerComposePostgreSQL, } from '@nestjs-mod/docker-compose'; // ... import { MinioModule } from '@nestjs-mod/minio'; // ...  import { ExecutionContext } from '@nestjs/common'; // ... bootstrapNestApplication({   modules: {    // ...      core: [       CacheManagerModule.forRoot({         staticConfiguration: {           type: isInfrastructureMode() ? 'memory' : 'redis',         },       }),     ],     infrastructure: [       DockerComposeMinio.forRoot({         staticConfiguration: { image: 'bitnami/minio:2024.11.7' },       }),     ]}     ); 

3. Запускаем генерацию дополнительного кода по инфраструктуре

Команды

npm run docs:infrastructure 

После запуска в docker-compose-файле появится новый сервис server-redis и в переменной окружения появится новая переменная окружения SERVER_REDIS_URL, которую нужно заполнить.

Обновленный файл apps/server/docker-compose-prod.yml

server-redis:   image: 'bitnami/redis:7.4.1'   container_name: 'server-redis'   volumes:     - 'server-redis-volume:/bitnami/redis/data'   ports:     - '6379:6379'   networks:     - 'server-network'   environment:     REDIS_DISABLE_COMMANDS: '${SERVER_REDIS_REDIS_DISABLE_COMMANDS}'     REDIS_IO_THREADS: '${SERVER_REDIS_REDIS_IO_THREADS}'     REDIS_IO_THREADS_DO_READS: '${SERVER_REDIS_REDIS_IO_THREADS_DO_READS}'   healthcheck:     test:       - 'CMD-SHELL'       - 'redis-cli ping | grep PONG'     interval: '5s'     timeout: '5s'     retries: 5   tty: true   restart: 'always' 

Обновляем файл .env

# ... SERVER_REDIS_URL=redis://:CHmeOQrZWUHwgahrfzsrzuREOxgAENsC@localhost:6379 

Повторно запускаем генерацию дополнительного кода по инфраструктуре, для генерации дополнительных переменных окружения.

Команды

npm run docs:infrastructure 

Обновленный файл apps/server/docker-compose-prod.yml

server-redis:   image: 'bitnami/redis:7.4.1'   container_name: 'server-redis'   volumes:     - 'server-redis-volume:/bitnami/redis/data'   ports:     - '6379:6379'   networks:     - 'server-network'   environment:     REDIS_DATABASE: '${SERVER_REDIS_REDIS_DATABASE}'     REDIS_PASSWORD: '${SERVER_REDIS_REDIS_PASSWORD}'     REDIS_DISABLE_COMMANDS: '${SERVER_REDIS_REDIS_DISABLE_COMMANDS}'     REDIS_IO_THREADS: '${SERVER_REDIS_REDIS_IO_THREADS}'     REDIS_IO_THREADS_DO_READS: '${SERVER_REDIS_REDIS_IO_THREADS_DO_READS}'   healthcheck:     test:       - 'CMD-SHELL'       - 'redis-cli --no-auth-warning -a $$REDIS_PASSWORD ping | grep PONG'     interval: '5s'     timeout: '5s'     retries: 5   tty: true   restart: 'always' 

4. Запускаем инфраструктуру с приложениями в режиме разработки и проверяем через E2E-тесты

Команды

npm run pm2-full:dev:start npm run pm2-full:dev:test:e2e 

5. Добавляем сервис для кэширования в WebhookModule-модуль

Создаем файл libs\feature\webhook\src\lib\services\webhook-cache.service.ts

import { CacheManagerService } from '@nestjs-mod/cache-manager'; import { InjectPrismaClient } from '@nestjs-mod/prisma'; import { Injectable } from '@nestjs/common'; import { PrismaClient, WebhookUser } from '@prisma/webhook-client'; import { WEBHOOK_FEATURE } from '../webhook.constants'; import { WebhookConfiguration } from '../webhook.configuration';  @Injectable() export class WebhookCacheService {   constructor(     @InjectPrismaClient(WEBHOOK_FEATURE)     private readonly prismaClient: PrismaClient,     private readonly webhookConfiguration: WebhookConfiguration,     private readonly cacheManagerService: CacheManagerService   ) {}    async clearCacheByExternalUserId(externalUserId: string) {     const webhookUsers = await this.prismaClient.webhookUser.findMany({       where: { externalUserId },     });     for (const webhookUser of webhookUsers) {       await this.cacheManagerService.del(this.getUserCacheKey(webhookUser));     }   }    async getCachedUserByExternalUserId(externalUserId: string, externalTenantId?: string) {     const cached = await this.cacheManagerService.get<WebhookUser | null>(       this.getUserCacheKey({         externalUserId,         externalTenantId,       })     );     if (cached) {       return cached;     }     const user = await this.prismaClient.webhookUser.findFirst({       where: {         externalUserId,         ...(externalTenantId ? { externalTenantId } : {}),       },     });     if (user) {       await this.cacheManagerService.set(this.getUserCacheKey({ externalTenantId, externalUserId }), user, this.webhookConfiguration.cacheTTL);       return user;     }     return null;   }    private getUserCacheKey({ externalTenantId, externalUserId }: { externalTenantId: string | undefined; externalUserId: string }): string {     return `${externalTenantId}_${externalUserId}`;   } } 

Данные по пользователю кэшируются на 15 секунд, время кэширования устанавливается через конфигурацию модуля.

Обновляем файл libs\feature\webhook\src\lib\webhook.configuration.ts

import { ConfigModel, ConfigModelProperty } from '@nestjs-mod/common'; import { WebhookEvent } from './types/webhook-event-object';  @ConfigModel() export class WebhookConfiguration {   @ConfigModelProperty({     description: 'List of available events.',   })   events!: WebhookEvent[];    @ConfigModelProperty({     description: 'TTL for cached data.',     default: 15_000,   })   cacheTTL?: number; }  // ... 

В WebhookGuard заменяем получение данных через орм на получение данных из сервиса кэирования.

Обновляем файл libs\feature\webhook\src\lib\webhook.guard.ts

//... import { WebhookCacheService } from './services/webhook-cache.service';  @Injectable() export class WebhookGuard implements CanActivate {   private logger = new Logger(WebhookGuard.name);    constructor(     //...     private readonly webhookCacheService: WebhookCacheService   ) {}    //...    private async tryGetOrCreateCurrentUserWithExternalUserId(req: WebhookRequest, externalTenantId: string | undefined, externalUserId: string) {     if (!req.webhookUser) {       if (!externalTenantId || !isUUID(externalTenantId)) {         throw new WebhookError(WebhookErrorEnum.EXTERNAL_TENANT_ID_NOT_SET);       }       if (this.webhookEnvironments.autoCreateUser) {         req.webhookUser = await this.webhookCacheService.getCachedUserByExternalUserId(externalUserId, externalTenantId);          if (!req.webhookUser) {           await this.prismaClient.webhookUser.create({             data: { externalTenantId, externalUserId, userRole: 'User' },           });         }       }       req.webhookUser = await this.webhookCacheService.getCachedUserByExternalUserId(externalUserId, externalTenantId);     }   }    private async tryGetCurrentSuperAdminUserWithExternalUserId(req: WebhookRequest, externalUserId: string) {     if (!req.webhookUser && this.webhookEnvironments.superAdminExternalUserId === externalUserId) {       req.webhookUser = await this.webhookCacheService.getCachedUserByExternalUserId(externalUserId);     }   }   //... } 

В контроллере с методами модификации пользователей добавляем вызов инвалидации кэша при изменении и удалении пользователя.

Обновляем файл libs\feature\webhook\src\lib\controllers\webhook-users.controller.ts

//... import { WebhookCacheService } from '../services/webhook-cache.service';  @ApiExtraModels(WebhookError) @ApiBadRequestResponse({   schema: { allOf: refs(WebhookError) }, }) @ApiTags('webhook') @CheckWebhookRole([WebhookRole.Admin]) @Controller('/webhook/users') export class WebhookUsersController {   constructor(     //...     private readonly webhookCacheService: WebhookCacheService   ) {}    //...    @Put(':id')   @ApiOkResponse({ type: WebhookUserObject })   async updateOne(@CurrentWebhookExternalTenantId() externalTenantId: string, @CurrentWebhookUser() webhookUser: WebhookUser, @Param('id', new ParseUUIDPipe()) id: string, @Body() args: UpdateWebhookUserArgs) {     const result = await this.prismaClient.webhookUser.update({       data: { ...args },       where: {         id,         ...this.webhookToolsService.externalTenantIdQuery(webhookUser, webhookUser.userRole === 'Admin' ? undefined : externalTenantId),       },     });     await this.webhookCacheService.clearCacheByExternalUserId(webhookUser.externalUserId);     return result;   }    @Delete(':id')   @ApiOkResponse({ type: StatusResponse })   async deleteOne(@CurrentWebhookExternalTenantId() externalTenantId: string, @CurrentWebhookUser() webhookUser: WebhookUser, @Param('id', new ParseUUIDPipe()) id: string) {     await this.prismaClient.webhookUser.delete({       where: {         id,         ...this.webhookToolsService.externalTenantIdQuery(webhookUser, webhookUser.userRole === 'Admin' ? undefined : externalTenantId),       },     });     await this.webhookCacheService.clearCacheByExternalUserId(id);     return { message: 'ok' };   }   //... } 

Подключаем сервис кэшировнаия в модуль WebhookModule.

Обновляем файл libs/feature/webhook/src/lib/webhook.module.ts

//... import { CacheManagerModule } from '@nestjs-mod/cache-manager'; import { WebhookCacheService } from './services/webhook-cache.service';  export const { WebhookModule } = createNestModule({   moduleName: WEBHOOK_MODULE,   moduleCategory: NestModuleCategory.feature,   staticEnvironmentsModel: WebhookEnvironments,   staticConfigurationModel: WebhookStaticConfiguration,   configurationModel: WebhookConfiguration,   imports: [     //...     CacheManagerModule.forFeature({       featureModuleName: WEBHOOK_FEATURE,     }),   ],   providers: [     //...     WebhookCacheService,   ],   //... }); 

6. Обновляем файлы и добавляем новые для запуска docker-compose и kubernetes

Полностью описывать изменения во всех файлах я не буду, их можно посмотреть по коммиту с изменениями для текущего поста, ниже просто добавлю обновленный docker-compose-full.yml и его файл с переменными окружения.

Обновляем файл .docker/docker-compose-full.yml

version: '3' networks:   nestjs-mod-fullstack-network:     driver: 'bridge' services:   nestjs-mod-fullstack-postgre-sql:     image: 'bitnami/postgresql:15.5.0'     container_name: 'nestjs-mod-fullstack-postgre-sql'     networks:       - 'nestjs-mod-fullstack-network'     healthcheck:       test:         - 'CMD-SHELL'         - 'pg_isready -U postgres'       interval: '5s'       timeout: '5s'       retries: 5     tty: true     restart: 'always'     environment:       POSTGRESQL_USERNAME: '${SERVER_POSTGRE_SQL_POSTGRESQL_USERNAME}'       POSTGRESQL_PASSWORD: '${SERVER_POSTGRE_SQL_POSTGRESQL_PASSWORD}'       POSTGRESQL_DATABASE: '${SERVER_POSTGRE_SQL_POSTGRESQL_DATABASE}'     volumes:       - 'nestjs-mod-fullstack-postgre-sql-volume:/bitnami/postgresql'   nestjs-mod-fullstack-authorizer:     image: 'lakhansamani/authorizer:1.4.4'     container_name: 'nestjs-mod-fullstack-authorizer'     ports:       - '8000:8080'     networks:       - 'nestjs-mod-fullstack-network'     environment:       DATABASE_URL: '${SERVER_AUTHORIZER_DATABASE_URL}'       DATABASE_TYPE: '${SERVER_AUTHORIZER_DATABASE_TYPE}'       DATABASE_NAME: '${SERVER_AUTHORIZER_DATABASE_NAME}'       ADMIN_SECRET: '${SERVER_AUTHORIZER_ADMIN_SECRET}'       PORT: '${SERVER_AUTHORIZER_PORT}'       AUTHORIZER_URL: '${SERVER_AUTHORIZER_URL}'       COOKIE_NAME: '${SERVER_AUTHORIZER_COOKIE_NAME}'       SMTP_HOST: '${SERVER_AUTHORIZER_SMTP_HOST}'       SMTP_PORT: '${SERVER_AUTHORIZER_SMTP_PORT}'       SMTP_USERNAME: '${SERVER_AUTHORIZER_SMTP_USERNAME}'       SMTP_PASSWORD: '${SERVER_AUTHORIZER_SMTP_PASSWORD}'       SENDER_EMAIL: '${SERVER_AUTHORIZER_SENDER_EMAIL}'       SENDER_NAME: '${SERVER_AUTHORIZER_SENDER_NAME}'       DISABLE_PLAYGROUND: '${SERVER_AUTHORIZER_DISABLE_PLAYGROUND}'       ACCESS_TOKEN_EXPIRY_TIME: '${SERVER_AUTHORIZER_ACCESS_TOKEN_EXPIRY_TIME}'       DISABLE_STRONG_PASSWORD: '${SERVER_AUTHORIZER_DISABLE_STRONG_PASSWORD}'       DISABLE_EMAIL_VERIFICATION: '${SERVER_AUTHORIZER_DISABLE_EMAIL_VERIFICATION}'       ORGANIZATION_NAME: '${SERVER_AUTHORIZER_ORGANIZATION_NAME}'       IS_SMS_SERVICE_ENABLED: '${SERVER_AUTHORIZER_IS_SMS_SERVICE_ENABLED}'       IS_EMAIL_SERVICE_ENABLED: '${SERVER_AUTHORIZER_IS_SMS_SERVICE_ENABLED}'       ENV: '${SERVER_AUTHORIZER_ENV}'       RESET_PASSWORD_URL: '${SERVER_AUTHORIZER_RESET_PASSWORD_URL}'       ROLES: '${SERVER_AUTHORIZER_ROLES}'       DEFAULT_ROLES: '${SERVER_AUTHORIZER_DEFAULT_ROLES}'       JWT_ROLE_CLAIM: '${SERVER_AUTHORIZER_JWT_ROLE_CLAIM}'       ORGANIZATION_LOGO: '${SERVER_AUTHORIZER_ORGANIZATION_LOGO}'     tty: true     restart: 'always'     depends_on:       nestjs-mod-fullstack-postgre-sql:         condition: service_healthy       nestjs-mod-fullstack-postgre-sql-migrations:         condition: service_completed_successfully   nestjs-mod-fullstack-minio:     image: 'bitnami/minio:2024.11.7'     container_name: 'nestjs-mod-fullstack-minio'     volumes:       - 'nestjs-mod-fullstack-minio-volume:/bitnami/minio/data'     ports:       - '9000:9000'       - '9001:9001'     networks:       - 'nestjs-mod-fullstack-network'     environment:       MINIO_ROOT_USER: '${SERVER_MINIO_MINIO_ROOT_USER}'       MINIO_ROOT_PASSWORD: '${SERVER_MINIO_MINIO_ROOT_PASSWORD}'     healthcheck:       test:         - 'CMD-SHELL'         - 'mc'         - 'ready'         - 'local'       interval: '5s'       timeout: '5s'       retries: 5     tty: true     restart: 'always'   nestjs-mod-fullstack-redis:     image: 'bitnami/redis:7.4.1'     container_name: 'nestjs-mod-fullstack-redis'     volumes:       - 'nestjs-mod-fullstack-redis-volume:/bitnami/redis/data'     ports:       - '6379:6379'     networks:       - 'nestjs-mod-fullstack-network'     environment:       REDIS_DATABASE: '${SERVER_REDIS_REDIS_DATABASE}'       REDIS_PASSWORD: '${SERVER_REDIS_REDIS_PASSWORD}'       REDIS_DISABLE_COMMANDS: '${SERVER_REDIS_REDIS_DISABLE_COMMANDS}'       REDIS_IO_THREADS: '${SERVER_REDIS_REDIS_IO_THREADS}'       REDIS_IO_THREADS_DO_READS: '${SERVER_REDIS_REDIS_IO_THREADS_DO_READS}'     healthcheck:       test:         - 'CMD-SHELL'         - 'redis-cli --no-auth-warning -a $$REDIS_PASSWORD ping | grep PONG'       interval: '5s'       timeout: '5s'       retries: 5     tty: true     restart: 'always'   nestjs-mod-fullstack-postgre-sql-migrations:     image: 'ghcr.io/nestjs-mod/nestjs-mod-fullstack-migrations:${ROOT_VERSION}'     container_name: 'nestjs-mod-fullstack-postgre-sql-migrations'     networks:       - 'nestjs-mod-fullstack-network'     tty: true     environment:       NX_SKIP_NX_CACHE: 'true'       SERVER_ROOT_DATABASE_URL: '${SERVER_ROOT_DATABASE_URL}'       SERVER_APP_DATABASE_URL: '${SERVER_APP_DATABASE_URL}'       SERVER_WEBHOOK_DATABASE_URL: '${SERVER_WEBHOOK_DATABASE_URL}'       SERVER_AUTHORIZER_DATABASE_URL: '${SERVER_AUTHORIZER_DATABASE_URL}'     depends_on:       nestjs-mod-fullstack-postgre-sql:         condition: 'service_healthy'     working_dir: '/usr/src/app'     volumes:       - './../apps:/usr/src/app/apps'       - './../libs:/usr/src/app/libs'   nestjs-mod-fullstack-server:     image: 'ghcr.io/nestjs-mod/nestjs-mod-fullstack-server:${SERVER_VERSION}'     container_name: 'nestjs-mod-fullstack-server'     networks:       - 'nestjs-mod-fullstack-network'     extra_hosts:       - 'host.docker.internal:host-gateway'     healthcheck:       test: ['CMD-SHELL', 'npx -y wait-on --timeout= --interval=1000 --window --verbose --log http://localhost:${SERVER_PORT}/api/health']       interval: 30s       timeout: 10s       retries: 10     tty: true     environment:       NODE_TLS_REJECT_UNAUTHORIZED: '0'       SERVER_PORT: '${SERVER_PORT}'       SERVER_APP_DATABASE_URL: '${SERVER_APP_DATABASE_URL}'       SERVER_WEBHOOK_DATABASE_URL: '${SERVER_WEBHOOK_DATABASE_URL}'       SERVER_WEBHOOK_SUPER_ADMIN_EXTERNAL_USER_ID: '${SERVER_WEBHOOK_SUPER_ADMIN_EXTERNAL_USER_ID}'       SERVER_AUTH_ADMIN_EMAIL: '${SERVER_AUTH_ADMIN_EMAIL}'       SERVER_AUTH_ADMIN_USERNAME: '${SERVER_AUTH_ADMIN_USERNAME}'       SERVER_AUTH_ADMIN_PASSWORD: '${SERVER_AUTH_ADMIN_PASSWORD}'       SERVER_AUTHORIZER_URL: '${SERVER_AUTHORIZER_URL}'       SERVER_AUTHORIZER_REDIRECT_URL: '${SERVER_AUTHORIZER_REDIRECT_URL}'       SERVER_AUTHORIZER_AUTHORIZER_URL: '${SERVER_AUTHORIZER_AUTHORIZER_URL}'       SERVER_AUTHORIZER_ADMIN_SECRET: '${SERVER_AUTHORIZER_ADMIN_SECRET}'       SERVER_MINIO_SERVER_HOST: '${SERVER_MINIO_SERVER_HOST}'       SERVER_MINIO_ACCESS_KEY: '${SERVER_MINIO_ACCESS_KEY}'       SERVER_MINIO_SECRET_KEY: '${SERVER_MINIO_SECRET_KEY}'       SERVER_REDIS_URL: '${SERVER_REDIS_URL}'     restart: 'always'     depends_on:       nestjs-mod-fullstack-authorizer:         condition: 'service_started'       nestjs-mod-fullstack-minio:         condition: 'service_started'       nestjs-mod-fullstack-redis:         condition: 'service_healthy'       nestjs-mod-fullstack-postgre-sql:         condition: service_healthy       nestjs-mod-fullstack-postgre-sql-migrations:         condition: service_completed_successfully   nestjs-mod-fullstack-nginx:     image: 'ghcr.io/nestjs-mod/nestjs-mod-fullstack-nginx:${CLIENT_VERSION}'     container_name: 'nestjs-mod-fullstack-nginx'     networks:       - 'nestjs-mod-fullstack-network'     healthcheck:       test: ['CMD-SHELL', 'curl -so /dev/null http://localhost:${NGINX_PORT} || exit 1']       interval: 30s       timeout: 10s       retries: 10     environment:       SERVER_PORT: '${SERVER_PORT}'       NGINX_PORT: '${NGINX_PORT}'       CLIENT_AUTHORIZER_URL: '${CLIENT_AUTHORIZER_URL}'       CLIENT_MINIO_URL: '${CLIENT_MINIO_URL}'       CLIENT_WEBHOOK_SUPER_ADMIN_EXTERNAL_USER_ID: '${CLIENT_WEBHOOK_SUPER_ADMIN_EXTERNAL_USER_ID}'     restart: 'always'     depends_on:       nestjs-mod-fullstack-server:         condition: service_healthy     ports:       - '${NGINX_PORT}:${NGINX_PORT}'   nestjs-mod-fullstack-e2e-tests:     image: 'ghcr.io/nestjs-mod/nestjs-mod-fullstack-e2e-tests:${ROOT_VERSION}'     container_name: 'nestjs-mod-fullstack-e2e-tests'     networks:       - 'nestjs-mod-fullstack-network'     environment:       IS_DOCKER_COMPOSE: 'true'       BASE_URL: 'http://nestjs-mod-fullstack-nginx:${NGINX_PORT}'       SERVER_AUTHORIZER_URL: 'http://nestjs-mod-fullstack-authorizer:8080'       SERVER_MINIO_URL: 'http://nestjs-mod-fullstack-minio:9000'       SERVER_URL: 'http://nestjs-mod-fullstack-server:8080'       SERVER_AUTH_ADMIN_EMAIL: '${SERVER_AUTH_ADMIN_EMAIL}'       SERVER_AUTH_ADMIN_USERNAME: '${SERVER_AUTH_ADMIN_USERNAME}'       SERVER_AUTH_ADMIN_PASSWORD: '${SERVER_AUTH_ADMIN_PASSWORD}'       SERVER_AUTHORIZER_ADMIN_SECRET: '${SERVER_AUTHORIZER_ADMIN_SECRET}'     depends_on:       nestjs-mod-fullstack-nginx:         condition: service_healthy     working_dir: '/usr/src/app'     volumes:       - './../apps:/usr/src/app/apps'       - './../libs:/usr/src/app/libs'   nestjs-mod-fullstack-https-portal:     image: steveltn/https-portal:1     container_name: 'nestjs-mod-fullstack-https-portal'     networks:       - 'nestjs-mod-fullstack-network'     ports:       - '80:80'       - '443:443'     links:       - nestjs-mod-fullstack-nginx     restart: always     environment:       STAGE: '${HTTPS_PORTAL_STAGE}'       DOMAINS: '${SERVER_DOMAIN} -> http://nestjs-mod-fullstack-nginx:${NGINX_PORT}'     depends_on:       nestjs-mod-fullstack-nginx:         condition: service_healthy     volumes:       - nestjs-mod-fullstack-https-portal-volume:/var/lib/https-portal volumes:   nestjs-mod-fullstack-postgre-sql-volume:     name: 'nestjs-mod-fullstack-postgre-sql-volume'   nestjs-mod-fullstack-https-portal-volume:     name: 'nestjs-mod-fullstack-https-portal-volume'   nestjs-mod-fullstack-minio-volume:     name: 'nestjs-mod-fullstack-minio-volume'   nestjs-mod-fullstack-redis-volume:     name: 'nestjs-mod-fullstack-redis-volume' 

Обновляем файл .docker/docker-compose-full.env

SERVER_PORT=9090 NGINX_PORT=8080 SERVER_ROOT_DATABASE_URL=postgres://postgres:postgres_password@nestjs-mod-fullstack-postgre-sql:5432/postgres?schema=public SERVER_APP_DATABASE_URL=postgres://app:app_password@nestjs-mod-fullstack-postgre-sql:5432/app?schema=public SERVER_WEBHOOK_DATABASE_URL=postgres://webhook:webhook_password@nestjs-mod-fullstack-postgre-sql:5432/webhook?schema=public SERVER_POSTGRE_SQL_POSTGRESQL_USERNAME=postgres SERVER_POSTGRE_SQL_POSTGRESQL_PASSWORD=postgres_password SERVER_POSTGRE_SQL_POSTGRESQL_DATABASE=postgres SERVER_DOMAIN=example.com HTTPS_PORTAL_STAGE=local # local|stage|production  CLIENT_AUTHORIZER_URL=http://localhost:8000 CLIENT_MINIO_URL=http://localhost:9000 SERVER_AUTHORIZER_REDIRECT_URL=http://localhost:8080 SERVER_AUTH_ADMIN_EMAIL=nestjs-mod-fullstack@site15.ru SERVER_AUTH_ADMIN_USERNAME=admin SERVER_AUTH_ADMIN_PASSWORD=SbxcbII7RUvCOe9TDXnKhfRrLJW5cGDA SERVER_URL=http://localhost:9090/api SERVER_AUTHORIZER_URL=http://localhost:8000 SERVER_MINIO_URL=http://localhost:9000 SERVER_AUTHORIZER_ADMIN_SECRET=VfKSfPPljhHBXCEohnitursmgDxfAyiD SERVER_AUTHORIZER_DATABASE_TYPE=postgres SERVER_AUTHORIZER_DATABASE_URL=postgres://Yk42KA4sOb:B7Ep2MwlRR6fAx0frXGWVTGP850qAxM6@nestjs-mod-fullstack-postgre-sql:5432/authorizer SERVER_AUTHORIZER_DATABASE_NAME=authorizer SERVER_AUTHORIZER_PORT=8080 SERVER_AUTHORIZER_AUTHORIZER_URL=http://nestjs-mod-fullstack-authorizer:8080 SERVER_AUTHORIZER_COOKIE_NAME=authorizer SERVER_AUTHORIZER_DISABLE_PLAYGROUND=true SERVER_AUTHORIZER_ACCESS_TOKEN_EXPIRY_TIME=30m SERVER_AUTHORIZER_DISABLE_STRONG_PASSWORD=true SERVER_AUTHORIZER_DISABLE_EMAIL_VERIFICATION=true SERVER_AUTHORIZER_ORGANIZATION_NAME=NestJSModFullstack SERVER_AUTHORIZER_IS_EMAIL_SERVICE_ENABLED=true SERVER_AUTHORIZER_IS_SMS_SERVICE_ENABLED=false SERVER_AUTHORIZER_RESET_PASSWORD_URL=/reset-password SERVER_AUTHORIZER_ROLES=user,admin SERVER_AUTHORIZER_DEFAULT_ROLES=user SERVER_AUTHORIZER_JWT_ROLE_CLAIM=role  SERVER_MINIO_SERVER_HOST=nestjs-mod-fullstack-minio SERVER_MINIO_ACCESS_KEY=FWGmrAGaeMKM SERVER_MINIO_SECRET_KEY=QatVJuLoZRARlJguoZMpoKvZMJHzvuOR SERVER_MINIO_ROOT_USER=FWGmrAGaeMKM SERVER_MINIO_ROOT_PASSWORD=QatVJuLoZRARlJguoZMpoKvZMJHzvuOR SERVER_MINIO_MINIO_ROOT_USER=FWGmrAGaeMKM SERVER_MINIO_MINIO_ROOT_PASSWORD=QatVJuLoZRARlJguoZMpoKvZMJHzvuOR  SERVER_REDIS_REDIS_DATABASE=0 SERVER_REDIS_REDIS_PASSWORD=CHmeOQrZWUHwgahrfzsrzuREOxgAENsC SERVER_REDIS_REDIS_DISABLE_COMMANDS= SERVER_REDIS_REDIS_IO_THREADS= SERVER_REDIS_REDIS_IO_THREADS_DO_READS=  SERVER_REDIS_URL=redis://:CHmeOQrZWUHwgahrfzsrzuREOxgAENsC@nestjs-mod-fullstack-redis:6379 

Заключение

В данном посте показан простой способ кэширования и инвалидации кэша, если сущностей и данных для кэширования больше, то нужно продумывать иной способ кэширования и инвалидации, для того чтобы писать меньше кода.

Планы

В следующем посте я добавлю получение серверного времени через WebSockets и отображение его в Angular-приложении…

Ссылки


ссылка на оригинал статьи https://habr.com/ru/articles/861064/


Комментарии

Добавить комментарий

Ваш адрес email не будет опубликован. Обязательные поля помечены *