@edirect/lock
v11.0.52
Published
Distributed lock module for eDirect NestJS applications. Provides two Redis-backed locking primitives: a **Timed Lock** for exclusive one-at-a-time task execution across pods, and a **Distributed Lock** (owner lock) for leader-election patterns in cluster
Maintainers
Keywords
Readme
@edirect/lock
Distributed lock module for eDirect NestJS applications. Provides two Redis-backed locking primitives: a Timed Lock for exclusive one-at-a-time task execution across pods, and a Distributed Lock (owner lock) for leader-election patterns in clustered deployments.
Features
- Timed Lock: Ensures a named task runs exclusively across all pods — subsequent calls wait until the lock is released or expires
- Distributed Lock (owner): Leader election — only the pod that owns the lock executes critical logic; other pods skip it
- Backed by Redis (via
ioredis) - Configurable per-namespace lock owner (
NAMESPACEenv) - NestJS
registerAsyncsupport for environment-driven configuration
Installation
pnpm add @edirect/lock
# or
npm install @edirect/lockSetup
Register LockModule in your AppModule
import { Module } from '@nestjs/common';
import { ConfigModule, ConfigService } from '@edirect/config';
import { LockModule } from '@edirect/lock';
@Module({
imports: [
ConfigModule,
LockModule.registerAsync({
imports: [ConfigModule],
useFactory: (configService: ConfigService) => ({
lockOwner: configService.get('NAMESPACE') ?? 'default',
redis: {
host: configService.get('REDIS_HOST') ?? 'localhost',
port: Number(configService.get('REDIS_PORT') ?? 6379),
password: configService.get('REDIS_PASS'),
},
}),
inject: [ConfigService],
}),
],
})
export class AppModule {}Usage
Timed Lock — Exclusive Task Execution
Use when you need exactly one pod to execute a task at a time (e.g., a cron job, a background worker):
import { Injectable } from '@nestjs/common';
import { LockService } from '@edirect/lock';
@Injectable()
export class SyncService {
constructor(private readonly lock: LockService) {}
async syncPolicies() {
this.lock.lock(
'sync-policies-task',
async unlock => {
try {
// Only one pod will execute this at a time
await this.fetchAndSyncPolicies();
} finally {
// Always unlock when done
unlock();
}
},
30000
); // optional TTL in ms (30s default)
}
}Distributed Lock (Owner Lock) — Leader Election
Use when you need only the "owner" pod to run periodic work (e.g., scheduled jobs in a horizontally scaled deployment):
import { Injectable } from '@nestjs/common';
import { LockService } from '@edirect/lock';
import { Cron } from '@nestjs/schedule';
@Injectable()
export class JobService {
constructor(private readonly lock: LockService) {}
@Cron('0 * * * * *') // every minute
async runScheduledJob() {
if (await this.lock.isLockOwner()) {
// Only the owner pod runs this
await this.processJob();
}
}
}Redis Key/Value Operations
LockService also exposes raw Redis set/get:
await this.lock.set('feature-flag:new-flow', 'true');
const value = await this.lock.get('feature-flag:new-flow');API
LockService
Timed Lock
| Method | Signature | Description |
| ------ | --------------------------------------------------------------------------- | -------------------------------------------------------------------------------------------------------------- |
| lock | (key: string, callback: (unlock: () => void) => void, ttl?: number): void | Acquire an exclusive lock for key. The callback receives an unlock function that must be called when done. |
Distributed Lock (Owner)
| Method | Signature | Description |
| ----------------- | ---------------------- | -------------------------------------------------- |
| isLockOwner | (): Promise<boolean> | Returns true if this pod currently owns the lock |
| setLockOwner | (): Promise<string> | Claim ownership of the lock. Returns the owner ID. |
| getLockOwner | (): Promise<string> | Get the current lock owner ID |
| removeLockOwner | (): Promise<void> | Release ownership |
Redis Key/Value
| Method | Signature | Description |
| ------ | ----------------------------------------------------------------- | ----------------------------------------------------------------------------------- |
| set | (key: string, value: string, override?: boolean): Promise<void> | Set a Redis key. If override is false (default), won't overwrite existing values. |
| get | (key: string): Promise<string> | Get a Redis value |
Environment Variables
| Variable | Description | Required |
| ------------ | ------------------------------------------------ | -------- |
| REDIS_HOST | Redis server host | Yes |
| REDIS_PORT | Redis server port | Yes |
| REDIS_PASS | Redis password | No |
| NAMESPACE | Lock owner namespace (identifies this pod group) | Yes |
