Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

docs: backup #549

Merged
merged 1 commit into from
Sep 23, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
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