Moleculer-Start

Usage

Create your first microservice

demo.js

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
const { ServiceBroker } = require("moleculer");

const broker = new ServiceBroker();

broker.createService({
name: "math",
actions: {
add(ctx) {
return Number(ctx.params.a) + Number(ctx.params.b);
}
}
});

broker.start()
// Call service
.then(() => broker.call("math.add", { a: 5, b: 3 }))
.then(res => console.log("5 + 3 =", res))
.catch(err => console.error(`Error occured! ${err.message}`));
1
2
3
4
5
6
7
8
9
10
11
[2019-06-03T07:54:26.366Z] INFO  ********/BROKER: Moleculer v0.13.9 is starting...
[2019-06-03T07:54:26.369Z] INFO ********/BROKER: Node ID: ********
[2019-06-03T07:54:26.370Z] INFO ********/BROKER: Namespace: <not defined>
[2019-06-03T07:54:26.370Z] INFO ********/REGISTRY: Strategy: RoundRobinStrategy
[2019-06-03T07:54:26.372Z] INFO ********/BROKER: Serializer: JSONSerializer
[2019-06-03T07:54:26.373Z] INFO ********/BROKER: Registered 10 internal middleware(s).
[2019-06-03T07:54:26.390Z] INFO ********/REGISTRY: '$node' service is registered.
[2019-06-03T07:54:26.392Z] INFO ********/REGISTRY: 'math' service is registered.
[2019-06-03T07:54:26.394Z] INFO ********/BROKER: ServiceBroker with 2 service(s) is started successfully.
5 + 3 = 8
[2019-06-03T07:54:26.400Z] INFO ********/BROKER: ServiceBroker is stopped. Good bye.

看到上方範例會啟用一個 microservice

計算出 5 + 3 = 8

之後結束這個程式

Create a Moleculer project

Install Nats

需要先安裝 Nats

如果您是選擇其他的 transporters 也需要安裝其他的套件

目前有提供的

  • Nats - 推薦使用
  • MQTT
  • Redis
  • NATS streaming (試驗)
  • Kafka (試驗)

Mac

1
$ brew install gnatsd

Go

Initial Project

有提供一個 Cli tool

install moleculer-cli

1
$ npm i moleculer-cli -g

create a new project

1
$ moleculer init project moleculer-demo

client 會提供幾個選項讓你選擇

1
2
3
4
5
6
7
8
9
10
? Add API Gateway (moleculer-web) service? // 是否使用 api gateway
? Would you like to communicate with other nodes? // 是否需要和其他 nodes 溝通
? Select a transporter NATS (recommended) // 使用哪一種 transporter 工具
? Would you like to use cache? 是否要使用 cache
? Select a cacher solution
? Add Docker files? 是否要使用 Docker
? Use ESLint to lint your code? 是否使用 ESLint
? Setup unit tests with Jest? Unitest framework
Create 'moleculerdemo' folder...
? Would you like to run 'npm install'?

可以依據個人的需求選擇

然後就可以得到一個專案

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
.
├── README.md
├── moleculer.config.js
├── package-lock.json
├── package.json
├── public
│   ├── banner.png
│   ├── favicon.ico
│   └── index.html
├── services
│   ├── api.service.js
│   └── greeter.service.js
└── test
└── unit
└── greeter.spec.js
1
$ yarn dev // 啟動一個 service

Broker

ServiceBrokerMoleculer 中主要的 component

他會處理幾件 nodes 之間溝通的事情

  • actions
  • emits
  • events
  • communicates

Broker Options

Ping

對遠端的 nodes 使用 broker.ping 來確認遠端 nodes 的狀態

回傳值是一個 Promise

Example

ping 一個 node 並設定 1S 的 timeout

1
broker.ping("node-123", 1000).then(res => broker.logger.info(res));

output

1
2
3
4
5
{ 
nodeID: 'node-123',
elapsedTime: 16,
timeDiff: -3
}
1
timeDiff 是兩個節點之間系統時間的誤差值

也可以同時 ping 多個 nodes

1
broker.ping(["node-100", "node-102"]).then(res => broker.logger.info(res));

output

1
2
3
4
5
6
7
8
9
10
11
12
{ 
"node-100": {
nodeID: 'node-100',
elapsedTime: 10,
timeDiff: -2
},
"node-102": {
nodeID: 'node-102',
elapsedTime: 250,
timeDiff: 850
}
}

ping 所有的 nodes

1
broker.ping().then(res => broker.logger.info(res));

output

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18

{
"node-100": {
nodeID: 'node-100',
elapsedTime: 10,
timeDiff: -2
} ,
"node-101": {
nodeID: 'node-101',
elapsedTime: 18,
timeDiff: 32
},
"node-102": {
nodeID: 'node-102',
elapsedTime: 250,
timeDiff: 850
}
}

