Skip to main content
Version: 4.0.0

etcd

etcd is an important basic component in the cloud native architecture, hosted by CNCF incubation. etcd can be registered as a service in discovery in microservices and Kubernetes clusters, and can also be used as a middleware for key-value storage.

Midway provides components packaged based on the etcd3 module, which provides etcd client calling capabilities.

Related Information:

Description
Available for Standard Items
Available for Serverless
Can be used for integration
contains independent main frame
Contains standalone logs

Install dependencies

$ npm i @midwayjs/etcd@3 --save

Or add the following dependencies in package.json and reinstall.

{
"dependencies": {
"@midwayjs/etcd": "^3.0.0",
//...
},
}

import component

First, import the component, import it in configuration.ts:

import { Configuration } from '@midwayjs/core';
import * as etcd from '@midwayjs/etcd';
import { join } from 'path'

@Configuration({
imports: [
//...
etcd,
],
//...
})
export class MainConfiguration {
}

Configure the default client

In most cases, we can only use the default client to complete the function.

// src/config/config.default.ts
export default {
//...
etcd: {
client: {
host: [
'127.0.0.1:2379'
]
},
},
}

Use the default client

After the configuration is complete, we can use it in the code.

import { Provide } from '@midwayjs/core';
import { ETCDService } from '@midwayjs/etcd';
import { join } from 'path';

@Provide()
export class UserService {

@Inject()
etcdService: ETCDService;

async invoke() {

await this.etcdService.put('foo').value('bar');

const fooValue = await this.etcdService.get('foo').string();
console.log('foo was:', fooValue);

const allFValues = await this.etcdService.getAll().prefix('f').keys();
console.log('all our keys starting with "f":', allFValues);

await this.etcdService.delete().all();
}
}

For more APIs, please refer to the ts definition or official document.

Multiple instance configuration

// src/config/config.default.ts
export default {
//...
etcd: {
clients: {
instance1: {
{
host: [
'127.0.0.1:2379'
]
},
},
instance2: {
{
host: [
'127.0.0.1:2379'
]
},
}
}
},
}

Get multiple instances

import { Provide } from '@midwayjs/core';
import { ETCDServiceFactory } from '@midwayjs/etcd';
import { join } from 'path';

@Provide()
export class UserService {

@Inject()
etcdServiceFactory: ETCDServiceFactory;

async invoke() {
const instance1 = this.etcdServiceFactory.get('instance1');
//...

const instance2 = this.etcdServiceFactory.get('instance2');
//...
}
}

Service Discovery

From v4, Midway provides a unified abstract service discovery capability. Although ETCD is not ideal as a registration center, we still implement ETCD as a service discovery client.

Service discovery includes service registration and service retrieval.

Configure service discovery

Configure at least one client; if multiple clients exist, specify the one used for discovery via serviceDiscoveryClient.

Configure discovery options via serviceDiscovery:

// src/config/config.default.ts
export default {
etcd: {
clients: {
default: { hosts: ['127.0.0.1:2379'] }
},
serviceDiscovery: {
namespace: 'services',
ttl: 30,
// optional: loadBalancer: LoadBalancerType.ROUND_ROBIN
}
}
}

Notes: namespace is the keyspace prefix; instance keys follow namespace/serviceName/instanceId. ttl is the expiration time in seconds.

Register a service

Register the current service to ETCD after startup:

import { Configuration, Inject } from '@midwayjs/core';
import { EtcdServiceDiscovery } from '@midwayjs/etcd';

@Configuration({})
export class MainConfiguration {
@Inject()
etcdDiscovery: EtcdServiceDiscovery;

async onServerReady() {
// create discovery client (override options if needed)
const client = this.etcdDiscovery.createClient();

// register current service and bring it online (write key and bind lease)
await client.register({
id: client.defaultMeta.id,
serviceName: 'order',
ttl: 30,
meta: {
version: '1.0.0',
host: client.defaultMeta.host,
port: '7001'
}
});
}
}

Notes: Registration brings the instance online by default; no need to call online. ETCD maintains TTL via Lease with periodic renewal; offline deletes the key and revokes the lease; deregister unregisters and cleans state. Repeated calls to register/online/offline/deregister are idempotent.

Get available services

Fetch all healthy instances or select one according to the load balancer:

@Provide()
export class OrderService {
@Inject()
etcdDiscovery: EtcdServiceDiscovery;

async getService() {
const instances = await this.etcdDiscovery.getInstances('order');
const one = await this.etcdDiscovery.getInstance('order');
return { instances, one };
}
}

Returned instances are the objects written during registration (EtcdInstanceMetadata), typically including serviceName/id/ttl/meta/tags/status fields.

Create instance dynamically

import { Provide } from '@midwayjs/core';
import { ETCDServiceFactory } from '@midwayjs/etcd';
import { join } from 'path';

@Provide()
export class UserService {

@Inject()
etcdServiceFactory: ETCDServiceFactory;

async invoke() {
const instance3 = await this.etcdServiceFactory.createInstance({
host: [
'127.0.0.1:2379'
]
}, 'instance3');
//...
}
}