Progressive microservices framework for Node.js
MIT License
Bot releases are hidden (Show)
Published by icebob over 3 years ago
disableHeartbeatChecks
option handling. #858
waitForServices
debug log messages. #870
EVENT
packet Avro schema. #856
Published by icebob almost 4 years ago
rediss://
cacher URI. #837
broker.waitForServices
response. #843
Published by icebob about 4 years ago
merged
service lifecycle hookService has a new merged
lifecycle hook which is called after the service schemas (including mixins) has been merged but before service is registered. It means you can manipulate the merged service schema before it's processed.
Example
// posts.service.js
module.exports = {
name: "posts",
settings: {},
actions: {
find: {
params: {
limit: "number"
}
handler(ctx) {
// ...
}
}
},
merged(schema) {
// Modify the service settings
schema.settings.myProp = "myValue";
// Modify the param validation schema in an action schema
schema.actions.find.params.offset = "number";
}
};
Published by icebob about 4 years ago
If you create a custom module (e.g. serializer), you can register it into the built-in modules with the register
method. This method is also available in all other built-in module resolver.
Example
// SafeJsonSerializer.js
const { Serializers } = require("moleculer");
class SafeJsonSerializer {}
Serializers.register("SafeJSON", SafeJSON);
module.exports = SafeJsonSerializer;
// moleculer.config.js
require("./SafeJsonSerializer");
module.exports = {
nodeID: "node-100",
serializer: "SafeJSON"
// ...
});
You can change the params
property name in validator options. It can be useful if you have a custom Validator implementation.
const broker = new ServiceBroker({
validator: {
type: "Fastest",
options: {
paramName: "myParams" // using `myParams` instead of `params`
}
}
});
broker.createService({
name: "posts",
actions: {
create: {
myParams: {
title: "string"
}
},
handler(ctx) { /* ... */ }
}
});
Thanks for @kthompson23, you can configure the action & events tracing span tags globally. These tags will be used for all actions & events where tracing is enabled. Of course, you can overwrite them locally in the action & event schema.
Example
// moleculer.config.js
module.exports = {
tracing: {
enabled: true,
exporter: 'Zipkin',
tags: {
action: {
meta: ['app.id', 'user.email', 'workspace.name'],
params: false, // overrides default behavior of all params being adding as tags
response: true,
},
event: (ctx) {
return {
caller: ctx.caller,
}
}
}
}
}
lastValue
property to histogram metric type.Published by icebob over 4 years ago
We have been approved in Github Sponsors program, so you can sponsor the Moleculer project via Github Sponsors.
If you have taxing problem with Patreon, change to Github Sponsors.
The validator
has the same module configuration in broker options like other modules. It means you can configure the validation constructor options via broker options (moleculer.config.js).
Default usage:
//moleculer.config.js
module.exports = {
nodeID: "node-100",
validator: true // Using the default Fastest Validator
}
Using built-in validator name:
//moleculer.config.js
module.exports = {
nodeID: "node-100",
validator: "FastestValidator" // Using the Fastest Validator
}
Example with options:
//moleculer.config.js
module.exports = {
nodeID: "node-100",
validator: {
type: "FastestValidator",
options: {
useNewCustomCheckerFunction: true,
defaults: { /*...*/ },
messages: { /*...*/ },
aliases: { /*...*/ }
}
}
}
Example with custom validator
//moleculer.config.js
const BaseValidator = require("moleculer").Validators.Base;
class MyValidator extends BaseValidator {}
module.exports = {
nodeID: "node-100",
validator: new MyValidator()
}
Added the following new metrics:
moleculer.event.received.active
: Number of active event executions.moleculer.event.received.error.total
: Number of event execution errors.moleculer.event.received.time
: Execution time of events in milliseconds.os.memory.total
: OS used memory size.moleculer.config.js
with export default
.tsd
.dependencyInterval
broker option. Using as default value for broker.waitForServices
#761
dd-trace
.EventLegacy
trace exporter.Published by icebob over 4 years ago
The Discoverer is a new built-in module in Moleculer framework. It's responsible for that all Moleculer nodes can discover each other and check them with heartbeats. In previous versions, it was an integrated module inside ServiceRegistry
& Transit
modules. In this version, the discovery logic has been extracted to a separated built-in module. It means you can replace it to other built-in implementations or a custom one. The current discovery & heartbeat logic is moved to the Local
Discoverer.
Nevertheless, this version also contains other discoverers, like Redis & etcd3 discoverers. Both of them require an external server to make them work.
One of the main advantages of the external discoverers, the node discovery & heartbeat packets don't overload the communication on the transporter. The transporter transfers only the request, response, event packets.
By the way, the external discoverers have some disadvantages, as well. These discoverers can detect lazier the new and disconnected nodes because they scan the heartbeat keys periodically on the remote Redis/etcd3 server. The period of checks depends on the heartbeatInterval
broker option.
The Local Discoverer (which is the default) works like the discovery of previous versions, so if you want to keep the original logic, you'll have to do nothing.
Please note the TCP transporter uses Gossip protocol & UDP packets for discovery & heartbeats, it means it can work only with Local Discoverer.
It's the default Discoverer, it uses the transporter module to discover all other moleculer nodes. It's quick and fast but if you have too many nodes (>100), the nodes can generate a lot of heartbeat packets which can reduce the performance of request/response packets.
Example
// moleculer.config.js
module.exports = {
registry: {
discoverer: "Local"
}
}
Example with options
// moleculer.config.js
module.exports = {
registry: {
discoverer: {
type: "Local",
options: {
// Send heartbeat in every 10 seconds
heartbeatInterval: 10,
// Heartbeat timeout in seconds
heartbeatTimeout: 30,
// Disable heartbeat checking & sending, if true
disableHeartbeatChecks: false,
// Disable removing offline nodes from registry, if true
disableOfflineNodeRemoving: false,
// Remove offline nodes after 10 minutes
cleanOfflineNodesTimeout: 10 * 60
}
}
}
}
This is an experimental module. Do not use it in production yet!
This Discoverer uses a Redis server to discover Moleculer nodes. The heartbeat & discovery packets are stored in Redis keys. Thanks to Redis key expiration, if a node crashed or disconnected unexpectedly, the Redis will remove its heartbeat keys from the server and other nodes can detect it.
Example to connect local Redis server
// moleculer.config.js
module.exports = {
registry: {
discoverer: "Redis"
}
}
Example to connect remote Redis server
// moleculer.config.js
module.exports = {
registry: {
discoverer: "redis://redis-server:6379"
}
}
Example with options
// moleculer.config.js
module.exports = {
registry: {
discoverer: {
type: "Redis",
options: {
redis: {
// Redis connection options.
// More info: https://github.com/luin/ioredis#connect-to-redis
port: 6379,
host: "redis-server",
password: "123456",
db: 3
}
// Serializer
serializer: "JSON",
// Full heartbeat checks. It generates more network traffic
// 10 means every 10 cycle.
fullCheck: 10,
// Key scanning size
scanLength: 100,
// Monitoring Redis commands
monitor: true,
// --- COMMON DISCOVERER OPTIONS ---
// Send heartbeat in every 10 seconds
heartbeatInterval: 10,
// Heartbeat timeout in seconds
heartbeatTimeout: 30,
// Disable heartbeat checking & sending, if true
disableHeartbeatChecks: false,
// Disable removing offline nodes from registry, if true
disableOfflineNodeRemoving: false,
// Remove offline nodes after 10 minutes
cleanOfflineNodesTimeout: 10 * 60
}
}
}
}
To be able to use this Discoverer, install the
ioredis
module with the npm install ioredis --save command.
Tip: To further network traffic reduction, you can use MsgPack/Notepack serializers instead of JSON.
This is an experimental module. Do not use it in production yet!
This Discoverer uses an etcd3 server to discover Moleculer nodes. The heartbeat & discovery packets are stored in the server. Thanks to etcd3 lease solution, if a node crashed or disconnected unexpectedly, the etcd3 will remove its heartbeat keys from the server and other nodes can detect it.
Example to connect local etcd3 server
// moleculer.config.js
module.exports = {
registry: {
discoverer: "Etcd3"
}
}
Example to connect remote etcd3 server
// moleculer.config.js
module.exports = {
registry: {
discoverer: "etcd3://etcd-server:2379"
}
}
Example with options
// moleculer.config.js
module.exports = {
registry: {
discoverer: {
type: "Etcd3",
options: {
etcd: {
// etcd3 connection options.
// More info: https://mixer.github.io/etcd3/interfaces/options_.ioptions.html
hosts: "etcd-server:2379",
auth: "12345678"
}
// Serializer
serializer: "JSON",
// Full heartbeat checks. It generates more network traffic
// 10 means every 10 cycle.
fullCheck: 10,
// --- COMMON DISCOVERER OPTIONS ---
// Send heartbeat in every 10 seconds
heartbeatInterval: 10,
// Heartbeat timeout in seconds
heartbeatTimeout: 30,
// Disable heartbeat checking & sending, if true
disableHeartbeatChecks: false,
// Disable removing offline nodes from registry, if true
disableOfflineNodeRemoving: false,
// Remove offline nodes after 10 minutes
cleanOfflineNodesTimeout: 10 * 60
}
}
}
}
To be able to use this Discoverer, install the
etcd3
module with the npm install etcd3--save command.
Tip: To further network traffic reduction, you can use MsgPack/Notepack serializers instead of JSON.
You can create your custom Discoverer. We recommend to copy the source of Redis Discoverer and implement the necessary methods.
heartbeatInterval
default value has been changed to 10
seconds.heartbeatTimeout
default value has been changed to 30
seconds.removeFromArray
function in Utils.mcall
method definition fixed in Typescript definition.Published by icebob over 4 years ago
Thanks for @jalerg, there is a NewRelic tracing exporter. PR #713
// moleculer.config.js
{
tracing: {
enabled: true,
events: true,
exporter: [
{
type: 'NewRelic',
options: {
// NewRelic Insert Key
insertKey: process.env.NEW_RELIC_INSERT_KEY,
// Sending time interval in seconds.
interval: 5,
// Additional payload options.
payloadOptions: {
// Set `debug` property in payload.
debug: false,
// Set `shared` property in payload.
shared: false,
},
// Default tags. They will be added into all span tags.
defaultTags: null,
},
},
],
},
}
Published by icebob over 4 years ago
New localMethod
hook in middlewares which wraps the service methods.
Example
// my.middleware.js
module.exports = {
name: "MyMiddleware",
localMethod(next, method) {
return (...args) => {
console.log(`The '${method.name}' method is called in '${method.service.fullName}' service.`, args);
return handler(...args);
}
}
}
Similar for action schema, you can define service methods with schema. It can be useful when middleware wraps service methods.
Example for new method schema
// posts.service.js
module.exports = {
name: "posts",
methods: {
list: {
async handler(count) {
// Do something
return posts;
}
}
}
};
Published by icebob over 4 years ago
Published by icebob over 4 years ago
If you have your custom logger you should wrap it into a Logger
class and implement the getLogHandler
method.
Using a custom logger
// moleculer.config.js
const BaseLogger = require("moleculer").Loggers.Base;
class MyLogger extends BaseLogger {
getLogHandler(bindings) {
return (type, args) => console[type](`[MYLOG-${bindings.mod}]`, ...args);
}
}
module.exports = {
logger: new MyLogger()
};
Published by icebob over 4 years ago
🎉 First 0.14 stable version. Full changelog: https://github.com/moleculerjs/moleculer/blob/master/CHANGELOG.md#0140-2020-02-12
Migration guide: https://github.com/moleculerjs/moleculer/blob/master/docs/MIGRATION_GUIDE_0.14.md
Thanks for @vladir95, AMQP 1.0 transporter is available.
Please note, it is an experimental transporter. Do not use it in production yet!
// moleculer.config.js
module.exports = {
transporter: "amqp10://activemq-server:5672"
};
To use this transporter install the
rhea-promise
module withnpm install rhea-promise --save
command.
Options can be passed to rhea.connection.open()
method, the topics, the queues, and the messages themselves.
Connect to 'amqp10://guest:guest@localhost:5672'
// moleculer.config.js
module.exports = {
transporter: "AMQP10"
};
Connect to a remote server
// moleculer.config.js
module.exports = {
transporter: "amqp10://activemq-server:5672"
};
Connect to a remote server with options & credentials
// moleculer.config.js
module.exports = {
transporter: {
url: "amqp10://user:pass@activemq-server:5672",
eventTimeToLive: 5000,
heartbeatTimeToLive: 5000,
connectionOptions: { // rhea connection options https://github.com/amqp/rhea#connectoptions, example:
ca: "", // (if using tls)
servername: "", // (if using tls)
key: "", // (if using tls with client auth)
cert: "" // (if using tls with client auth)
},
queueOptions: {}, // rhea queue options https://github.com/amqp/rhea#open_receiveraddressoptions
topicOptions: {}, // rhea queue options https://github.com/amqp/rhea#open_receiveraddressoptions
messageOptions: {}, // rhea message specific options https://github.com/amqp/rhea#message
topicPrefix: "topic://", // RabbitMq uses '/topic/' instead, 'topic://' is more common
prefetch: 1
}
};
Thanks for AAfraitane, use can connect to a Redis Cluster with the Redis transporter.
Connect to Redis cluster
// moleculer.config.js
module.exports = {
transporter: {
type: "Redis",
options: {
cluster: {
nodes: [
{ host: "localhost", port: 6379 },
{ host: "localhost", port: 6378 }
]
}
}
}
};
Published by icebob over 4 years ago
Thanks for @vladir95, AMQP 1.0 transporter is available.
Please note, it is an experimental transporter. Do not use it in production yet!
// moleculer.config.js
module.exports = {
transporter: "amqp10://activemq-server:5672"
};
To use this transporter install the
rhea-promise
module withnpm install rhea-promise --save
command.
Options can be passed to rhea.connection.open()
method, the topics, the queues, and the messages themselves.
Connect to 'amqp10://guest:guest@localhost:5672'
// moleculer.config.js
module.exports = {
transporter: "AMQP10"
};
Connect to a remote server
// moleculer.config.js
module.exports = {
transporter: "amqp10://activemq-server:5672"
};
Connect to a remote server with options & credentials
// moleculer.config.js
module.exports = {
transporter: {
url: "amqp10://user:pass@activemq-server:5672",
eventTimeToLive: 5000,
heartbeatTimeToLive: 5000,
connectionOptions: { // rhea connection options https://github.com/amqp/rhea#connectoptions, example:
ca: "", // (if using tls)
servername: "", // (if using tls)
key: "", // (if using tls with client auth)
cert: "" // (if using tls with client auth)
},
queueOptions: {}, // rhea queue options https://github.com/amqp/rhea#open_receiveraddressoptions
topicOptions: {}, // rhea queue options https://github.com/amqp/rhea#open_receiveraddressoptions
messageOptions: {}, // rhea message specific options https://github.com/amqp/rhea#message
topicPrefix: "topic://", // RabbitMq uses '/topic/' instead, 'topic://' is more common
prefetch: 1
}
};
Thanks for AAfraitane, use can connect to a Redis Cluster with the Redis transporter.
Connect to Redis cluster
// moleculer.config.js
module.exports = {
transporter: {
type: "Redis",
options: {
cluster: {
nodes: [
{ host: "localhost", port: 6379 },
{ host: "localhost", port: 6378 }
]
}
}
}
};
Published by icebob over 4 years ago
ctx.locals
Published by icebob over 4 years ago
Published by icebob over 4 years ago
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: () => { ... }
}
};
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
}
}
};
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
}
}
};
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 withnpm install pino --save
command.
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 withnpm install bunyan --save
command.
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 withnpm install winston --save
command.
debug
loggerThis 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 withnpm install debug --save
command.
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 withnpm install log4js --save
command.
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
}
}
};
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",
}
},
{
type: "File",
options: {
level: "info",
folder: "/logs/moleculer",
filename: "all-{date}.log",
formatter: "{timestamp} {level} {nodeID}/{mod}: {msg}"
}
},
{
type: "File",
options: {
level: "error",
folder: "/logs/moleculer",
filename: "errors-{date}.json",
formatter: "json"
}
}
]
};
Using different loggers for different modules
This configuration demonstrates how you can define loggers for certain modules.
// moleculer.config.js
module.exports = {
logger: [
// Shorthand `Console` logger configuration
"Console",
{
// This logger saves messages from all modules except "greeter" service.
type: "File",
options: {
level: {
"GREETER": false,
"**": "info"
},
filename: "moleculer-{date}.log"
}
},
{
// This logger saves messages from only "greeter" service.
type: "File",
options: {
level: {
"GREETER": "debug",
"**": false
},
filename: "greeter-{date}.log"
}
}
],
logLevel: "info" // global log level. All loggers inherits it.
};
To configure logging levels, you can use the well-known logLevel
broker option which can be a String
or an Object
. But it is possible to overwrite it in all logger options
with the level
property.
Complex logging level configuration
// moleculer.config.js
module.exports = {
logger: [
// The console logger will use the `logLevel` global setting.
"Console",
{
type: "File",
options: {
// Overwrite the global setting.
level: {
"GREETER": false,
"**": "warn"
}
}
}
],
logLevel: {
"TRACING": "trace",
"TRANS*": "warn",
"GREETER": "debug",
"**": "info",
}
};
chalk
to kleur
timeout
option to action schema.Published by icebob over 4 years ago
Published by icebob over 4 years ago
The Node version 8 LTS lifecycle has been ended on December 31, 2019, so the minimum required Node version is 10.
The Bluebird Promise library has been dropped from the project because as of Node 10 the native Promise
implementation is faster (2x) than Bluebird.
Nonetheless, you can use your desired Promise library, just set the Promise
broker options.
Using Bluebird
const BluebirdPromise = require("bluebird");
// moleculer.config.js
module.exports = {
Promise: BluebirdPromise
};
Please note, the given Promise library will be polyfilled with
delay
,method
,timeout
andmapSeries
methods (which are used inside Moleculer core modules).
Service class has a new emitLocalEventHandler
method in order to call a service event handler directly. It can be useful in Unit Tests because you don't need to emit an event with broker.emit
.
Example
// posts.service.js
module.exports = {
name: "posts",
events: {
async "user.created"(ctx) {
this.myMethod(ctx.params);
}
}
};
// posts.service.spec.js
describe("Test events", () => {
const broker = new ServiceBroker({ logger: false });
const svc = broker.createService(PostService);
beforeAll(() => broker.start());
afterAll(() => broker.stop());
describe("Test 'user.created' event", () => {
beforeAll(() => svc.myMethod = jest.fn());
afterAll(() => svc.myMethod.mockRestore());
it("should call the event handler", async () => {
await svc.emitLocalEventHandler("branch.closed", { a: 5 });
expect(svc.myMethod).toBeCalledTimes(1);
expect(svc.myMethod).toBeCalledWith({ a: 5 });
});
});
});
objectMode
supportThanks for @artur-krueger, the request & response streams support objectMode
, as well. You can also send Javascript objects via streams.
Example
defaultBuckets
value has been changed to milliseconds.caller
label for EVENT_RECEIVED_TOTAL metric.heartbeatInterval: 0
broker option.currentContext
property in Service
& ServiceBroker
.this.originalSchema
.