When Redis is down

Handle connection failures — wait for Redis or fall back to in-memory (with caveats).

When Redis is down

At startup ready() waits for a connection (by default until Redis connects). You can wait until Redis is back (recommended for multiple instances) or fall back to in-memory (risky with multiple instances).

Option 1: Wait until Redis is back (recommended for multiple instances)

With multiple instances, each process has its own memory. If you fall back to an in-memory limiter per instance, the combined limit is effectively N × your per-instance limit, so you can exceed the intended global threshold. To keep a single shared limit, wait for Redis instead of falling back.

Simple: just call ready()

By default the limiter waits until Redis connects. You don’t need a retry loop — just call await limiter.ready() and it will resolve when Redis is up.

import { DistributedRateLimiter } from 'rate-queue';

const limiter = new DistributedRateLimiter({
  id: 'api-limiter',
  maxConcurrent: 10,
  redis: { url: process.env.REDIS_URL || 'redis://localhost:6379' },
});
await limiter.ready();
const result = await limiter.schedule(() => fetch('/api/data'));

Custom retry loop (e.g. to log each attempt):

import { DistributedRateLimiter } from 'rate-queue';

async function createLimiter() {
  const maxAttempts = 60;
  const waitMs = 2000;

  for (let attempt = 1; attempt <= maxAttempts; attempt++) {
    try {
      const limiter = new DistributedRateLimiter({
        id: 'api-limiter',
        redis: { url: process.env.REDIS_URL || 'redis://localhost:6379' },
      });
      await limiter.ready();
      return limiter;
    } catch (err) {
      if (attempt === maxAttempts) throw err;
      console.warn(`Redis not ready (attempt ${attempt}/${maxAttempts}), retrying in ${waitMs}ms...`);
      await new Promise((r) => setTimeout(r, waitMs));
    }
  }
}

const limiter = await createLimiter();
const result = await limiter.schedule(() => fetch('/api/data'));

After Redis was lost — wait for reconnection, then retry:
ioredis auto-reconnects. If you need to block until Redis is back (e.g. before retrying a failed operation), use the underlying storage:

// Wait up to 30s for Redis to come back (e.g. after an 'error' from the limiter)
await limiter.getStorage().waitForConnection(30_000);
// Then retry your schedule(...) or other logic

If the connection is already up, waitForConnection() resolves immediately. If the client is in a terminal state (end / close), it rejects; otherwise it waits for the next ready or times out.

Option 2: Fall back to in-memory (single instance or accept risk)

Only use this if you run a single instance or explicitly accept that under Redis outage the combined rate can exceed your intended limit.

At startup:

import { RateLimiter, DistributedRateLimiter } from 'rate-queue';

let limiter;

try {
  limiter = new DistributedRateLimiter({
    id: 'api-limiter',
    redis: { url: process.env.REDIS_URL || 'redis://localhost:6379' },
  });
  await limiter.ready();
} catch (err) {
  console.warn('Redis unavailable, using local limiter', err);
  limiter = new RateLimiter({ maxConcurrent: 5, minTime: 100 });
}

const result = await limiter.schedule(() => fetch('/api/data'));

What happens when the connection fails: If you use a timeout (see API reference readyTimeout), ready() will reject after that time and your catch runs. Otherwise ready() waits until Redis connects. The err you get is one of:

CauseExample err.message
Timeout (no connection within configured time)Redis connection timeout
Redis not running / connection refusedconnect ECONNREFUSED 127.0.0.1:6379 (ioredis error)
Client already closedRedis connection already closed (status: end)

So in the snippet above: if connection fails, you see a warning with one of these errors and the app continues with the local limiter.

After connection: If Redis goes away later, Redis commands will reject and the limiter emits error. In-flight jobs may reject; queued jobs wait. ioredis auto-reconnects, so short outages can recover without extra code.

Next: API overview.