Skip to content

Latest commit

 

History

History
348 lines (286 loc) · 11.9 KB

cluster.md

File metadata and controls

348 lines (286 loc) · 11.9 KB

Cluster

Usage

1, we need to import the ClusterModule into our root module:

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

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

HINT: The ClusterModule is a global module. Once defined, this module is available everywhere.

2, we can use cluster in two ways.

via decorator:

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 ping(): Promise<string> {
        return await this.cluster.ping();
    }
}

via service:

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 ping(): Promise<string> {
        return await this.cluster.ping();
    }
}

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

Name Type Default value Description
closeClient boolean true If 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.
readyLog boolean false If true, will show a message when the client is ready.
config ClientOptions or ClientOptions[] undefined Specify single or multiple clients.

ClientOptions

Name Type Default value Description
namespace string or symbol 'default' The name of the client, and must be unique. You can import DEFAULT_CLUSTER_NAMESPACE to reference the default value.
nodes { host?: string; port?: number }[] or string[] or number[] undefined A list of nodes of the cluster. The first argument of new Cluster(startupNodes, options).
onClientCreated function undefined This function will be executed as soon as the client is created.
...ClusterOptions object - Extends the ClusterOptions.

Asynchronous configuration

via useFactory:

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: 'cluster1' }
                    }
                };
            }
        })
    ]
})
export class AppModule {}

via useClass:

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: 'cluster1' }
            }
        };
    }
}

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

via extraProviders:

// 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: {
        readyLog: true,
        config: {
            nodes: [{ host: 'localhost', port: 16380 }],
            redisOptions: { password: 'cluster1' }
        }
    }
};

@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.

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

readyLog

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: 'cluster1' }
            }
        })
    ]
})
export class AppModule {}

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

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

Single client

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

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

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

Multiple clients

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

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

with URL:

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

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

onClientCreated

For example, we can listen to the error event of the cluster client.

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

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

Non-global

By default, the ClusterModule is registered in the global scope, so ClusterService and all cluster clients defined are available everywhere.

You can change the behavior by modifying isGlobal parameter:

// 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(
            {
                readyLog: true,
                config: {
                    nodes: [{ host: 'localhost', port: 16380 }],
                    redisOptions: { password: 'cluster1' }
                }
            },
            false // <-- register inside the module scope
        )
    ],
    providers: [CatsService],
    controllers: [CatsController]
})
export class CatsModule {}