broker properties

broker methods

Services

Services 代表 Moleculer 中的微服務

可以定義多個 action 並且訂閱 ‘event’

建立新的 service 必須先定義好 schema

這些 schema 類似 component of Vuejs

  • name
  • version
  • settings
  • methods
  • events

Actions

基本的 schema

1
2
3
4
{
name: "posts",
version: 1
}

定義多個 actions

1
2
3
4
5
6
7
8
9
10
11
12
{
name: "math",
actions: {
add(ctx) {
return Number(ctx.params.a) + Number(ctx.params.b);
},

sub(ctx) {
return Number(ctx.params.a) - Number(ctx.params.b);
}
}
}

name 是必須要定義的參數

當你呼叫這個 api 時,是第一部分的 route 組成元素

1
2
3
4
5
// 可以在設定中 disable service name prefix

{
$noServiceNamePrefix: true
}

version 不是必要的參數

可以讓同樣的 service 跑不同的 version 做 api 版本控制

可以是 NumberString

1
2
3
4
5
6
7
{
name: "posts",
version: 2,
actions: {
find() {...}
}
}

在上方的範例中若是要呼叫這隻 API route 為 GET /v2/posts/find

Settings

settings 是一個 store

你可以在裡面做各種設定

使用 this.settings 取得你的 setting object

setting options

Mixins

Mixins 是一個可以在 Moleculer 中可以重複使用的 function

Service 的 constructor 會自動合併這些 mixins

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
const ApiGwService = require("moleculer-web");

module.exports = {
name: "api",
mixins: [ApiGwService]
settings: {
// Change port setting
port: 8080
},
actions: {
myAction() {
// Add a new action to apiGwService service
}
}
}

合併的規則

Lifecycle events

當 service 生命週期各自會 trigger 的 function

  • startd
  • stopped
  • created

Dependencies

當你的 service 有依賴到其他 service 的時候

可以利用 Dependencies 來做處理(待捕)

Hot reloading services

在開發過程中需要使用 hot reloading 的機制有兩種方式

1
2
3
4
5
const broker = new ServiceBroker({
hotReload: true
});

broker.loadService("./services/test.service.js");

或是 command

1
$ moleculer-runner --hot ./services/test.service.js

Local variables

如果你需要一些 Local variables

可以在 created 中宣告

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
const http = require("http");

module.exports = {
name: "www",

settings: {
port: 3000
},

created() {
// Create HTTP server
this.server = http.createServer(this.httpHandler);
},

started() {
// Listening...
this.server.listen(this.settings.port);
},

stopped() {
// Stop server
this.server.close();
},

methods() {
// HTTP handler
httpHandler(req, res) {
res.end("Hello Moleculer!");
}
}
}

ES6 classses

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
const Service = require("moleculer").Service;

class GreeterService extends Service {

constructor(broker) {
super(broker);

this.parseServiceSchema({
name: "greeter",
version: "v2",
meta: {
scalable: true
},
dependencies: [
"auth",
"users"
],

settings: {
upperCase: true
},
actions: {
hello: this.hello,
welcome: {
cache: {
keys: ["name"]
},
params: {
name: "string"
},
handler: this.welcome
}
},
events: {
"user.created": this.userCreated
},
created: this.serviceCreated,
started: this.serviceStarted,
stopped: this.serviceStopped,
});
}

// Action handler
hello() {
return "Hello Moleculer";
}

// Action handler
welcome(ctx) {
return this.sayWelcome(ctx.params.name);
}

// Private method
sayWelcome(name) {
this.logger.info("Say hello to", name);
return `Welcome, ${this.settings.upperCase ? name.toUpperCase() : name}`;
}

// Event handler
userCreated(user) {
this.broker.call("mail.send", { user });
}

serviceCreated() {
this.logger.info("ES6 Service created.");
}

serviceStarted() {
this.logger.info("ES6 Service started.");
}

serviceStopped() {
this.logger.info("ES6 Service stopped.");
}
}

module.exports = GreeterService;
文章目录
  1. 1. Usage
    1. 1.1. Create your first microservice
    2. 1.2. Create a Moleculer project
      1. 1.2.1. Install Nats
        1. 1.2.1.1. Mac
        2. 1.2.1.2. Go
      2. 1.2.2. Initial Project
    3. 1.3. Broker
      1. 1.3.1. Ping
        1. 1.3.1.1. Example
    4. 1.4. Services
      1. 1.4.1. Actions
      2. 1.4.2. Settings
      3. 1.4.3. Mixins
      4. 1.4.4. Lifecycle events
      5. 1.4.5. Dependencies
      6. 1.4.6. Hot reloading services
      7. 1.4.7. Local variables
        1. 1.4.7.1. ES6 classses
|