github moleculerjs/moleculer v0.15.0-beta1

pre-release13 days ago

Migration guide from 0.14 to 0.15

Breaking changes

Minimum Node 18

The minimum supported Node version is changed from Node 10 to Node 18.

Communication protocol has been changed

The Moleculer communication protocol has been changed. The new protocol version is 5. However all schema-based serializer has been removed from the core repo. It means v0.15 Moleculer nodes will able to communicate with v0.14 nodes, if you disable version checking in broker options.

Schema-based serializers (ProtoBuf, Avro, Thrift) are removed

The reason is desribed in this issue: #882

If you use one of those, you should change it to one of these schemaless serializers: MsgPack, Notepack.io, JSON, JSONExt, CBOR

EventLegacy tracing export is removed

The EventLegacy tracing exporter is removed. Use the Event tracing exporter instead.

Legacy event handler is removed

The legacy event handler signature (user.created(payload, sender, eventName)) is removed. You should use the new Context based signature which was introduced in version 0.14.

Legacy event handler

module.exports = {
    name: "accounts",
    events: {
        "user.created"(payload, sender, eventName) {
            // ...
        }
    }
};

Supported event handler

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);

            // ...
        }
    }
};

New REPL options

In order to the REPL options can be more extensible, a new replOptions broker option is introduces. You can use it instead of the old replCommands and replDelimiter broker options.

Old REPL options

// moleculer.config.js
module.exports = {
    replDelimiter: "mol # ",
    replCommands: [
        {
            command: "hello <name>",			
            action(broker, args) {
                // ...
            }
        }
    ]
}

New REPL options

// moleculer.config.js
module.exports = {
    replOptions: {
        delimiter: "mol # ",
        customCommands: [
            {
                command: "hello <name>",			
                action(broker, args) {
                    // ...
                }
            }
        ]
    }
}

Please note, you should rename the replCommands property to customCommands, as well.

Action streaming

The built-in Stream sending has been rewritten. Now it accepts params besides the Stream instance.
The Stream parameter moved from ctx.params into calling options under a stream property.

New way to send a stream with extra parameters

The stream instance is passed as a calling options, so you can use ctx.params as a normal action call.

ctx.call("file.save", { filename: "as.txt" }, { stream: fs.createReadStream() });

New way to receive a stream

// file.service.js
module.exports = {
    name: "file",
    actions: {
        save(ctx) {
            // The stream is in Context directly
            const stream = ctx.stream;
            const s = fs.createWriteStream(ctx.params.filename);
            stream.pipe(s);
        }
    }
};

Removed deprecated functions and signatures

Removed deprecated broker.createService signature

The broker.createService second argument (for service schema extending) is removed. You should use the mixins in service schema.

Removed deprecated event sending method signature

In previous versions, the emit, broadcast and broadcastLocal methods accept a group String or groups as Array<String> as third arguments, instead of an opts.
This signature is removed, you should always pass an opts object as 3rd argument.

Removed deprecated middleware as a Function

We removed and old and deprecated middleware signature where the middleware was localAction function. Now ServiceBroker accepts middleware as Object only.

Removed deprecated getLocalService signature.

The broker.getLocalService supports only getLocalService(name|obj) without second version parameter. If you want to get a versioned service, use the v1.posts argument or as object { name: "posts", version: 1}

Removed Service constructor 3rd argument.

The Service constructor had a 3rd argument as schemaMods which was deprecated because you should use mixins instead modifier schemas.

Garbage collector and event-loop metrics removed

Since gc-stats and event-loop-stats native libraries are not maintained and they are not compatible with newer Node versions, they are removed from the built-in metrics.

Removed metrics:

  • process.gc.time
  • process.gc.total.time
  • process.gc.executed.total
  • process.eventloop.lag.min
  • process.eventloop.lag.avg
  • process.eventloop.lag.max
  • process.eventloop.lag.count
  • process.internal.active.requests

Removed STAN (NATS Streaming) transporter

The STAN (NATS Streaming) transporter has been removed while it's deprecated and not supported by the NATS.io, as well. More info: https://nats-io.gitbook.io/legacy-nats-docs/nats-streaming-server-aka-stan

Rewritten Kafka transporter (based on kafkajs)

The previous kafka-node based transporter has been rewritten to a kafkajs based transporter. It means, you should migrate your Kafka Transporter options.

// moleculer.config.js
module.exports = {
    transporter: {
        type: "Kafka",
        options: {
            // KafkaClient options. More info: https://kafka.js.org/docs/configuration
            client: {
                brokers: [/*...*/]
            },

            // KafkaProducer options. More info: https://kafka.js.org/docs/producing#options
            producer: {},

            // ConsumerGroup options. More info: https://kafka.js.org/docs/consuming#a-name-options-a-options
            consumer: {},

            // Advanced options for `send`. More info: https://kafka.js.org/docs/producing#producing-messages
            publish: {},

            // Advanced message options for `send`. More info: https://kafka.js.org/docs/producing#message-structure
            publishMessage: {
                partition: 0
            }
        }
    }
}

