РЕПЕТИТОР математика физика информатика
Для школьников и студентов. Подтягивание пробелов. ЦЭ, ЦТ, ОГЭ, ЕГЭ.
Идет набор на ЛЕТО. Жмите для подробностей:)
⊗jsnsSpThSt 132 of 201 menu
◀ ▶

Хранилище счётчика в Nest

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

Модуль принимает класс с интерфейсом ThrottlerStorage из пакета @nestjs/throttler и передаёт его в поле storage при ThrottlerModule.forRoot. В документации Nest для Redis указаны сторонние адаптеры, а здесь покажем своё хранилище в памяти с тем же контрактом, чтобы счётчик можно было заменить на общий позже.

Покажем на примере постов:

import { ThrottlerStorage, ThrottlerStorageRecord, } from '@nestjs/throttler'; type CounterRow = { hits: number; resetAt: number; blockedUntil: number; }; export class PostCounterStorage implements ThrottlerStorage { private map = new Map<string, CounterRow>(); async increment( key: string, ttl: number, limit: number, blockDuration: number, throttlerName: string, ): Promise<ThrottlerStorageRecord> { const storageKey = key + ':' + throttlerName; const now = Date.now(); let row = this.map.get(storageKey); if (!row || row.resetAt <= now) { row = { hits: 0, resetAt: now + ttl, blockedUntil: 0, }; this.map.set(storageKey, row); } if (row.blockedUntil > now) { return { totalHits: row.hits, timeToExpire: Math.ceil((row.resetAt - now) / 1000), isBlocked: true, timeToBlockExpire: Math.ceil( (row.blockedUntil - now) / 1000, ), }; } row.hits += 1; const isBlocked = row.hits > limit; if (isBlocked && blockDuration > 0) { row.blockedUntil = now + blockDuration; } const timeToExpire = Math.ceil((row.resetAt - now) / 1000); const timeToBlockExpire = row.blockedUntil > now ? Math.ceil((row.blockedUntil - now) / 1000) : 0; return { totalHits: row.hits, timeToExpire, isBlocked, timeToBlockExpire, }; } }

Передадим хранилище в настройку модуля:

import { Module } from '@nestjs/common'; import { APP_GUARD } from '@nestjs/core'; import { ThrottlerGuard, ThrottlerModule } from '@nestjs/throttler'; import { PostController } from './post.controller.js'; import { PostCounterStorage } from './post-counter.storage.js'; @Module({ imports: [ ThrottlerModule.forRoot({ throttlers: [ { ttl: 60000, limit: 10, }, ], storage: new PostCounterStorage(), }), ], controllers: [PostController], providers: [ { provide: APP_GUARD, useClass: ThrottlerGuard, }, ], }) export class AppModule {}

Реализуйте своё хранилище счётчика в памяти для API работников и подключите его в корневом модуле с WorkerController вместо встроенного по умолчанию.

← →
↑
Мы используем cookie для работы сайта, аналитики и персонализации. Обработка данных происходит согласно Политике конфиденциальности.
принять все настроить отклонить