This documentation leads you how you can migrate your project to be compatible with the Moleculer v0.13.x versions.
Please note! The previous version of
moleculer-web
doesn't work with Moleculer 0.13. You need to upgrade it to 0.8.x version too.
If you are using Moleculer Runner with
moleculer.config.js
, skip this part.
The ServiceBroker & Service lifecycle handler logic has been changed.
It works in the previous version
const { ServiceBroker } = require("moleculer");
const broker = new ServiceBroker();
broker.loadService("./math.service.js");
broker.call("math.add", { a: 5, b: 3 }).then(res => console.log);
// Prints: 8
Since v0.13 it will throw a ServiceNotFoundError
exception because the service is only loaded but not started yet.
Correct logic
const { ServiceBroker } = require("moleculer");
const broker = new ServiceBroker();
broker.loadService("./math.service.js");
broker.start().then(() => {
broker.call("math.add", { a: 5, b: 3 }).then(res => console.log);
// Prints: 8
});
It can cause problems in your tests as well. Make sure you use broker.start()
and broker.stop()
in all test cases.
Good test case
describe("Test 'posts.find' action", () => {
let broker = new ServiceBroker({ logger: false });
let actionHandler = jest.fn(ctx => ctx);
broker.createService({
name: "posts",
actions: {
find: actionHandler
}
});
/* The important part! */
beforeAll(() => broker.start());
afterAll(() => broker.stop());
it("should call action handler", () => {
return broker.call("posts.find", { id: 5 }).then(ctx => {
expect(ctx.params).toEqual({ id: 5 });
expect(actionHandler).toHaveBeenCalledTimes(1);
expect(actionHandler).toHaveBeenCalledWith(ctx);
});
});
});
No more need to set logger: console
in broker options because ServiceBroker uses console
as default logger.
Side effect: broker instances in your tests will print log messages.
To disable logging (default behavior in previous version) set logger: false
in broker options.
Disable loggging
const broker = new ServiceBroker({ logger: false });
If you use $
prefixed custom events in your project, be careful because now these events will be transferred to remote nodes too if you emit them with broker.emit
or broker.broadcast
methods. To previous behavior emit them with broker.broadcastLocal
method.
By the way, we don't recommend to use $
custom events because the prefix is reserved for core modules & features.
Old options
const broker = new ServiceBroker({
circuitBreaker: {
enabled: true,
maxFailures: 5,
halfOpenTime: 10 * 1000,
failureOnTimeout: true,
failureOnReject: true
}
});
New options
const broker = new ServiceBroker({
nodeID: "node-1",
circuitBreaker: {
enabled: true,
threshold: 0.5,
minRequestCount: 20,
windowTime: 60, // in seconds
halfOpenTime: 5 * 1000,
check: err => err && err.code >= 500
}
});
Steps:
- Change
maxFailures
(count) tothreshold
(percent from 0.0 to 1.0) - Change
failureOnTimeout
&failureOnReject
to acheck
function.
Tips
All options can be overwritten in action:
module.export = { name: "users", actions: { create: { circuitBreaker: { threshold: 0.3, windowTime: 30 }, handler(ctx) {} } } };
Now it uses exponential backoff for retries.
Old options
const broker = new ServiceBroker({
requestRetry: 5
});
New options
const broker = new ServiceBroker({
nodeID: "node-1",
retryPolicy: {
enabled: true,
retries: 5,
delay: 100,
maxDelay: 2000,
factor: 2,
check: err => err && !!err.retryable
}
});
Overwrite the retries value in calling option The retryCount
calling options has been renamed to retries
.
broker.call("posts.find", {}, { retries: 3 });
Tips
All options can be overwritten in action:
module.export = { name: "users", actions: { find: { retryPolicy: { // All Retry policy options can be overwritten from broker options. retries: 3, delay: 500 }, handler(ctx) {} }, create: { retryPolicy: { // Disable retries for this action enabled: false }, handler(ctx) {} } } };
Old options
const broker = new ServiceBroker({
trackContext: true
});
New options
const broker = new ServiceBroker({
nodeID: "node-1",
tracking: {
enabled: true,
shutdownTimeout: 5000
}
});
Disable tracking in calling option at calling
broker.call("posts.find", {}, { tracking: false });
The shutdown timeout can be overwritten by $shutdownTimeout property in service settings.
If you need it, download from here, load as a service and call the stat.snapshot
to receive the collected statistics.
Some errors have been renamed in order to follow name conventions.
ServiceNotAvailable
->ServiceNotAvailableError
RequestRejected
->RequestRejectedError
QueueIsFull
->QueueIsFullError
InvalidPacketData
->InvalidPacketDataError
If you check the err.name
or instanceof
in your code, you should check these parts and update to the new error names.
The ctx.callerNodeID
has been removed. The ctx.nodeID
always contains the target or caller nodeID.
Steps:
- Search
callerNodeID
in your project and change them toctx.nodeID
.
It returns Promise
with results of ping responses. Moreover, the method is renamed to broker.ping
.
Ping all known nodes
broker.ping().then(res => broker.logger.info(res));
Output:
{
server: {
nodeID: 'server',
elapsedTime: 10,
timeDiff: -2
}
}
Steps:
- If you uses
broker.sendPing
in your project, rename it tobroker.ping
and handle the returnedPromise
.
The cacher key generation has been changed. If you uses Redis cacher, the old <=0.12 cacher won't find the new 0.13 cache entries.
The cacher matcher code is changed in cacher.clean
method. The previous (wrong) matcher didn't handle dots (.) properly in patterns. E.g the posts.*
pattern cleaned the posts.find.something
keys too. Now it has been fixed, but it means that you should use posts.**
pattern because the params
and meta
values can contain dots.
Some Moleculer Error class constructor signature has been changed.
Steps:
- If you create Moleculer errors in your projects, please check the constructor signature of these errors.
It's not a breaking change because old middleware works with Moleculer v0.13, but it's recommended to do.
The new middleware is an Object
with hooks instead of a simple Function
.
Legacy old middleware
const broker = new ServiceBroker({
middlewares: [
function(handler, action) {
// Wrap the handler if neccessary
}
]
});
Migrated new middleware
const broker = new ServiceBroker({
middlewares: [
{
localAction: function(handler, action) {
// Wrap the handler if neccessary
}
}
]
});
The
broker.use
method to register middlewares has been deprecated. Please usemiddlewares:[]
in broker options instead.
List of all available hooks in new middlewares:
const MyCustomMiddleware = {
// Wrap local action handlers (legacy middleware handler)
localAction(next, action) {
},
// Wrap remote action handlers
remoteAction(next, action) {
},
// Wrap local event handlers
localEvent(next, event) {
}
// Wrap broker.createService method
createService(next) {
}
// Wrap broker.destroyService method
destroyService(next) {
}
// Wrap broker.call method
call(next) {
}
// Wrap broker.mcall method
mcall(next) {
}
// Wrap broker.emit method
emit(next) {
},
// Wrap broker.broadcast method
broadcast(next) {
},
// Wrap broker.broadcastLocal method
broadcastLocal(next) {
},
// After a new local service created (sync)
serviceCreated(service) {
},
// Before a local service started (async)
serviceStarting(service) {
},
// After a local service started (async)
serviceStarted(service) {
},
// Before a local service stopping (async)
serviceStopping(service) {
},
// After a local service stopped (async)
serviceStopped(service) {
},
// After broker is created (async)
created(broker) {
},
// Before broker starting (async)
starting(broker) {
},
// After broker started (async)
started(broker) {
},
// Before broker stopping (async)
stopping(broker) {
},
// After broker stopped (async)
stopped(broker) {
}
}
🎉 Well, you are done! 👏
Happy coding in your brand new Moleculer project. If you need help, join to Gitter chat and don't hesitate to ask Moleculer community.