Skip to content

Releases: moleculerjs/moleculer

v0.14.0-beta7

09 Jan 20:06
Compare
Choose a tag to compare
v0.14.0-beta7 Pre-release
Pre-release

Minimum Node version is 10

The Node version 8 LTS lifecycle has been ended on December 31, 2019, so the minimum required Node version is 10.

Event parameter validation

Similar to action parameter validation, the event parameter validation is supported.
Like in action definition, you should define params in even definition and the built-in Validator validates the parameters in events.

// mailer.service.js
module.exports = {
    name: "mailer",
    events: {
        "send.mail": {
            // Validation schema
            params: {
                from: "string|optional",
                to: "email",
                subject: "string"
            },
            handler(ctx) {
                this.logger.info("Event received, parameters OK!", ctx.params);
            }
        }
    }
};

The validation errors are not sent back to the caller, they are logged or you can catch them with the new global error handler.

Other fixes

v0.13.12

17 Dec 20:07
Compare
Choose a tag to compare

Changes

  • fix expire time updating issue in MemoryCacher. #630
  • fix action hook calling issue in mixins. #631
  • fix NATS transporter "Invalid Subject" issue. #620
  • update dependencies.

v0.14.0-beta6

19 Nov 22:03
Compare
Choose a tag to compare
v0.14.0-beta6 Pre-release
Pre-release

Fastest validator upgraded to 1.x.x

fastest-validator, the default validation has been upgraded to the 1.0.0 version. It means breaking changes but the new version faster and contains many sanitization functions.
If you use custom rules, you should upgrade your codes. Check the changes here.

Problematic metrics dependencies removed

The gc-stats and event-loop-stats optional dependencies removed and moved to devDependencies. If you want to use them, you should install manually.

v0.14.0-beta5

08 Feb 09:25
Compare
Choose a tag to compare
v0.14.0-beta5 Pre-release
Pre-release

Changes

  • Fixed #576, #593, #598, #599
  • Added rating to metrics
  • Added Throttle & Debounce middlewares
  • Added tracking support for events.

v0.13.11

01 Oct 18:02
Compare
Choose a tag to compare

Changes

  • fix retry issue in case of remote calls & disabled preferLocal options. #599
  • update dependencies.

v0.14.0-beta4

08 Feb 09:22
Compare
Choose a tag to compare
v0.14.0-beta4 Pre-release
Pre-release

Logger settings changed

The whole logging function has been rewritten in this version. It means, it has a lot of new features, but the configuration of loggers has contains breaking changes. You can't use some old custom logger configuration form. The new configuration same as the other Moleculer module configurations. This new version supports all famous loggers like Pino, Winston, Bunyan, Debug & Log4js.

If you are using the built-in default console logger, this breaking change doesn't affect you.

The logFormatter and logObjectPrinter broker options has been removed and moved into the Console and File logger options.

Not changed usable configurations

// moleculer.config.js
module.exports = {
    // Enable console logger
    logger: true,

    // Disable all loggers
    logger: false
};

You CANNOT use these legacy configurations

// moleculer.config.js
module.exports = {
    // DON'T use a custom create function, like
    logger: bindings => pino.child(bindings),

    // DON'T use a custom logger, like
    logger: {
        error: () => { ... },
        warn: () => { ... },
        info: () => { ... },
        debug: () => { ... }
    }
};

Console logger

This logger prints all log messags to the console. It supports several built-in formatters or you can use your custom formatter, as well.

Shorthand configuration with default options

// moleculer.config.js
module.exports = {
    logger: "Console",
};

Full configuration

// moleculer.config.js
module.exports = {
    logger: {
        type: "Console",
        options: {
            // Logging level
            level: "info",
            // Using colors on the output
            colors: true,
            // Print module names with different colors (like docker-compose for containers)
            moduleColors: false,
            // Line formatter. It can be "json", "short", "simple", "full", a `Function` or a template string like "{timestamp} {level} {nodeID}/{mod}: {msg}"
            formatter: "full",
            // Custom object printer. If not defined, it uses the `util.inspect` method.
            objectPrinter: null,
            // Auto-padding the module name in order to messages begin at the same column.
            autoPadding: false
        }
    }
};

File logger

This logger saves all log messages to file(s). It supports JSON & formatted text files or you can use your custom formatter, as well.

Shorthand configuration with default options

// moleculer.config.js
module.exports = {
    logger: "File",
};

It will save the log messages to the logs folder in the current directory with moleculer-{date}.log filename.

Full configuration

