github moleculerjs/moleculer v0.8.0

latest releases: v0.15.0-beta1, v0.14.33, v0.14.32...
7 years ago

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.

Read more about runner

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

image

List services

mol $ services

List actions

mol $ actions

image

Show common informations

mol $ info

image

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" nodeID
  • targetNodeID: 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 the actions property to services and now it contains all services with actions of node
  • splitted broker.registerService to registerLocalService and registerRemoteService
  • new broker.unregisterServicesByNode. It will be called when a node disconnected

Don't miss a new moleculer release

NewReleases is sending notifications on new releases.