moleculerjs / moleculer Goto Github PK
View Code? Open in Web Editor NEW:rocket: Progressive microservices framework for Node.js
Home Page: https://moleculer.services/
License: MIT License
:rocket: Progressive microservices framework for Node.js
Home Page: https://moleculer.services/
License: MIT License
The generator always hangs on the "run npm install" question.
The moleculer start
always hangs after help
command.
I'm using node 8.1. Maybe that's it?
The remoteCall
and targetNodeID
is not used.
Refactoring the below parts:
$node.actions
$node.services
actions
in REPLservices
in REPLactions
in INFO & DISCOVER packetsOther tasks:
Hello!
Do you have any plan to support typescript?
I didn't see moleculer at @types.
Thanks in advance
Current solution: if a request returns back with >=500 error code, broker set the node to "unavailable". It is not too accurate because maybe just an action give errors, the node and node's other actions are working properly. Need to implement CB for actions (in the ServiceBroker).
Leave the node's "unavailable" flag when heartbeat is not received from the node.
Trying to implement as a middleware. Performance limit is -10%. โ
I keep doing checks to avoid broker throwing errors. I think broker should be able to detect a call for itself and do the proper actions
module.exports = function(router) {
/**
* Gets all cluster nodes excluding the current node
*/
router.get("/cluster/nodes", async function(req, res) {
const broker = req.app.broker;
const logger = req.app.logger;
const nodes = {};
const allNodes = await broker.call("$node.list", { withEndpoints: true });
allNodes
.map(node => {
if (node.id === null) {
node.id = broker.nodeID; // PROBLEM #1 - I have to fill the gaps for null ids
}
if (node.services) {
delete node.services;
}
return node;
})
.forEach(node => {
nodes[node.id] = node;
});
for (const nodeID in nodes) {
// This check doesn't make sense
const callOptions = nodeID === broker.nodeID ? { } : { nodeID }; // PROBLEM #2 - Broker should detect this scenario
try {
nodes[nodeID].stats = await broker.call("$node.stats", {}, callOptions);
} catch(err) {
logger.error(err);
nodes[nodeID].stats = null;
}
try {
nodes[nodeID].health = await broker.call("$node.health", {}, callOptions);
} catch(err) {
logger.error(err);
nodes[nodeID].health = null;
}
}
res.send(nodes);
});
};
Would be nice to be able to listen on node for disconnected event
(when we are using 'moleculer-web')
so we can do some custom logic in that case
and also some parameter in settings so when some node goes down then show this kind of respnses
instead of hanging request to specific action (this happens after we stop/kill some node)
would be nice also to check if node is down or not
before we call action
{
"name": "ServiceNotFoundError",
"message": "Service 'extra.hello' is not available!",
"code": 501,
"type": null,
"data": {
"action": "extra.hello"
}
}
or
{
"name": "NodeNotFoundError",
"message": "Service 'extra.hello' on node 'server-1' is not available!",
"code": 501,
"type": null,
"data": {
"action": "extra.hello"
}
}
yes we can use timeout but then it does not gives us a correct understanding what was happened
in case some node is disconnected
[TRANSIT] Node 'server-1' disconnected!
NATS is beased on go language. I think it should be easy implement moleculer-go.
But i can't find the molecular's protocol.
Would this be something that would align with the gameplan for Moleculer? Right now if version exists its being prefixed with a 'v' which makes sense for numerical versions. In our use case we might want to have different versions of a microservice running for various features we are working on. In that case i have suggested something like 'staging.serviceName.actionName'. Allowing individual teams to deploy microservices to our infrastructure that can be targeted via the api gateway for that specific environment/feature.
I was just discovering this project starting out on a new one of my own. It looks nice. but I was wondering where it has been used in production. Or if anyone notable was using it. I think it looks great but if im going to start something new I don't want to start with any random framework.
as a comparison, outside of this i was probably going to go with hapi.js
I don't know if this is NATS specific and I couldn't figure out why this happens, but can be easily reproduced:
moleculer connect nats://localhost:4222
actions
and you'll see all actions offline.actions
too. All actions are online.https://files.gitter.im/ice-services/moleculer/Dna6/image.png
Add AMQP support with amqp.node
It's a pretty big win if moleculer could also work like this:
http://cote.js.org/#multicast-address
The single point of failture like NATS would be gone.
We need a namespace
property that we can segment our services.
For example, we are running development & production services (or more production services) on the same transporter, but we need to avoid collisions.
Currently there is a prefix
property in the Transporter options (which solve it), but I want to move it to ServiceBroker options (in v0.9.x).
const broker = new ServiceBroker({
logger: console,
namespace: "blog" // for production
namespace: "blog.dev" // for development
namespace: "blog.test" // for testing
});
And it can be also set via environment variable NAMESPACE
.
It'd be great to have better support for action/method grouping (svc.actionGroup.subAction
).
Currently it's achievable using string literal keys:
{
name: "svc",
methods: {
"methodGroup.subMethod": () => 42,
},
actions: {
"actionGroup.subAction"() {
return this["methodGroup.subMethod"]();
},
},
}
Both the pattern and modularizing of service logic based on groups could be more elegant:
{
name: "svc",
methods: {
methodGroup: {
subMethod: () => 42,
},
},
actions: {
actionGroup: {
subAction() {
return this.methodGroup.subMethod();
},
}
},
}
If two services listen to a same event, when it occurs, both of them will receive the event, I guess.
Does moleculer support event group which is supported natively by nats and amqp?
Say, if the two services listen to a same event but and join a same group, only one of them will receive the event at a time.
What happens if we register multiple times the same service name with different schema?
(currently seems the latest registered schema wins)
Would it be usefull to have the hash of the loaded schema reported for each service?
Is it safe to register services on the fly (without stoping restarting the broker)?
In examples/user.service.js there is a flag latestVersion: true. Any plans to use semantic versioning in order
to implicitly peek a service version (like stable or latest) as default?
NATS Streaming, Kafka...etc
With protobufjs
Just curious how far you are and what is still missing/planned for a prod ready release.
How that is stack up to other contenders such as seneca? pros/cons?
Cheers!
NATS transporter (node-nats)
Redis transporter (ioredis)
MQTT transporter (mqtt)
Redis cacher (ioredis)
Avro serializer (avsc)
MsgPack serializer (msgpack5)
Protocol Buffer serializer (protobufjs)
Update docs
When I call a service from Chrome, I always get:
ServiceNotFoundError: Service 'favicon.ico' is not available!
followed by an error stack.
While using Redis transporter:
(node:10664) Warning: a promise was created in a handler at \node_modules\moleculer\src\transit.js:73:11 but was not returned from it, see http://goo.gl/rRqMUw
at new Promise (\node_modules\bluebird\js\release\promise.js:79:10)
(node:10664) Warning: a promise was created in a handler at \node_modules\moleculer\src\transit.js:76:21 but was not returned from it, see http://goo.gl/rRqMUw
at new Promise (\node_modules\bluebird\js\release\promise.js:79:10)
(node:10664) Warning: a promise was created in a handler at \node_modules\moleculer\src\transit.js:77:21 but was not returned from it, see http://goo.gl/rRqMUw
at new Promise (\node_modules\bluebird\js\release\promise.js:79:10)
Metadata in context which will be transported with request. (for user, session, state...etc)
ctx.meta = {
user: {
id: req.user.id,
roles: req.user.roles
}
}
broker.mcall([
{ action: "posts.find", params: {limit: 5, offset: 0}, options: { timeout: 500 } },
{ action: "users.find", params: {limit: 5, sort: "username"} }
]).then(results => {
let posts = results[0];
let users = results[1];
})
broker.mcall({
posts: { action: "posts.find", params: {limit: 5, offset: 0}, options: { timeout: 500 } },
users: { action: "users.find", params: {limit: 5, sort: "username"} }
}).then(results => {
let posts = results.posts;
let users = results.users;
})
Support MQTT with mqtt.js
It's not working to define cacher with env
CACHER=redis://redis
According to the documentation, we could get nodeID in context
But I only get null.
Context {
id: null,
broker:
ServiceBroker {
options:
{ nodeID: 'T4F-MBP-13504.local.24144',
logger: [Object],
logLevel: 'info',
transporter: null,
requestTimeout: 0,
requestRetry: 0,
maxCallLevel: 0,
heartbeatInterval: 10,
heartbeatTimeout: 30,
registry: [Object],
circuitBreaker: [Object],
cacher: null,
serializer: null,
validation: true,
metrics: false,
metricsRate: 1,
statistics: false,
internalActions: true },
Promise:
{ [Function: Promise]
TypeError: [Function: TypeError],
RangeError: [Function: RangeError],
CancellationError: [Function: SubError],
TimeoutError: [Function: SubError],
OperationalError: [Function: OperationalError],
RejectionError: [Function: OperationalError],
AggregateError: [Function: SubError],
_peekContext: [Function],
onPossiblyUnhandledRejection: [Function],
onUnhandledRejectionHandled: [Function],
longStackTraces: [Function],
hasLongStackTraces: [Function],
config: [Function],
getNewLibraryCopy: [Function],
is: [Function],
fromCallback: [Function],
fromNode: [Function],
all: [Function],
cast: [Function],
fulfilled: [Function],
resolve: [Function],
rejected: [Function],
reject: [Function],
setScheduler: [Function],
pending: [Function],
defer: [Function],
method: [Function],
try: [Function],
attempt: [Function],
bind: [Function],
PromiseInspection: [Function: PromiseInspection],
join: [Function],
Promise: [Circular],
version: '3.5.0',
map: [Function],
using: [Function],
delay: [Function],
coroutine: [Object],
spawn: [Function],
promisify: [Function],
promisifyAll: [Function],
props: [Function],
race: [Function],
reduce: [Function],
settle: [Function],
some: [Function],
_SomePromiseArray: [Function: SomePromiseArray],
filter: [Function],
each: [Function],
mapSeries: [Function: PromiseMapSeries],
any: [Function],
noConflict: [Function: noConflict] },
ServiceFactory: [Function: Service],
ContextFactory: [Function: Context],
nodeID: 'T4F-MBP-13504.local.24144',
_loggerCache:
{ BROKER: [Object],
'HELLO-SVC': [Object],
'API-GW-SVC': [Object] },
logger:
{ fatal: [Function: bound ],
error: [Function: bound ],
warn: [Function: bound ],
info: [Function: bound ],
debug: [Function: noop],
trace: [Function: noop] },
bus:
EventEmitter {
_events: {},
newListener: false,
verboseMemoryLeak: false,
_conf: [Object],
_maxListeners: 100,
wildcard: true,
listenerTree: {} },
services: [ [Object], [Object] ],
serviceRegistry:
ServiceRegistry {
opts: [Object],
services: [Array],
actions: [Object],
broker: [Circular] },
middlewares: [ [Function: bound validatorMiddleware] ],
cacher: null,
serializer: JSONSerializer { broker: [Circular] },
validator: ParamValidator { validator: [Object], broker: [Circular] },
sampleCount: 0,
getNodeHealthInfo: [Function],
_closeFn: [Function] },
action:
{ handler: [Function],
name: 'hello.hello',
version: undefined,
service:
Service {
name: 'hello',
version: undefined,
settings: {},
schema: [Object],
broker: [Object],
Promise: [Object],
logger: [Object],
actions: [Object],
created: [Function],
started: [Function],
stopped: [Function] },
cache: false },
nodeID: null,
parentID: null,
metrics: false,
level: 2,
timeout: 0,
retryCount: 0,
params: {},
meta: {},
requestID: null,
startTime: null,
startHrTime: null,
stopTime: null,
duration: 0,
cachedResult: false }
Hi, I like this project concept. I've been created 2 projects a worker and gateway connecting on the Redis transport, but I have some problem when I stop or restart worker. The gateway continues calling the stopped worker, look the gateway log messages:
[BROKER] 'api-gw' service is registered!
[API-GW-SVC] API Gateway created!
[API-GW-SVC] API Gateway listening on http://0.0.0.0:3000
[TX] Redis-sub connected!
[TX] Redis-pub connected!
[BROKER] Broker started. NodeID: GW-HPDEV-24176
[TRANSIT] Node 'WORKER-HPDEV-24155' connected! -> I start the worker
[TRANSIT] Node 'WORKER-HPDEV-24192' connected! -> Restart the worker
[TRANSIT] Node 'WORKER-HPDEV-24155' disconnected! -> detected the disconnection
[API-GW-SVC] Call 'math.teste' action with params: {}
[BROKER] Action 'math.teste' call timed out on 'WORKER-HPDEV-24155'! -> look, he called the killed process
[BROKER] Recall 'math.teste' action (retry: 3)...
[API-GW-SVC] Call 'math.teste' action with params: {}
After some retries he call right service.
This is a bug or wrong configuration?
let broker = new ServiceBroker({
nodeID: 'GW-' + hostname + '-' + process.pid,
logger: console,
metrics: true,
requestTimeout: 5000,
requestRetry: 3,
circuitBreaker: {
enabled: true,
maxFailures: 3,
halfOpenTime: 500,
failureOnTimeout: true,
failureOnReject: true
},
transporter: new RedisTransporter({
redis: {
port: 6379,
host: 'localhost',
family: 4,
db: 1
}
})
})
// Load API Gateway
broker.createService(ApiService);
// Start server
broker.start()
metricsSendInterval
). It is not neccessary. Anyone can call it via $node.health
and $node.stats
I've found you're using fastest-validator
(which rocks!), but it's not documented (or I haven't found it).
It would be helpful to have access to it directly from the documentation.
Having an issue with service discovery on MQTT, probably just a user error but i'd appreciate some guidance.
const Moleculer = require('moleculer');
const { ServiceBroker, Transporters: { MQTT: MqttTransport } } = Moleculer;
const transporter = new MqttTransport('mqtt://localhost:1883');
const broker = new ServiceBroker({
logger: console,
transporter,
});
broker.createService({
name: 'engagedAction',
actions: {
create() {
return 'hello world';
},
},
});
broker.start().then(() => broker.call('engagedAction.create')).then(r => console.log(r));
I run this then I switch to terminal where I create an identical ServiceBroker and call $node.services and the service from the other node is never there. I have confirmed that both nodes are connected to my MQTT service and i can see messages posting in the backend. Any thoughts on the step i'm missing?
If transporter can't connect to server, but reconnect is success, transit doesn't register handlers & doesn't send discover.
Exceptions in event handlers result in unhandled promise rejections.
Features
/api
)users.create
-> POST /users
)Upon sending SIGINT
to an application, the NATS transporter sends a disconnect packet, every now and then resulting in an unhandled promise rejection:
Unhandled rejection TypeError: Cannot read property 'publish' of null
at NatsTransporter.publish (\node_modules\moleculer\src\transporters\nats.js:151:14)
at Transit.publish (\node_modules\moleculer\src\transit.js:494:18)
at Transit.sendDisconnectPacket (\node_modules\moleculer\src\transit.js:162:8)
at Transit.disconnect (\node_modules\moleculer\src\transit.js:145:16)
at Promise.resolve.then.catch.then (\node_modules\moleculer\src\service-broker.js:291:26)
at runCallback (timers.js:800:20)
at tryOnImmediate (timers.js:762:5)
at processImmediate [as _immediateCallback] (timers.js:733:5)
From previous event:
at ServiceBroker.stop (\node_modules\moleculer\src\service-broker.js:289:5)
at process.ServiceBroker._closeFn (\node_modules\moleculer\src\service-broker.js:159:9)
at emitOne (events.js:115:13)
at process.emit (events.js:210:7)
This package looks awesome! Great work so far, excited to see what else will come of it!
One thing I noticed is that a large chunk (~2/3) of the dependencies are only used for the REPL (vorpal, table, clui)
(collected using cost-of-modules)
I haven't looked deeply enough into the source code to see if it would be possible. But I think it may be worth exploring making moleculer-repl
a separate package that developers can add as a devDepenency
and reduce final size of the production build.
Would be great if we could use something like Pino as the logger:
const logger = require("pino")({ level: "info" });
const { ServiceBroker } = require("moleculer");
const broker = new ServiceBroker({ logger });
broker.logger.info("hi");
TypeError: Cannot read property 'write' of undefined
at LOG (node_modules\pino\lib\tools.js:102:9)
at EventEmitter. (node_modules\moleculer\src\logger.js:63:7)
After all, it's really fast and supports custom log levels and child loggers.
With ioredis
Is there any guideline to help choose transporter?
Hi everyone,
I'm trying to choose a microservices framework to use with node
but I really need to be able to integrate it with Eureka since we already have a
microservices infrastructure using Eureka :'(
Does anybody know how to use moleculer with Eureka for service register/discovery?
Create a CLI tool to generate moleculer base project & services from templates.
Tasks
moleculer init
- generate an empty moleculer base project from a templatemoleculer add service
- create a new service file. Prompted values: name, version, action names. Create service file and put to the services
folder.moleculer connect <connectionstring>
- connect to a transporter or start a local broker. After it switch to REPL mode with vorpal. Available commands: call
, event
, loadService
A declarative, efficient, and flexible JavaScript library for building user interfaces.
๐ Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.
TypeScript is a superset of JavaScript that compiles to clean JavaScript output.
An Open Source Machine Learning Framework for Everyone
The Web framework for perfectionists with deadlines.
A PHP framework for web artisans
Bring data to life with SVG, Canvas and HTML. ๐๐๐
JavaScript (JS) is a lightweight interpreted programming language with first-class functions.
Some thing interesting about web. New door for the world.
A server is a program made to process requests and deliver data to clients.
Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.
Some thing interesting about visualization, use data art
Some thing interesting about game, make everyone happy.
We are working to build community through open source technology. NB: members must have two-factor auth.
Open source projects and samples from Microsoft.
Google โค๏ธ Open Source for everyone.
Alibaba Open Source for everyone
Data-Driven Documents codes.
China tencent open source team.