Skip to content

Commit

Permalink
docs: backup (#549)
Browse files Browse the repository at this point in the history
  • Loading branch information
liaoliaots authored Sep 23, 2024
1 parent f50ff6e commit cb18450
Show file tree
Hide file tree
Showing 4 changed files with 936 additions and 2 deletions.
8 changes: 6 additions & 2 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@
<h1 align="center">Nest Redis Module</h1>

<p align="center">
Redis(ioredis) module for Nest framework (node.js).
Redis(ioredis & node-redis) module for Nest framework (node.js).
<br />
<a href="#usage"><strong>Explore the docs »</strong></a>
<br />
Expand Down Expand Up @@ -76,8 +76,12 @@ This lib requires **Node.js >=16.13.0**, **NestJS ^10.0.0**, **ioredis ^5.0.0**.

- If you depend on **ioredis 5** & **NestJS 10**, please use version **10** of the lib.
- If you depend on **ioredis 5** & **NestJS 9**, please use version **9** of the lib.
- If you depend on **ioredis 4**, please use [version 7](https://github.com/liaoliaots/nestjs-redis/tree/v7.0.0) of the lib.
- If you depend on **ioredis 5**, **NestJS 7** or **8**, please use [version 8](https://github.com/liaoliaots/nestjs-redis/tree/v8.2.2) of the lib.
- If you depend on **ioredis 4**, please use [version 7](https://github.com/liaoliaots/nestjs-redis/tree/v7.0.0) of the lib.

### Node-Redis

If you prefre [node-redis](https://github.com/redis/node-redis), check out [this guide](), but it is in working progress.

### Installation

Expand Down
359 changes: 359 additions & 0 deletions docs/v9/cluster.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,359 @@
## Usage

**First**, we need to import the `ClusterModule` into our root module:

```ts
import { Module } from '@nestjs/common';
import { ClusterModule } from '@liaoliaots/nestjs-redis';

@Module({
imports: [
ClusterModule.forRoot({
config: {
nodes: [{ host: 'localhost', port: 16380 }],
redisOptions: { password: 'authpassword' }
}
})
]
})
export class AppModule {}
```

**Now**, we can use cluster in two ways.

via decorator:

```ts
import { Injectable } from '@nestjs/common';
import { InjectCluster, DEFAULT_CLUSTER_NAMESPACE } from '@liaoliaots/nestjs-redis';
import { Cluster } from 'ioredis';

@Injectable()
export class AppService {
constructor(
@InjectCluster() private readonly cluster: Cluster // or // @InjectCluster(DEFAULT_CLUSTER_NAMESPACE) private readonly cluster: Cluster
) {}

async set() {
return await this.cluster.set('key', 'value', 'EX', 10);
}
}
```

via service:

```ts
import { Injectable } from '@nestjs/common';
import { ClusterService, DEFAULT_CLUSTER_NAMESPACE } from '@liaoliaots/nestjs-redis';
import { Cluster } from 'ioredis';

@Injectable()
export class AppService {
private readonly cluster: Cluster;

constructor(private readonly clusterService: ClusterService) {
this.cluster = this.clusterService.getClient();
// or
// this.cluster = this.clusterService.getClient(DEFAULT_CLUSTER_NAMESPACE);
}

async set() {
return await this.cluster.set('key', 'value', 'EX', 10);
}
}
```

> HINT: By default, the `ClusterModule` is a [**Global module**](https://docs.nestjs.com/modules#global-modules).
> HINT: If you don't set the `namespace` for a client, its namespace is set to `"default"`. Please note that you shouldn't have multiple client without a namespace, or with the same namespace, otherwise they will get overridden.
## Configuration

### [ClusterModuleOptions](/packages/redis/lib/cluster/interfaces/cluster-module-options.interface.ts)

| Name | Type | Default | Required | Description |
| ----------- | -------------------------------------------------- | ----------- | -------- | -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| closeClient | `boolean` | `true` | `false` | If set to `true`, all clients will be closed automatically on nestjs application shutdown. To use `closeClient`, you **must enable listeners** by calling `app.enableShutdownHooks()`. [Read more about the application shutdown.](https://docs.nestjs.com/fundamentals/lifecycle-events#application-shutdown) |
| readyLog | `boolean` | `false` | `false` | If set to `true`, then ready logging will be displayed when the client is ready. |
| errorLog | `boolean` | `true` | `false` | If set to `true`, then errors that occurred while connecting will be displayed by the built-in logger. |
| config | `ClusterClientOptions` \| `ClusterClientOptions`[] | `undefined` | `true` | Used to specify single or multiple clients. |

### [ClusterClientOptions](/packages/redis/lib/cluster/interfaces/cluster-module-options.interface.ts)

| Name | Type | Default | Required | Description |
| ---------------------- | ---------------------------------------------------------------- | ----------- | -------- | ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| namespace | `string` \| `symbol` | `'default'` | `false` | Client name. If client name is not given then it will be called "default". Different clients must have different names. You can import `DEFAULT_CLUSTER_NAMESPACE` to use it. |
| nodes | `{ host?: string; port?: number }[]` \| `string[]` \| `number[]` | `undefined` | `true` | List of cluster nodes. |
| onClientCreated | `function` | `undefined` | `false` | Function to be executed as soon as the client is created. |
| **...** ClusterOptions | `ClusterOptions` | - | `false` | Inherits from [ClusterOptions](https://luin.github.io/ioredis/interfaces/ClusterOptions.html). |

### Asynchronous configuration

via `useFactory`:

```ts
import { Module } from '@nestjs/common';
import { ClusterModule, ClusterModuleOptions } from '@liaoliaots/nestjs-redis';
import { ConfigService, ConfigModule } from '@nestjs/config';

@Module({
imports: [
ClusterModule.forRootAsync({
imports: [ConfigModule],
inject: [ConfigService],
useFactory: async (configService: ConfigService): Promise<ClusterModuleOptions> => {
await somePromise();

return {
config: {
nodes: [{ host: 'localhost', port: 16380 }],
redisOptions: { password: 'authpassword' }
}
};
}
})
]
})
export class AppModule {}
```

via `useClass`:

```ts
import { Module, Injectable } from '@nestjs/common';
import { ClusterModule, ClusterOptionsFactory, ClusterModuleOptions } from '@liaoliaots/nestjs-redis';

@Injectable()
export class ClusterConfigService implements ClusterOptionsFactory {
async createClusterOptions(): Promise<ClusterModuleOptions> {
await somePromise();

return {
config: {
nodes: [{ host: 'localhost', port: 16380 }],
redisOptions: { password: 'authpassword' }
}
};
}
}

@Module({
imports: [
ClusterModule.forRootAsync({
useClass: ClusterConfigService
})
]
})
export class AppModule {}
```

via `extraProviders`:

```ts
// just a simple example

import { Module, ValueProvider } from '@nestjs/common';
import { ClusterModule, ClusterModuleOptions } from '@liaoliaots/nestjs-redis';

const MyOptionsSymbol = Symbol('options');
const MyOptionsProvider: ValueProvider<ClusterModuleOptions> = {
provide: MyOptionsSymbol,
useValue: {
config: {
nodes: [{ host: 'localhost', port: 16380 }],
redisOptions: { password: 'authpassword' }
}
}
};

@Module({
imports: [
ClusterModule.forRootAsync({
useFactory(options: ClusterModuleOptions) {
return options;
},
inject: [MyOptionsSymbol],
extraProviders: [MyOptionsProvider]
})
]
})
export class AppModule {}
```

... or via `useExisting`, if you wish to use an existing configuration provider imported from a different module.

```ts
ClusterModule.forRootAsync({
imports: [ConfigModule],
useExisting: ConfigService
});
```

### readyLog

```ts
import { Module } from '@nestjs/common';
import { ClusterModule } from '@liaoliaots/nestjs-redis';

@Module({
imports: [
ClusterModule.forRoot({
readyLog: true,
config: {
nodes: [{ host: 'localhost', port: 16380 }],
redisOptions: { password: 'authpassword' }
}
})
]
})
export class AppModule {}
```

The `ClusterModule` will display a message when `CLUSTER INFO` reporting the cluster is able to receive commands.

```sh
[Nest] 18886 - 09/16/2021, 6:19:56 PM LOG [ClusterModule] default: connected successfully to the server
```

### Single client

```ts
import { Module } from '@nestjs/common';
import { ClusterModule } from '@liaoliaots/nestjs-redis';

@Module({
imports: [
ClusterModule.forRoot({
config: {
nodes: [{ host: 'localhost', port: 16380 }],
redisOptions: { password: 'authpassword' }

// or with URL
// nodes: ['redis://:authpassword@localhost:16380']
}
})
]
})
export class AppModule {}
```

### Multiple clients

```ts
import { Module } from '@nestjs/common';
import { ClusterModule } from '@liaoliaots/nestjs-redis';

@Module({
imports: [
ClusterModule.forRoot({
config: [
{
nodes: [{ host: 'localhost', port: 16380 }],
redisOptions: { password: 'authpassword' }
},
{
namespace: 'cluster2',
nodes: [{ host: 'localhost', port: 16480 }],
redisOptions: { password: 'authpassword' }
}
]
})
]
})
export class AppModule {}
```

with URL:

```ts
import { Module } from '@nestjs/common';
import { ClusterModule } from '@liaoliaots/nestjs-redis';

@Module({
imports: [
ClusterModule.forRoot({
config: [
{
nodes: ['redis://:authpassword@localhost:16380']
},
{
namespace: 'cluster2',
nodes: ['redis://:authpassword@localhost:16480']
}
]
})
]
})
export class AppModule {}
```

### onClientCreated

For example, we can listen to some events of the cluster instance.

```ts
import { Module } from '@nestjs/common';
import { ClusterModule } from '@liaoliaots/nestjs-redis';

@Module({
imports: [
ClusterModule.forRoot({
config: {
nodes: [{ host: 'localhost', port: 16380 }],
redisOptions: { password: 'authpassword' },
onClientCreated(client) {
client.on('error', err => {});
client.on('ready', () => {});
}
}
})
]
})
export class AppModule {}
```

### Non-Global

By default, the `ClusterModule` is a **Global module**, `ClusterService` and all cluster instances are registered in the global scope. Once defined, they're available everywhere.

You can change this behavior by `isGlobal` parameter:

```ts
// cats.module.ts
import { Module } from '@nestjs/common';
import { ClusterModule } from '@liaoliaots/nestjs-redis';
import { CatsService } from './cats.service';
import { CatsController } from './cats.controller';

@Module({
imports: [
ClusterModule.forRoot(
{
config: {
nodes: [{ host: 'localhost', port: 16380 }],
redisOptions: { password: 'authpassword' }
}
},
false // <-- providers are registered in the module scope
)
],
providers: [CatsService],
controllers: [CatsController]
})
export class CatsModule {}
```

### Testing

This package exposes `getClusterToken()` function that returns an internal injection token based on the provided context. Using this token, you can provide a mock implementation of the cluster instance using any of the standard custom provider techniques, including `useClass`, `useValue`, and `useFactory`.

```ts
import { Test, TestingModule } from '@nestjs/testing';
import { getRedisToken } from '@liaoliaots/nestjs-redis';

const module: TestingModule = await Test.createTestingModule({
providers: [{ provide: getClusterToken('namespace'), useValue: mockedInstance }, YourService]
}).compile();
```

A working example is available [here](/sample).
Loading

0 comments on commit cb18450

Please sign in to comment.