@tecace/nest-consul v0.0.3
@tecace/nest-consul
请注意:本工具的主要目的是为了帮助 NestJS 用户更轻松地进行 consul 服务注册和健康检查,而不是为了封装 Consul 的 API。使用该工具时,可以选择自动或手动注册服务,然后通过 api 获取 Consul 实例,可以像使用官方 API 一样使用它来管理服务或进行二次封装。
base on node-consul@1.2.0 https://www.npmjs.com/package/consul/v/1.2.0
基于 node-consul 的 1.2.0 版本封装的 nestjs 版本,封装了服务和健康检查注册/注销,kv 存储操作,获取其他服务的url等功能,绑定了自动注册服务/健康检查,可以手动注销服务和健康检查。
Documentation
install
npm install @tecace/nest-consul
# or
pnpm add @tecace/nest-consul
use
这里只是核心的代码,当中还涉及了微服务的创建,运行等,参考官方文档 https://docs.nestjs.com/microservices/grpc#grpc
注册module
单独注册ConsulModule
// app.modules.ts or any.modules.ts
import { ConsulModule, ConsulService } from '@tecace/nest-consul';
@Module({
imports: [
// 参数类型是InitOptions, 下文会提到InitOptions的类型
ConsulModule.register({
host: 'localhost',
port: '8500',
promisify: true,
autoRegister: true, // 自动注册服务与健康检查
registerOptions: {
// 服务配置
id: 'user-service',
name: 'user-service',
port: 5001,
address: 'localhost',
},
check: {
// 可选,健康检查配置,要注册健康检查,需要开发好对应接口,consul会根据提供的grpc/http等类型进行检查
id: 'user_health_check',
name: 'user_health_check',
// http: 'localhost:5001/health/check'
grpc: 'localhost:5001',
interval: '15s',
ttl: '10s',
},
}),
],
controllers: [AppController],
providers: [ConsulService], // 需要提供ConsulService,在AppController中才能使用consulService
})
export class AppModule {}
或在微服务ClientsModule中注册
import { ClientsModule, Transport } from '@nestjs/microservices';
// 省略部分代码
ClientsModule.registerAsync([
{
imports: [
// 在微服务中注册ConsulModule
ConsulModule.register({
host: '10.211.55.14',
port: '8500',
promisify: true,
autoRegister: true,
registerOptions: {
id: 'category-service',
name: 'category-service',
port: 5002,
address: '192.168.31.117',
},
check: {
id: 'category_health_check',
name: 'category_health_check',
grpc: '192.168.31.117:5002',
interval: '15s',
ttl: '10s',
},
}),
],
name: 'UserGrpcClient',
useFactory: async (consulSrv: ConsulService) => {
const url = await consulSrv.getServiceUrl('user-service'); // 在另外一个微服务中获取user-service注册相关的url,以便进行通信
return {
name: 'UserGrpcClient',
transport: Transport.GRPC,
options: {
url,
package: protosLoader.getPackages(),
protoPath: protosLoader.getProtos(),
},
};
},
inject: [ConsulService],
},
]),
// 省略部分代码
// app.controller.ts or any.controller.ts
import { Controller, Inject } from '@nestjs/common';
import { GrpcMethod } from '@nestjs/microservices';
import { ConsulService } from '@tecace/nest-consul';
@Controller()
export class AppController {
// 这里注入了consulService的实例,会基于在app.module.ts中导入模块的配置进行操作
constructor(@Inject(ConsulService) private consulService: ConsulService) {}
// 这里需要实现grpc健康检查
@GrpcMethod('Health', 'Check')
healthCheck() {
return {
status: 1,
};
}
// 实现服务和健康检查的注销
@GrpcMethod('Health', 'Deregister')
async deregister() {
const [err] = await this.consulService.srvDeregistration();
if (err) {
console.error(err);
}
}
// 实现服务和检查检查的注册
@GrpcMethod('Health', 'Register')
async register() {
const [err] = await this.consulService.srvRegistration();
if (err) {
console.error(err);
}
}
}
注意:如果使用 grpc 进行健康检查,这个包名不可以改动 注意:如果使用 grpc 进行健康检查,这个包名不可以改动 注意:如果使用 grpc 进行健康检查,这个包名不可以改动
PS: I don't know why, 每次改了健康检查它就是不行。
protofile 官方原代码:https://github.com/grpc/grpc/blob/master/doc/health-checking.md
下面的 proto 文件是笔者增加了一些
syntax = "proto3";
package grpc.health.v1;
message HealthCheckRequest {
string service = 1;
}
message HealthCheckResponse {
enum ServingStatus {
UNKNOWN = 0;
SERVING = 1;
NOT_SERVING = 2;
SERVICE_UNKNOWN = 3; // Used only by the Watch method.
}
ServingStatus status = 1;
}
message Empty {}
service Health {
rpc Check(HealthCheckRequest) returns (HealthCheckResponse);
rpc Deregister(Empty) returns (Empty);
rpc Register(Empty) returns (Empty);
rpc Watch(HealthCheckRequest) returns (stream HealthCheckResponse);
}
api
getConsulInstance(): Consul.Consul; 核心 api
返回初始化后的 consul 实例,从而像使用官方 API 一样使用,初始化 Consul 阶段基于 InitOptions 中的 ConsulOptions 部分,InitOptions 请查看下一小节
const consul = consulService.getConsulInstance();
// 假如要使用catalog
consul.catalog.register(options)
// 要使用session
consul.session.create();
constructor(consulOptions: InitOptions);
ConsulModule.register(consulOptions: InitOptions)
// InitOptions是基于官方提供的类型进行合并或者扩展
export type InitOptions = ConsulOptions & {
autoRegister?: boolean; //是否自动注册
registerOptions: Consul.Agent.Service.RegisterOptions; // 服务配置
// 健康检查配置
check?: Consul.Agent.Check.RegisterOptions & {
id: string;
grpc?: string;
};
};
srvRegistration(): Promise<err: string>;
服务和健康检查注册,如果在 InitOptions 中提供了 autoRegister,那么这个 api 在初始化阶段会自动调用
const [err] = await consulService.srvRegistration();
srvDeregistration(): Promise<err: string>;
服务和健康检查注销
const [err] = await consulService.srvDeregistration();
kvSet(data: Consul.Kv.SetOptions): Promise<err: string>;
k/v 存的设置,data 类型是 Consul.kv.SetOptions
const [err] = await consulService.kvSet({
key: 'someKey',
value: 'someValue',
dc: 'datacenter in your defination',
...
});
kvGet(data: Consul.Kv.GetOptions): Promise<err: string, data: any>;
k/v 获取的设置,data 类型是 Consul.kv.GetOptions
const [err, res] = await consulService.kvGet({
key: 'someKey',
dc: 'datacenter in your defination',
...
});
getService(serviceName?: string): Promise<err: string, data: ConsulServiceList | ConsulServiceDetail | null>;
获取 service 列表或者service的详情,传了serviceName返回对应的详情,反之返回列表
const [err, serviceList] = await consulSrv.getService(); // 返回列表
const [err, serviceDetail] = await consulSrv.getService("user-service") // 返回详情
getServiceUrl(serviceName?: string): Promise<err: string, data: ConsulServiceList | ConsulServiceDetail | null>;
获取 service 列表或者service的详情,传了serviceName返回对应的详情,反之返回列表
const [err, url] = await consulSrv.getServiceUrl('user-service');
// url host:port
// err null