v0.8.0
New
Project runner script
There is a new Moleculer project runner script in the bin
folder.
You can use it if you want to create small repos for services. In this case you needn't to create a ServiceBroker with options. Just create a moleculer.config.js
or moleculer.config.json
file in the root of repo fill it with your options and call the moleculer-runner
within the NPM scripts.
Other solution is that you don't put options to file, instead put it to the environment variables.
Shorthand for transporters, cachers and serializers in broker options
There are implemented some new resolvers in broker options to support shorthand configurations. This feature is enabled to load broker options easily from a JSON file or load from environment variables.
Usage for transporters
// Connect to the NATS default (localhost) server
let broker = new ServiceBroker({
transporter: "NATS"
});
// Connect to a NATS server with connection string
let broker = new ServiceBroker({
transporter: "nats://nats-server:4222"
});
// Connect to a NATS server with transporter options
let broker = new ServiceBroker({
transporter: {
type: "NATS",
options: {
prefix: "TEST",
nats: {
host: "nats-server",
user: "admin",
pass: "nats-pass"
}
}
}
});
Usage for cachers
// Use a memory cacher
let broker = new ServiceBroker({
cacher: true
// or
// cacher: "Memory"
});
// Use a Redis cacher with default options
let broker = new ServiceBroker({
cacher: "Redis"
});
// Use a Redis cacher with options
let broker = new ServiceBroker({
cacher: {
type: "Redis",
options: {
ttl: 100
}
}
});
Usage for serializers
// Use the Avro serializer
let broker = new ServiceBroker({
serializers: "Avro"
});
// Use the Protocol Buffer serializer
let broker = new ServiceBroker({
serializers: {
type: "ProtoBuf"
}
});
Built-in circuit breaker #22
Implemented better circuit breaker solution. Now every calls (local and remote) are protected with the built-in circuit breaker.
You only need to enable it in broker options.
Usage
let broker = new ServiceBroker({
circuitBreaker: {
enabled: true, // Enable this feature
maxFailures: 5, // Trip breaker on 5 failures
halfOpenTime: 10 * 1000 // 10 sec to switch to `half-open` state
failureOnTimeout: true // Failure if request timed out
failureOnReject: true // Failure if request rejected with error code >= 500
}
});
nodeUnavailable
method is dropped.
Service Registry module
Created a built-in Service Registry module. It handles actions of services on nodes, circuit breaker logic...etc. In the future it will be perhaps pluggable.
Via broker options you can change the load balancing strategies of Service Registry.
Example
const { STRATEGY_ROUND_ROBIN, STRATEGY_RANDOM } = require("moleculer");
let broker = new ServiceBroker({
registry: {
strategy: STRATEGY_ROUND_ROBIN, // Load balancing strategy
preferLocal: true // First call local service if available
}
});
REPL mode #30
Broker has an interactive REPL mode. You can load services, call actions, emit events, subscribe & unsubscribe events from your console. You can list registered nodes & actions.
To use REPL mode please install the moleculer-repl module with
npm install moleculer-repl --save
command.
Start REPL mode
let broker = new ServiceBroker({ logger: console });
// Start REPL
broker.repl();
Commands
Commands:
help [command...] Provides help for a given command.
exit Exits application.
q Exit application
call <actionName> [params] Call an action
dcall <nodeID> <actionName> [params] Call a direct action
emit <eventName> [payload] Emit an event
load <servicePath> Load a service from file
loadFolder <serviceFolder> [fileMask] Load all service from folder
subscribe <eventName> Subscribe to an event
unsubscribe <eventName> Unsubscribe from an event
actions [options] List of actions
nodes List of nodes
info Information from broker
REPL Commands
List nodes
mol $ nodes
List services
mol $ services
List actions
mol $ actions
Show common informations
mol $ info
Call an action
mol $ call "test.hello"
Call an action with params
mol $ call "math.add" '{"a": 5, "b": 4}'
Direct call
mol $ dcall server-2 "$node.health"
Emit an event
mol $ emit "user.created"
Subscribe to an event
mol $ subscribe "user.created"
Unsubscribe from an event
mol $ unsubscribe "user.created"
Load a service
mol $ load "./math.service.js"
Load services from folder
mol $ load "./services"
Direct call
There is available to call an action directly on a specified node. For use, you need to set nodeID
in options of call.
Example
broker.call("user.create", {}, { timeout: 5000, nodeID: "server-12" });
Mergeable schemas in createService
Now there is a second parameter of broker.createService
. With it you can override the schema properties. You can use it to use a built-in service & override some props.
Example
broker.createService(apiGwService, {
settings: {
// Change port setting
port: 8080
},
actions: {
myAction() {
// Add a new action to apiGwService service
}
},
created() {
// Overwrite apiGwService.created handler
}
});
Or you can merge it manually with mergeSchemas
method.
let mergedSchema = broker.mergeSchemas(origSchema, modifications);
broker.createService(mergedSchema);
Service mixins
Similar as mergeable schemas, the service can contain any mixin schemas. The constructor of Service will merge these mixins with the schema of Service. Use it to reuse an other Service in your service. Or you can extend an other Service.
Examples
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
}
}
}
New option to protect calling loop
You can protect your app against calling loop with the new maxCallLevel
option. If the ctx.level
value reaches this limit, will be thrown a MaxCallLevelError
error.
let broker = new ServiceBroker({
maxCallLevel: 100
});
New Service setting
There is a new useVersionPrefix
option in settings of Service. If false, Moleculer can't use the version number of service as prefix for action names. The name of service will be users.find
instead of v2.users.find
. The default is true
.
Changes
Removed the node.reconnected
and node.broken
events (breaking)
We merged the node.connected
and node.reconnected
events. The payload is changed:
{
node: {...},
reconnected: false // it indicates the node is connected or reconnected
}
We merged also the node.disconnected
and node.broken
events. The payload is changed:
{
node: {...},
unexpected: true // True: broken, not coming heart-beat, False: received "DISCONNECT" packet
}
Remove Transporter, Cacher and Serializers dependencies (breaking)
Moleculer doesn't contain dependencies for NATS, Redis, MQTT, MsgPack, Avro and Protobuf. So it need install manually in your project.
If you want to create a Moleculer project which communicates via NATS and your Redis cacher, you have to install npm install moleculer nats redis --save
Changed code of ServiceNotFoundError
The code of ServiceNotFoundError
is changed from 501
to 404
. More info
Using Nanomatch instead of micromatch
Memory cacher is using nanomatch instead of micromatch. The nanomatch
is ~10x faster.
Removed metricsSendInterval
option #24
The metricsSendInterval
option is removed from broker options. If you want to access statistics & health info, call the $node.health
and $node.stats
actions.
Metrics & Statistics separated #24
The metrics & statistics features separated. You can use just metrics or just statistics.
Metrics nodeID
Metrics events contains two nodeID properties.
nodeID
: the "caller" nodeIDtargetNodeID
: in case of remote call this is the remote nodeID
Response error with stack trace
If an action responses an error on a remote node, the transporter will send back the error to the caller with the stack traces.
// It will print the original error stack trace.
broker.call("account.deposit").catch(err => console.log(err.stack));
Type property in custom error
The CustomError
class renamed to MoleculerError
. It got a type
new property. You can store here a custom error type. E.g if you have a Validation error sometimes you don't enough the name & code. With type
the client can handle the cause of error programmatically.
Example
const ERR_MISSING_ID = "ERR_MISSING_ID";
const ERR_ENTITY_NOT_FOUND = "ERR_ENTITY_NOT_FOUND";
broker.createService({
actions: {
get(ctx) {
if (ctx.params.id) {
const entity = this.searchEntity(ctx.params.id);
if (entity)
return entity;
else
return Promise.reject(new ValidationError("Not found entity!", ERR_ENTITY_NOT_FOUND));
} else
return Promise.reject(new ValidationError("Please set the ID field!", ERR_MISSING_ID));
}
}
});
Renamed appendServiceName
settings to serviceNamePrefix
in Service schema
Fatal crash
The ServiceBroker
has a new fatal
method. If you call it, broker will log the message with fatal
level and exit the process with code 2
.
broker.fatal(message, err, needExit = true)
If you are running your app in containers and it has restart policy, you can use it to restart your app.
Usage
try {
// Do something dangerous
} catch(err) {
broker.fatal("Dangerous thing is happened!", err, true);
}
Low-level changes
- new output of
$node.actions
and$node.services
- In packet
INFO
&DISCOVER
changed theactions
property toservices
and now it contains all services with actions of node - splitted
broker.registerService
toregisterLocalService
andregisterRemoteService
- new
broker.unregisterServicesByNode
. It will be called when a node disconnected