About new configuration options, check this documentation: https://kafka.js.org/docs/configuration

Removed legacy NATS library (nats@1.x.x) implementation

The legacy nats@1.x.x transporter implementation is removed. This version supports only nats@2.x.x library.

The Fastest Validator options changed.

In 0.15 the useNewCustomCheckFunction default value is changed from false to true. It means, if you have old custom checker function in your parameter validation schemas, you should rewrite it to the new custom check function form.

You can see example about migration here: https://github.com/icebob/fastest-validator/blob/master/CHANGELOG.md#new-custom-function-signature

Rewritten Typescript definition files

The previously used huge one-file index.d.ts file has been rewritten and separated to multiple d.ts files, all are placed besides the source file. It may causes breaking changes in Typescript projects.

Other breaking changes

  • ServiceBroker.Promise is removed. Use broker.Promise or this.Promise inside a Service.

New features

New JSON Extended serializer

We implemented a new JSON serializer which unlike the native JSON serializer, it supports serializing Buffer, BigInt, Date, Map, Set and RegExp classes, as well.

Example

// moleculer.config.js
module.exports = {
    serializer: "JSONExt"
}

Custom extensions

You can extend the serializer with custom types.

Example to extend with a custom class serializing/deserializing

// MyClass.js
class MyClass {
    constructor(a, b) {
        this.a = a;
        this.b = b;
    }
}
// moleculer.config.js
module.exports = {
    serializer: {
        type: "JSONExt",
        options: {
            customs: [
                {
                    // This is the identifier of the custom type
                    prefix: "AB",
                    
                    // This function checks the type of JSON value
                    check: v => v instanceof MyClass,
                    
                    // Serialize the custom class properties to a String
                    serialize: v => v.a + "|" + v.b,

                    // Deserialize the JSON string to custom class instance and set properties
                    deserialize: v => {
                        const [a, b] = v.split("|");
                        return new MyClass(parseInt(a), b);
                    }
                }
            ]
        }
    }
}

New Request headers

We added a new headers property in calling options and Context class to store meta information for an action calling or an event emitting.

The difference between headers and meta is that the meta is always passed to all action calls in a chain and merged, the headers is transferred only to the actual action call and not passed to the nested calls.

Please note, header keys start with $ means internal header keys (e.g. $streamObjectMode). We recommend to don't use this prefix for your keys to avoid conflicts.

Set headers in action calls

broker.call("posts.list", { limit: 100 }, {
    headers: {
        customProp: "customValue"
    }
});

You can use the same way for event emitting or broadcasting.

Read headers inside action handler

// posts.service.js
module.exports = {
    name: "posts",
    actions: {
        list(ctx) {
            const customProp = ctx.headers.customProp;
        }
    }
};

You can use the same way in event handlers.

Use header value in cache keys

You can add headers values to the cache keys as well. For this, use @ prefix

// posts.service.js
module.exports = {
    name: "posts",
    actions: {
        list: {
            cache: {
                keys: [
                    "limit",        // value from `ctx.params`
                    "#tenant",      // value from `ctx.meta`
                    "@customProp"   // value from `ctx.headers`
                ]
            }
            handler(ctx) {
                const customProp = ctx.headers.customProp;
            }
        }
    }
};

Response headers

The Moleculer protocol supports headers in response, as well (ctx.responseHeaders). But in normal way, you can't access to them in your services because you don't have pointer to the returned Context instance. So at present, it can be used by middlewares only.

Other changes

Better error handling in event handlers.

!TODO!

Cacher changes

The getCacheKey and opts.keygen signature has been changed

Old signature: getCacheKey(actionName, params, meta, keys, actionKeygen)

New signature: getCacheKey(action, opts, ctx)

Added missingResponse option to cacher options

In 0.14, you could not make a difference between the result cached value is null or it's not in the cache. Because both way, the cacher.get responded with null.

In 0.15, if a cache key is not found in cache, it returns undefined by default, or you can change it with missingResponse option.

Example: using a custom symbol to detect missing entries

const missingSymbol = Symbol("MISSING");

// moleculer.config.js
module.exports = {
    cacher: {
        type: "Memory",
        options: {
            missingResponse: missingSymbol
        }
    }
}

// Get data from cache

const res = await cacher.get("not-existing-key");
if (res === cacher.opts.missingSymbol) {
    console.log("It's not cached.");
}

Cache key generation changed

There are some changes in the serialized values in the cache keys. In previous versions, the null and undefined values were serialized as null, and "null" as string also serialized to null.
In 0.15, string values are wrapped into quotes, the null is null and undefined is serialized as undefined, so similar serialized values.

These changes means the 0.15 cachers create different cache keys than 0.14 cachers.

Full Changelog: v0.14.33...v0.15.0-beta1

Don't miss a new moleculer release

NewReleases is sending notifications on new releases.