// moleculer.config.js
module.exports = {
    logger: {
        type: "File",
        options: {
            // Logging level
            level: "info",
            // Folder path to save files. You can use {nodeID} & {namespace} variables.
            folder: "./logs",
            // Filename template. You can use {date}, {nodeID} & {namespace} variables.
            filename: "moleculer-{date}.log",
            // Line formatter. It can be "json", "short", "simple", "full", a `Function` or a template string like "{timestamp} {level} {nodeID}/{mod}: {msg}"
            formatter: "json",
            // Custom object printer. If not defined, it uses the `util.inspect` method.
            objectPrinter: null,
            // End of line. Default values comes from the OS settings.
            eol: "\n",
            // File appending interval in milliseconds.
            interval: 1 * 1000
        }
    }
};

Pino logger

This logger uses the Pino logger.

Shorthand configuration with default options

// moleculer.config.js
module.exports = {
    logger: "Pino",
};

Full configuration

// moleculer.config.js
module.exports = {
    logger: {
        type: "Pino",
        options: {
            // Logging level
            level: "info",

            pino: {
                // More info: http://getpino.io/#/docs/api?id=options-object
                options: null,

                // More info: http://getpino.io/#/docs/api?id=destination-sonicboom-writablestream-string
                destination: "/logs/moleculer.log",
            }
        }
    }
};

To use this logger please install the pino module with npm install pino --save command.

Bunyan logger

This logger uses the Bunyan logger.

Shorthand configuration with default options

// moleculer.config.js
module.exports = {
    logger: "Bunyan",
};

Full configuration

// moleculer.config.js
module.exports = {
    logger: {
        type: "Bunyan",
        options: {
            // Logging level
            level: "info",

            bunyan: {
                // More settings: https://github.com/trentm/node-bunyan#constructor-api
                name: "moleculer"
            }
        }
    }
};

To use this logger please install the bunyan module with npm install bunyan --save command.

Winston logger

This logger uses the Winston logger.

Shorthand configuration with default options

// moleculer.config.js
module.exports = {
    logger: "Winston",
};

Full configuration

// moleculer.config.js
const winston = require("winston");

module.exports = {
    logger: {
        type: "Winston",
        options: {
            // Logging level
            level: "info",

            winston: {
                // More settings: https://github.com/winstonjs/winston#creating-your-own-logger
                transports: [
                    new winston.transports.Console(),
                    new winston.transports.File({ filename: "/logs/moleculer.log" })
                ]
            }
        }
    }
};

To use this logger please install the winston module with npm install winston --save command.

debug logger

This logger uses the debug logger.
To see messages you have to set the DEBUG environment variable to export DEBUG=moleculer:*.

Shorthand configuration with default options

// moleculer.config.js
module.exports = {
    logger: "Debug",
};

Full configuration

// moleculer.config.js
module.exports = {
    logger: {
        type: "Debug",
        options: {
            // Logging level
            level: "info",
        }
    }
};

To use this logger please install the debug module with npm install debug --save command.

Log4js logger

This logger uses the Log4js logger.

Shorthand configuration with default options

// moleculer.config.js
module.exports = {
    logger: "Log4js",
};

Full configuration

// moleculer.config.js
module.exports = {
    logger: {
        type: "Log4js",
        options: {
            // Logging level
            level: "info",
            
            log4js: {
                // More info: https://github.com/log4js-node/log4js-node#usage
                appenders: {
                    app: { type: "file", filename: "/logs/moleculer.log" }
                },
                categories: {
                    default: { appenders: [ "app" ], level: "debug" }
                }
            }
        }
    }
};

To use this logger please install the log4js module with npm install log4js --save command.

Datadog logger

This logger uploads log messages to the Datadog server.

Please note, this logger doesn't print any messages to the console, just collects & uploads. Use it beside another logger which also prints the messages.

Shorthand configuration with default options

// moleculer.config.js
module.exports = {
    logger: "Datadog",
};

Full configuration

// moleculer.config.js
module.exports = {
    logger: {
        type: "Datadog",
        options: {
            // Logging level
            level: "info",

            // Datadog server endpoint. https://docs.datadoghq.com/api/?lang=bash#send-logs-over-http
            url: "https://http-intake.logs.datadoghq.com/v1/input/",
            // Datadog API key
            apiKey: process.env.DATADOG_API_KEY,
            // Datadog source variable
            ddSource: "moleculer",
            // Datadog env variable
            env: undefined,
            // Datadog hostname variable
            hostname: os.hostname(),
            // Custom object printer function for `Object` & `Ąrray`
            objectPrinter: null,
            // Data uploading interval
            interval: 10 * 1000
        }
    }
};

