Progressive microservices framework for Node.js
MIT License
Bot releases are hidden (Show)
Full Changelog: https://github.com/moleculerjs/moleculer/compare/v0.14.32...v0.14.33
Published by icebob 11 months ago
Full Changelog: https://github.com/moleculerjs/moleculer/compare/v0.14.31...v0.14.32
Published by icebob about 1 year ago
Full Changelog: https://github.com/moleculerjs/moleculer/compare/v0.14.30...v0.14.31
Published by icebob over 1 year ago
Full Changelog: https://github.com/moleculerjs/moleculer/compare/v0.14.29...v0.14.30
Published by icebob over 1 year ago
Full Changelog: https://github.com/moleculerjs/moleculer/compare/v0.14.28...v0.14.29
Published by icebob almost 2 years ago
__proto__
to Object.getProtoTypeOf
#1170
Full Changelog: https://github.com/moleculerjs/moleculer/compare/v0.14.27...v0.14.28
Published by icebob almost 2 years ago
Full Changelog: https://github.com/moleculerjs/moleculer/compare/v0.14.26...v0.14.27
Published by icebob almost 2 years ago
Full Changelog: https://github.com/moleculerjs/moleculer/compare/v0.14.25...v0.14.26
Published by icebob almost 2 years ago
Full Changelog: https://github.com/moleculerjs/moleculer/compare/v0.14.24...v0.14.25
Published by icebob about 2 years ago
Published by icebob about 2 years ago
35 commits from 11 contributors.
Published by icebob over 2 years ago
20 commits from 2 contributors.
This version contains an ESM-based Moleculer Runner. This Runner is able to load ESM configuration file and ESM services. It can load the CJS services, as well
Example usage
moleculer-runner-esm --repl services/**/*.service.mjs
Moreover, the index.js
file is wrapped into index.mjs
, so you can import internal modules from the core in ESM modules. E.g.:
import { ServiceBroker, Errors } from "moleculer";
Please note, the hot-reload function doesn't work with this ESM Runner. The cause: https://github.com/nodejs/modules/issues/307
Node maintainers try to solve the missing features (module cache and module dependency tree) with loaders but this API is not stable yet.
broker.stopping
property is created to indicate that broker is in stopping state.Published by icebob over 2 years ago
52 commits from 8 contributors.
In mixed architecture, it's not hard to create a circular service dependency that may cause a dead-lock during the start of Moleculer nodes. The problem is that Moleculer node only sends the local service registry to remote nodes after all local services started properly.
As of 0.14.20, this behavior has changed. The new logic uses a debounced registry sending method which is triggered every time a local service, that the node manages, has started()
.
Note that the new method generates more INFO packets, than early versions, during the start of the node. The number of INFO packets depends on the number of the services that the node manages. The debounce timeout, between sending INFO packets, is 1 second.
Published by icebob almost 3 years ago
69 commits from 7 contributors.
You can create a custom Regenerator
class which is able to serialize and deserialize your custom errors. It's necessary when the custom error is created on a remote node and must be serialized to be able to sent back to the caller.
Create a custom Regenerator
const { Regenerator, MoleculerError } = require("moleculer").Errors;
class TimestampedError extends MoleculerError {
constructor(message, code, type, data, timestamp) {
super(message, code, type, data);
this.timestamp = timestamp;
}
}
class CustomRegenerator extends Regenerator {
restoreCustomError(plainError, payload) {
const { name, message, code, type, data, timestamp } = plainError;
switch (name) {
case "TimestampedError":
return new TimestampedError(message, code, type, data, timestamp);
}
}
extractPlainError(err) {
return {
...super.extractPlainError(err),
timestamp: err.timestamp
};
}
}
module.exports = CustomRegenerator;
Use it in broker options
// moleculer.config.js
const CustomRegenerator = require("./custom-regenerator");
module.exports = {
errorRegenerator: new CustomRegenerator()
}
When an error occured inside ServiceBroker, it's printed to the console, but there was no option that you can process it programatically (e.g. transfer to an external monitoring service). This feature solves it. Every error inside ServiceBroker broadcasts a local (not transported) event ($transporter.error
, $broker.error
, $transit.error
, $cacher.error
, $discoverer.error
) what you can listen in your dedicated service or in a middleware.
Example to listen in an error-tracker service
module.exports = {
name: "error-tracker",
events: {
"$**.error": {
handler(ctx) {
// Send the error to the tracker
this.sendError(ctx.params.error);
}
}
}
}
Example to listen in a middleware or in broker options
module.exports = {
created(broker) {
broker.localBus.on("*.error", payload => {
// Send the error to the tracker
this.sendError(payload.error);
});
}
}
You can use *
wildcard in action names when you use it in Action Hooks.
Example
hooks: {
before: {
// Applies to all actions that start with "create-"
"create-*": [],
// Applies to all actions that end with "-user"
"*-user": [],
}
}
Published by icebob about 3 years ago
61 commits from 10 contributors.
heartbeatTimeout
option in BaseDiscoverer. #985
keygen
option action definition. #1004
Published by icebob over 3 years ago
15 commits from 5 contributors.
Published by icebob over 3 years ago
105 commits from 11 contributors.
CBOR (cbor-x) is a new serializer but faster than any other serializers.
Example
// moleculer.config.js
module.exports = {
logger: true,
serializer: "CBOR"
};
Benchmark
Suite: Serialize packet with 10bytes
√ JSON 509,217 rps
√ Avro 308,711 rps
√ MsgPack 79,932 rps
√ ProtoBuf 435,183 rps
√ Thrift 93,324 rps
√ Notepack 530,121 rps
√ CBOR 1,016,135 rps
JSON (#) 0% (509,217 rps) (avg: 1μs)
Avro -39.38% (308,711 rps) (avg: 3μs)
MsgPack -84.3% (79,932 rps) (avg: 12μs)
ProtoBuf -14.54% (435,183 rps) (avg: 2μs)
Thrift -81.67% (93,324 rps) (avg: 10μs)
Notepack +4.11% (530,121 rps) (avg: 1μs)
CBOR +99.55% (1,016,135 rps) (avg: 984ns)
settled
option in broker.mcall
The broker.mcall
method has a new settled
option to receive all Promise results. Without this option, if you make a multi-call and one call is rejected, the response will be a rejected Promise
and you don't know how many (and which) calls were rejected.
If settled: true
, the method returns a resolved Promise
in any case and the response contains the statuses and responses of all calls.
Example
const res = await broker.mcall([
{ action: "posts.find", params: { limit: 2, offset: 0 },
{ action: "users.find", params: { limit: 2, sort: "username" } },
{ action: "service.notfound", params: { notfound: 1 } }
], { settled: true });
console.log(res);
The res
will be something similar to
[
{ status: "fulfilled", value: [/*... response of `posts.find`...*/] },
{ status: "fulfilled", value: [/*... response of `users.find`...*/] },
{ status: "rejected", reason: {/*... Rejected response/Error`...*/} }
]
MOLECULER_CONFIG
environment variable in RunnerIn the Moleculer Runner, you can configure the configuration filename and path with the MOLECULER_CONFIG
environment variable. It means, no need to specify the config file with --config
argument.
[email protected]
in NATS transporterThe new nats 2.x.x
version has a new breaking API which has locked the NATS transporter for [email protected]
library. As of this release, the NATS transporter supports both major versions of the nats
library.
The transporter automatically detects the version of the library and uses the correct API.
ctx
as metadataSince [email protected]
, the FastestValidator supports async custom validators and you can pass metadata for custom validator functions.
In Moleculer, the FastestValidator
passes the ctx
as metadata. It means you can access to the current context, service, broker and you can make async calls (e.g calling another service) in custom checker functions.
Example
// posts.service.js
module.exports = {
name: "posts",
actions: {
params: {
$$async: true,
owner: { type: "string", custom: async (value, errors, schema, name, parent, context) => {
const ctx = context.meta;
const res = await ctx.call("users.isValid", { id: value });
if (res !== true)
errors.push({ type: "invalidOwner", field: "owner", actual: value });
return value;
} },
},
/* ... */
}
}
Utils
in typescript definition. #909