express-rate-limit / cluster-memory-store

express-rate-limit Store that shares state between all the workers in a node.js cluster
MIT License
5 stars 2 forks source link

TypeError: An invalid store was passed #1

Closed modeht closed 1 year ago

modeht commented 1 year ago

Description

Full error: TypeError: An invalid store was passed. Please ensure that the store is a class that implements the Store interface.

I am using pm2 cluster mode Here is my middleware

import rateLimit from 'express-rate-limit';
import cluster from 'cluster';
import {
  ClusterMemoryStorePrimary,
  ClusterMemoryStoreWorker,
} from '@express-rate-limit/cluster-memory-store';

let store;
if (cluster.isPrimary) {
  store = new ClusterMemoryStorePrimary();
  store.init();
} else {
  store = new ClusterMemoryStoreWorker();
}

export const rateLimiter = rateLimit({
  windowMs: 1 * 60 * 1000,
  limit: async (req, res) => {
    if (req.admin) return 500;
    return 0;
  },
  store: store,
});

Library version

0.1.1

Node version

v18.13.0

Typescript version (if you are using it)

5.2.2

Module system

ESM

modeht commented 1 year ago

I fixed it. my error was i didn't need to pass the store if it is the primary process here is the fix

import rateLimit from 'express-rate-limit';
import cluster from 'cluster';
import {
  ClusterMemoryStorePrimary,
  ClusterMemoryStoreWorker,
} from '@express-rate-limit/cluster-memory-store';

let store;
let worker = !cluster.isPrimary;
if (!worker) {
  store = new ClusterMemoryStorePrimary();
  store.init();
} else {
  store = new ClusterMemoryStoreWorker();
}

export const rateLimiter = rateLimit({
  windowMs: 1 * 60 * 1000,
  limit: async (req, res) => {
    if (req.admin) return 500;
    return 0;
  },
  ...(worker ? {store: store} : null),
});
nfriedly commented 1 year ago

Yeah, that works, or what I would do is to not create the rateLimiter (or even the app) in the primary process - see https://github.com/express-rate-limit/cluster-memory-store/blob/main/example/server.js

It's also possible to have the worker be a separate file entirely; I might add an example to show that sometime.