Skip to content

Redis

Overview

@modularityjs/redis provides a shared ioredis client used by all Redis-backed drivers (cache-redis, lock-redis, queue-redis). It manages the connection lifecycle — connecting during boot and disconnecting on shutdown.

It is kind shared, not a contract: RedisService is concrete, and getClient() returns ioredis's own Redis type. Consumers use the full client surface — pipelines, Lua eval, streams, pub/sub — so no abstract could describe it that a different client library could satisfy. There is one implementation by construction, and nothing to swap. Wire RedisModule once; every *-redis driver injects RedisService from it rather than opening its own connection.

Setup

typescript
import { RedisModule } from '@modularityjs/redis';

const modules = [
  RedisModule.forRoot({
    url: process.env.REDIS_URL, // e.g. redis://localhost:6379
  }),
  // ... Redis drivers
];

The url is required — there is no localhost fallback. Boot fails with a ValidationException (MJS0015) until an explicit redis:// or rediss:// URL is passed.

Configuration

OptionDefaultDescription
urlrequiredConnection URL (redis://… / rediss://…); carries host, port, credentials, and db
keyPrefix'modularityjs:'Prefix for all keys (used by drivers, not ioredis)
lazyConnecttrueDefer connection until onInit
commandTimeoutMs5000Per-command timeout (ioredis commandTimeout, 0 disables)
maxRetriesPerRequest-ioredis per-request retry cap

Key Prefixing

All Redis drivers build keys using the pattern:

{RedisConfig.keyPrefix}{driver namespace}{key}

For example, with default config:

  • Cache key user:1 becomes modularityjs:cache:user:1
  • Lock key payment:123 becomes modularityjs:lock:payment:123
  • Queue stream orders becomes modularityjs:queue:stream:orders

The prefix is not passed to ioredis's keyPrefix option (which breaks Lua scripts). Instead, each driver builds the full key manually for consistency across all Redis commands including eval.

Lifecycle

  • onInit — connects to Redis. If the connection fails, boot fails immediately.
  • onShutdown — gracefully disconnects via QUIT.

Direct Access

Inject RedisService for custom Redis operations beyond what the framework drivers provide:

typescript
import { Inject, Injectable } from '@modularityjs/di';
import { RedisService } from '@modularityjs/redis';

@Injectable()
class LeaderboardService {
  constructor(@Inject(RedisService) private readonly redis: RedisService) {}

  async addScore(userId: string, score: number): Promise<void> {
    const client = this.redis.getClient();
    await client.zadd('leaderboard', score, userId);
  }

  async getTopPlayers(count: number): Promise<string[]> {
    const client = this.redis.getClient();
    return client.zrevrange('leaderboard', 0, count - 1);
  }
}

getClient() returns the raw ioredis Redis instance. The global keyPrefix from RedisConfig is not applied automatically to direct client calls -- build keys manually when needed.

Environment Configuration

RedisModule does not register a ConfigSchemaPool entry and does not read from ConfigService. To configure Redis from environment variables, the consumer must read process.env (or query ConfigService against its own schema) and pass the value to RedisModule.forRoot({...}):

typescript
RedisModule.forRoot({
  url: process.env.REDIS_URL, // redis://user:pass@redis.prod.internal:6379/0
});