The Service
represents a microservice in the Moleculer framework. You can define actions and subscribe to events. To create a service you must define a schema. The service schema is similar to a component of VueJS.
Schema
The schema has some main parts name
, version
, settings
, actions
, methods
, events
that are described below.
Simple service schema to define two actions
// math.service.js |
Name & Version
Services are defined using a schema-based approach. This section explores the two mandatory properties that form the foundation of a service definition:
name
- This property represents a unique identifier for your service within the Moleculer application.
- It serves as the first part of the action name when invoking actions provided by the service.
version
- This optional property allows you to define multiple versions of the same service within your application.
- When specified, it acts as a prefix to the action name, enabling versioning for your service’s functionality. The version can be either a number or a string.
// posts.v2.service.js |
To call this find
action on version 2
service:
broker.call("v2.posts.find"); |
REST callVia API Gateway, make a request to
GET /v2/posts/find
.
Disabling Prefixes
Moleculer.js provides a way to disable both service name and version prefixing within service settings using the $noServiceNamePrefix
and $noVersionPrefix
properties, respectively. However, it’s generally recommended to maintain these prefixes for better organization and clarity within your microservices architecture.
Additional Considerations
- Consider utilizing versioning for services that undergo significant changes over time, allowing for a smooth transition between versions.
- Remember that disabling prefixes can lead to naming conflicts if multiple services have the same action names.
Settings
The settings
property is a static store, where you can store every settings/options to your service. You can reach it via this.settings
inside the service.
// mailer.service.js |
Note: The
settings
is also obtainable on remote nodes. It is transferred during service discovering.
Internal Settings
There are some internal settings which are used by core modules. These setting names start with $
(dollar sign).
Name | Type | Default | Description |
---|---|---|---|
$noVersionPrefix |
Boolean |
false |
Disable version prefixing in action names. |
$noServiceNamePrefix |
Boolean |
false |
Disable service name prefixing in action names. |
$dependencyTimeout |
Number |
0 |
Timeout for dependency waiting. |
$shutdownTimeout |
Number |
0 |
Timeout for waiting for active requests at shutdown. |
$secureSettings |
Array |
[] |
List of secure settings. |
Secure service settings
To protect your tokens & API keys, define a $secureSettings: []
property in service settings and set the protected property keys. The protected settings won’t be published to other nodes and it won’t appear in Service Registry. These settings will only available under this.settings
inside the service functions.
// mail.service.js |
Mixins
Mixins are a flexible way to distribute reusable functionalities for Moleculer services. The Service constructor merges these mixins with the current schema. When a service uses mixins, all properties present in the mixin will be “mixed” into the current service.
Example how to extend moleculer-web
service
// api.service.js |
The above example creates an api
service which inherits all properties from ApiGwService
but overwrite the port setting and extend it with a new myAction
action.
Merge algorithm
The merge algorithm depends on the property type.
Property | Algorithm |
---|---|
name , version |
Merge & overwrite. |
settings |
Deep extend with defaultsDeep. |
metadata |
Deep extend with defaultsDeep. |
actions |
Deep extend with defaultsDeep. You can disable an action from mixin if you set to false in your service. |
hooks |
Deep extend with defaultsDeep. |
methods |
Merge & overwrite. |
events |
Concatenate listeners. |
created , started , stopped |
Concatenate listeners. |
mixins |
Merge & overwrite. |
dependencies |
Merge & overwrite. |
any custom | Merge & overwrite. |
Merge algorithm examplesMerge & overwrite: if serviceA has
a: 5
,b: 8
and serviceB hasc: 10
,b: 15
, the mixed service will havea: 5
,b: 15
andc: 10
.
Concatenate: if serviceA & serviceB subscribe tousers.created
event, both event handler will be called when theusers.created
event emitted.
Actions
The actions are the callable/public methods of the service. They are callable with broker.call
or ctx.call
.
The action could be a Function
(shorthand for handler) or an object with some properties and handler
.
The actions should be placed under the actions
key in the schema. For more information check the actions documentation.
// math.service.js |
You can call the above actions as
const res = await broker.call("math.add", { a: 5, b: 7 }); |
Inside actions, you can call other nested actions in other services with ctx.call
method. It is an alias to broker.call
, but it sets itself as parent context (due to correct tracing chains).
// posts.service.js |
In action handlers the
this
is always pointed to the Service instance.
Events
You can subscribe to events under the events
key. For more information check the events documentation.
// report.service.js |
In event handlers the
this
is always pointed to the Service instance.
Grouping
The broker groups the event listeners by group name. By default, the group name is the service name. But you can overwrite it in the event definition.
// payment.service.js |
Methods
To define private methods within a service, place your functions under the methods
key in the schema. These methods are not directly callable with broker.call
, but can be invoked internally within the service, such as from action handlers, event handlers, and lifecycle event handlers.
Usage
// mailer.service.js |
If you want to wrap a method with a middleware use the following notation:
// posts.service.js |
The method name can’t be
name
,version
,settings
,metadata
,schema
,broker
,actions
,logger
, because these words are reserved in the schema.
In methods the
this
is always pointed to the Service instance.
Lifecycle Events
There are some lifecycle service events, that will be triggered by broker. They are placed in the root of schema.
For more information check the lifecycle events documentation.
// www.service.js |
Dependencies
If your service depends on other services, use the dependencies
property in the schema. The service waits for dependent services before calls the started
lifecycle event handler.
// posts.service.js |
The started
service handler is called once the likes
, v2.auth
, v2.users
, staging.comments
services are available (either the local or remote nodes).
Wait for services via ServiceBroker
To wait for services, you can also use the waitForServices
method of ServiceBroker
. It returns a Promise
which will be resolved, when all defined services are available & started.
Parameters
Parameter | Type | Default | Description |
---|---|---|---|
services |
String or Array |
- | Service list to waiting |
timeout |
Number |
0 |
Waiting timeout. 0 means no timeout. If reached, a MoleculerServerError will be rejected. |
interval |
Number |
1000 |
Frequency of watches in milliseconds |
Example
broker.waitForServices(["posts", "v2.users"]).then(() => { |
Set timeout & interval
broker.waitForServices("accounts", 10 * 1000, 500).then(() => { |
Metadata
The Service
schema has a metadata
property. You can store here any meta information about service. You can access it as this.metadata
inside service functions.
Core modules don’t use it. You can store in it whatever you want.
module.exports = { |
The
metadata
is also obtainable on remote nodes. It is transferred during service discovering.
Properties of Service Instances
In service functions, this
is always pointed to the Service instance. It has some properties & methods what you can use in your service functions.
Name | Type | Description |
---|---|---|
this.name |
String |
Name of service (from schema) |
this.version |
Number or String |
Version of service (from schema) |
this.fullName |
String |
Name of version prefix |
this.settings |
Object |
Settings of service (from schema) |
this.metadata |
Object |
Metadata of service (from schema) |
this.schema |
Object |
Schema definition of service |
this.broker |
ServiceBroker |
Instance of broker |
this.Promise |
Promise |
Class of Promise (Bluebird) |
this.logger |
Logger |
Logger instance |
this.actions |
Object |
Actions of service. Service can call own actions directly |
this.waitForServices |
Function |
Link to broker.waitForServices method |
this.currentContext |
Context |
Get or set the current Context object. |
Service creation
There are several ways to create and load a service.
broker.createService()
For testing, developing or prototyping, use the broker.createService
method to load & create a service by schema. It’s simplest & fastest.
broker.createService({ |
Load service from file
The recommended way is to place your service code into a single file and load it with the broker.
math.service.js
// Export the schema of service |
Load it with broker:
// Create broker |
In the service file you can also create the Service instance. In this case, you have to export a function which returns the instance of Service.
const { Service } = require("moleculer"); |
Or create a function which returns with the schema of service
// Export a function, the `loadService` will call with the ServiceBroker instance. |
Load multiple services from a folder
If you have many services (and you will have) we suggest to put them to a services
folder and load all of them with the broker.loadServices
method.
Syntax
broker.loadServices(folder = "./services", fileMask = "**/*.service.js"); |
Example
// Load every *.service.js file from the "./services" folder (including subfolders) |
Load with Moleculer Runner (recommended)
We recommend to use the Moleculer Runner to start a ServiceBroker and load services. Read more about Moleculer Runner. It is the easiest way to start a node.
Hot Reloading Services
Moleculer has a built-in hot-reloading function. During development, it can be very useful because it reloads your services when you modify it. You can enable it in broker options or in Moleculer Runner. Demo video how it works.
Enable in broker options
const broker = new ServiceBroker({ |
Enable it in Moleculer Runner
Turn it on with --hot
or -H
flags.
$ moleculer-runner --hot ./services/test.service.js |
Hot reloading function is working only with Moleculer Runner or if you load your services with
broker.loadService
orbroker.loadServices
. It doesn’t work withbroker.createService
.
Hot reload mechanism watches the service files and their dependencies. Every time a file change is detected the hot-reload mechanism will track the services that depend on it and will restart them.
Local Variables
If you would like to use local properties/variables in your service, declare them in the created
event handler.
Example for local variables
const http = require("http"); |
Naming restrictionIt is important to be aware that you can’t use variable name which is reserved for service or coincides with your method names! E.g.
this.name
,this.version
,this.settings
,this.schema
…etc.
ES6 Classes
If you prefer ES6 classes to Moleculer service schema, you can write your services in ES6 classes. There are two ways to do it.
Native ES6 classes with schema parsing
Define actions
and events
handlers as class methods and call the parseServiceSchema
method in constructor with schema definition where the handlers pointed to these class methods.
const Service = require("moleculer").Service; |
Use decorators
Thanks for @ColonelBundy, you can use ES7/TS decorators as well: moleculer-decorators
Need a compilerPlease note, you must use Typescript or Babel to compile decorators.
Example service
const { ServiceBroker } = require('moleculer'); |
Internal Services
The ServiceBroker
contains some internal services to check the node health or get some registry information. You can disable them by setting internalServices: false
in broker options.
List of nodes
It lists all known nodes (including local node).
broker.call("$node.list").then(res => console.log(res)); |
Parameters
Name | Type | Default | Description |
---|---|---|---|
withServices |
Boolean |
false |
List with services. |
onlyAvailable |
Boolean |
false |
List only available nodes. |
List of services
It lists all registered services (local & remote).
broker.call("$node.services").then(res => console.log(res)); |
Parameters
Name | Type | Default | Description |
---|---|---|---|
onlyLocal |
Boolean |
false |
List only local services. |
skipInternal |
Boolean |
false |
Skip the internal services ($node ). |
withActions |
Boolean |
false |
List with actions. |
onlyAvailable |
Boolean |
false |
List only available services. |
List of local actions
It lists all registered actions (local & remote).
broker.call("$node.actions").then(res => console.log(res)); |
It has some options which you can declare within params
.
Options
Name | Type | Default | Description |
---|---|---|---|
onlyLocal |
Boolean |
false |
List only local actions. |
skipInternal |
Boolean |
false |
Skip the internal actions ($node ). |
withEndpoints |
Boolean |
false |
List with endpoints (nodes). |
onlyAvailable |
Boolean |
false |
List only available actions. |
List of local events
It lists all event subscriptions.
broker.call("$node.events").then(res => console.log(res)); |
It has some options which you can declare within params
.
Options
Name | Type | Default | Description |
---|---|---|---|
onlyLocal |
Boolean |
false |
List only local subscriptions. |
skipInternal |
Boolean |
false |
Skip the internal event subscriptions $ . |
withEndpoints |
Boolean |
false |
List with endpoints (nodes). |
onlyAvailable |
Boolean |
false |
List only available subscriptions. |
List of metrics
It lists all metrics.
broker.call("$node.metrics").then(res => console.log(res)); |
It has some options which you can declare within params
.
Options
Name | Type | Default | Description |
---|---|---|---|
types |
String or Array |
null |
Type of metrics to include in response. |
includes |
String or Array |
null |
List of metrics to be included in response. |
excludes |
String or Array |
null |
List of metrics to be excluded from the response. |
Retrieving broker options
It returns the broker options.
broker.call("$node.options").then(res => console.log(res)); |
Health of node
It returns the health info of local node (including process & OS information).
broker.call("$node.health").then(res => console.log(res)); |
Example health info:
{ |
Please note, internal service actions are not traced.
Extending
Internal service can be easily extended with custom functionalities. To do it you must define a mixin schema in broker´s internalServices
option.
// moleculer.config.js |