Multiple loggers

This new logger configuration admits to use multiple loggers even from the same logger type and different logging levels.

Define multiple loggers with different logging levels

This configuration demonstrates how you can define a Console logger, a File logger to save all log messages in formatted text file and another File logger to save only error messages in JSON format.

// moleculer.config.js
module.exports = {
    logger: [
        {
            type: "Console",
            options: {
                level: "info",
            }
        },
        {            
          ...
Read more

v0.13.10

26 Aug 19:31
Compare
Choose a tag to compare

New

Customizable serializer for Redis cacher by @shawnmcknight #589

The default serializer is the JSON Serializer but you can change it in Redis cacher options.

You can use any built-in Moleculer serializer or use a custom one.

Example to set the built-in MessagePack serializer:

const broker = new ServiceBroker({
    nodeID: "node-123",
    cacher: {
        type: "Redis",
        options: {
            ttl: 30,

            // Using MessagePack serializer to store data.
            serializer: "MsgPack",

            redis: {
                host: "my-redis"
            }
        }
    }
});

Cluster mode of Redis cacher by Gadi-Manor #539

Redis cacher supports cluster mode.

Example

const broker = new ServiceBroker({
    cacher: {
        type: "Redis",
        options: {
            ttl: 30, 

            cluster: {
                nodes: [
                    { port: 6380, host: "127.0.0.1" },
                    { port: 6381, host: "127.0.0.1" },
                    { port: 6382, host: "127.0.0.1" }
                ],
                options: { /* More information: https://github.com/luin/ioredis#cluster */ }
            }	
        }
    }
});

Changes

  • update dependencies.
  • update Typescript definitions by @shawnmcknight.
  • fix Protocol Buffer definitions by @fugufish.

v0.14.0-beta3

08 Feb 09:27
Compare
Choose a tag to compare
v0.14.0-beta3 Pre-release
Pre-release

Changes

  • added ctx.locals
  • update dependencies
  • Fixed #570

v0.14.0-beta1

02 Jul 18:10
Compare
Choose a tag to compare
v0.14.0-beta1 Pre-release
Pre-release

Migration guide from 0.13 to 0.14

Breaking changes

Communication protocol has been changed

The Moleculer communication protocol has been changed. The new protocol version is 4.
It means the new Moleculer 0.14 nodes can't communicate with old <= 0.13 nodes.

Validation settings changed

The validation: true broker options was removed to follow other module configuration. Use validator option, instead.

Enable validation with built-in validator (default option)

const broker = new ServiceBroker({
    validator: true
});

Disable validation/validator

const broker = new ServiceBroker({
    validator: false
});

Use custom validation

const broker = new ServiceBroker({
    validator: new MyCustomValidator()
});

The broker.use removed

The broker.use has been deprecated in version 0.13 and now it is removed. Use middleware: [] broker options to define middlewares.

loading middleware after the broker has started is no longer available.

The $node.health response changed

The $node.health action's response has been changed. The transit property is removed. To get transit metrics, use the new $node.metrics internal action.

Middleware shorthand definition is dropped

In previous versions you could define middleware which wraps the localAction hook with a simple Function.
In version 0.14 this legacy shorthand is dropped. When you define a middleware as a Function, the middleware handler will call it as an initialization and pass the ServiceBroker instance as a parameter.

Old shorthand middleware definition as a Function

const MyMiddleware = function(next, action) {
    return ctx => next(ctx);
};

const broker = new ServiceBroker({
    middlewares: [MyMiddleware]
});

New middleware definition as a Function

const MyMiddleware = function(broker) {
    // Create a custom named logger
    const myLogger = broker.getLogger("MY-LOGGER");

    return {
        localAction: function(next, action) {
            return ctx => {
                myLogger.info(`${action.name} has been called`);
                return next(ctx);
            }
        }
    }
};

const broker = new ServiceBroker({
    middlewares: [MyMiddleware]
});

The localEvent middleware hook signature changed

Old signature

// my-middleware.js
module.exports = {
    // Wrap local event handlers
    localEvent(next, event) {
        return (payload, sender, event) => {
            return next(payload, sender, event);
        };
    },
};

New context-based signature

// my-middleware.js
module.exports = {
    // Wrap local event handlers
    localEvent(next, event) {
        return (ctx) => {
            return next(ctx);
        };
    },
};

New

Context-based events

The new 0.14 version comes context-based event handler. It is very useful when you are using event-driven architecture and you would like to tracing the event. The Event Context is same as Action Context. They are the same properties except a few new properties related to the event.
It doesn't mean you should rewrite all existing event handlers. Moleculer detects the signature if your event handler. If it finds that the signature is "user.created(ctx) { ... }, it will call it with Event Context. If not, it will call with old arguments & the 4th argument will be the Event Context, like "user.created"(payload, sender, eventName, ctx) {...}

Use Context-based event handler & emit a nested event

module.exports = {
    name: "accounts",
    events: {
        "user.created"(ctx) {
            console.log("Payload:", ctx.params);
            console.log("Sender:", ctx.nodeID);
            console.log("We have also metadata:", ctx.meta);
            console.log("The called event name:", ctx.eventName);

            ctx.emit("accounts.created", { user: ctx.params.user });
        }
    }
};

New built-in metrics

Moleculer v0.14 comes with a brand-new and entirely rewritten metrics module. It is now a built-in module. It collects a lot of internal Moleculer & process metric values. You can easily define your custom metrics. There are several built-in metrics reporters like Console, Prometheus, Datadog, ...etc.
Multiple reporters can be defined.

Enable metrics & define console reporter

const broker = new ServiceBroker({
    metrics: {
        enabled: true,
        reporter: [
            "Console"
        ]
    }
});

Define custom metrics

// posts.service.js
module.exports = {
    name: "posts",

    actions: {
        get(ctx) {
            // Update metrics
            this.broker.metrics.increment("posts.get.total");
            return posts;
        }
    },

    created() {
        // Register new custom metrics
        this.broker.metrics.register({ type: "counter", name: "posts.get.total" });
    }
};

Enable metrics & define Prometheus reporter with filtering

const broker = new ServiceBroker({
    metrics: {
        enabled: true,
        reporter: [
            {
                type: "Prometheus",
                options: {
                    port: 3030,
                    includes: ["moleculer.**"],
                    excludes: ["moleculer.transit.**"]
                }
            }
        ]
    }
});

Supported metric types

  • counter - A counter is a cumulative metric that represents a single monotonically increasing counter whose value can only increase or be reset to zero. For example, you can use a counter to represent the number of requests served, tasks completed, or errors.

  • gauge - A gauge is a metric that represents a single numerical value that can arbitrarily go up and down. Gauges are typically used for measured values like current memory usage, but also "counts" that can go up and down, like the number of concurrent requests.

  • histogram - A histogram samples observations (usually things like request durations or response sizes) and counts them in configurable buckets. It also provides a sum of all observed values and calculates configurable quantiles over a sliding time window.

  • info - An info is a single string or number value like process arguments, hostname or version numbers.

Internal metrics

Process metrics

  • process.arguments (info)
  • process.pid (info)
  • process.ppid (info)
  • process.eventloop.lag.min (gauge)
  • process.eventloop.lag.avg (gauge)
  • process.eventloop.lag.max (gauge)
  • process.eventloop.lag.count (gauge)
  • process.memory.heap.size.total (gauge)
  • process.memory.heap.size.used (gauge)
  • process.memory.rss (gauge)
  • process.memory.external (gauge)
  • process.memory.heap.space.size.total (gauge)
  • process.memory.heap.space.size.used (gauge)
  • process.memory.heap.space.size.available (gauge)
  • process.memory.heap.space.size.physical (gauge)
  • process.memory.heap.stat.heap.size.total (gauge)
  • process.memory.heap.stat.executable.size.total (gauge)
  • process.memory.heap.stat.physical.size.total (gauge)
  • process.memory.heap.stat.available.size.total (gauge)
  • process.memory.heap.stat.used.heap.size (gauge)
  • process.memory.heap.stat.heap.size.limit (gauge)
  • process.memory.heap.stat.mallocated.memory (gauge)
  • process.memory.heap.stat.peak.mallocated.memory (gauge)
  • process.memory.heap.stat.zap.garbage (gauge)
  • process.uptime (gauge)
  • process.internal.active.handles (gauge)
  • process.internal.active.requests (gauge)
  • process.versions.node (info)
  • process.gc.time (gauge)
  • process.gc.total.time (gauge)
  • process.gc.executed.total (gauge)

OS metrics

  • os.memory.free (gauge)
  • os.memory.total (gauge)
  • os.uptime (gauge)
  • os.type (info)
  • os.release (info)
  • os.hostname (info)
  • os.arch (info)
  • os.platform (info)
  • os.user.uid (info)
  • os.user.gid (info)
  • os.user.username (info)
  • os.user.homedir (info)
  • os.network.address (info)
  • os.network.mac (info)
  • os.datetime.unix (gauge)
  • os.datetime.iso (info)
  • os.datetime.utc (info)
  • os.datetime.tz.offset (gauge)
  • os.cpu.load.1 (gauge)
  • os.cpu.load.5 (gauge)
  • os.cpu.load.15 (gauge)
  • os.cpu.utilization (gauge)
  • os.cpu.user (gauge)
  • os.cpu.system (gauge)
  • os.cpu.total (gauge)
  • os.cpu.info.model (info)
  • os.cpu.info.speed (gauge)
  • os.cpu.info.times.user (gauge)
  • os.cpu.info.times.sys (gauge)

Moleculer metrics

  • moleculer.node.type (info)
  • moleculer.node.versions.moleculer (info)
  • moleculer.node.versions.protocol (info)
  • moleculer.broker.namespace (info)
  • moleculer.broker.started (gauge)
  • moleculer.broker.local.services.total (gauge)
  • moleculer.broker.middlewares.total (gauge)
  • moleculer.registry.nodes.total (gauge)
  • moleculer.registry.nodes.online.total (gauge)
  • moleculer.registry.services.total (gauge)
  • moleculer.registry.service.endpoints.total (gauge)
  • moleculer.registry.actions.total (gauge)
  • moleculer.registry.action.endpoints.total (gauge)
  • moleculer.registry.events.total (gauge)
  • moleculer.registry.event.endpoints.total (gauge)
  • moleculer.request.bulkhead.inflight (gauge)
  • moleculer.request.timeout.total (counter)
  • moleculer.request.retry.attempts.total (counter)
  • moleculer.request.fallback.total (counter)
  • moleculer.request.total (counter)
  • moleculer.request.active (gauge)
  • moleculer.request.error.total (counter)
  • moleculer.request.time (histogram)
  • moleculer.request.levels (counter)
  • moleculer.event.emit.total (counter)
  • moleculer.event.broadcast.total (counter)
  • `mol...
Read more

v0.13.9

18 Apr 18:30
Compare
Choose a tag to compare

New

Cache locking feature by @tiaod #490

Example to enable cacher locking:

cacher: {
  ttl: 60,
  lock: true, // Set to true to enable cache locks. Default is disabled.
}

//  Or
cacher: {
  ttl: 60,
  lock: {
    ttl: 15, //the maximum amount of time you want the resource locked in seconds
    staleTime: 10, // If the ttl is less than this number, means that the resources are staled
  }
}

// Disable the lock
cacher: {
  ttl: 60,
  lock: {
    enable: false, // Set to false to disable.
    ttl: 15, //the maximum amount of time you want the resource locked in seconds
    staleTime: 10, // If the ttl is less than this number, means that the resources are staled
  }
}

Example for Redis cacher with redlock library:

const broker = new ServiceBroker({
  cacher: {
    type: "Redis",
    options: {
      // Prefix for keys
      prefix: "MOL",
      // set Time-to-live to 30sec.
      ttl: 30,
      // Turns Redis client monitoring on.
      monitor: false,
      // Redis settings
      redis: {
        host: "redis-server",
        port: 6379,
        password: "1234",
        db: 0
      },
      lock: {
        ttl: 15, //the maximum amount of time you want the resource locked in seconds
        staleTime: 10, // If the ttl is less than this number, means that the resources are staled
      },
      // Redlock settings
      redlock: {
        // Redis clients. Support node-redis or ioredis. By default will use the local client.
        clients: [client1, client2, client3],
        // the expected clock drift; for more details
        // see http://redis.io/topics/distlock
        driftFactor: 0.01, // time in ms

        // the max number of times Redlock will attempt
        // to lock a resource before erroring
        retryCount: 10,

        // the time in ms between attempts
        retryDelay: 200, // time in ms

        // the max time in ms randomly added to retries
        // to improve performance under high contention
        // see https://www.awsarchitectureblog.com/2015/03/backoff.html
        retryJitter: 200 // time in ms
      }
    }
  }
});

Changes

  • fix event wildcard handling in case of NATS transporter and disabled balancer #517
  • update typescript d.ts file. #501 #521
  • fix context calling options cloning.
  • service modification support for ES6 classes #514
  • fix null, 0 & false return value issue in case of ProtoBuf serializer #511