Code Monkey home page Code Monkey logo

seneca-mesh's Introduction

Seneca

Mesh your Seneca.js microservices together - no more service discovery!

seneca-mesh

npm version Build Status Gitter

This plugin allows you to wire up Seneca microservices using automatic meshing. It uses the SWIM gossip algorithm for automatic service discovery within the microservice network.

To join the network, all a service has to do is contact one other service already in the network. The network then shares information about which services respond to which patterns. There is no need to configure the location of individual services anywhere.

Many thanks to Rui Hu for the excellent swim module that makes this work.

If you're using this module, and need help, you can:

If you are new to Seneca in general, please take a look at senecajs.org. We have everything from tutorials to sample apps to help get you up and running quickly.

Seneca compatibility

Supports Seneca versions 3.x and above.

Install

To install, use npm

npm install seneca-balance-client
npm install seneca-mesh

The seneca-mesh plugin depends on the seneca-balance-client plugin.

And in your code:

require('seneca')()
  .use('mesh', { ... options ... })

Using Windows? seneca-mesh uses some native modules, so make sure to configure msbuild.

Quick Example

Create a microservice. The service translates color names into hex values.

// color-service.js
var Seneca = require('seneca')

Seneca()
  // Uncomment to get detailed logs
  // .test('print')
  
  // provide an action for the format:hex pattern
  .add('format:hex', function (msg, reply) {

    // red is the only color supported!
    var color = 'red' === msg.color ? '#FF0000' : '#FFFFFF'

    reply({color: color})
  })

  // load the mesh plugin
  .use('mesh', {

    // this is a base node
    isbase: true,

    // this service will respond to the format:hex pattern
    pin: 'format:hex'
  })

Run the service (and leave it running) using:

$ node color-service.js

Create a client for the service. This client joins the mesh network, performs an action, and then leaves.

// color-client.js
var Seneca = require('seneca')

Seneca({log: 'test'})

  // load the mesh plugin
  .use('mesh')

  // send a message out into the network
  // the network will know where to send format:hex messages
  .act({format: 'hex', color: 'red'}, function (err, out) {

    // prints #FF0000
    console.log(out.color)
  })

Run the client in a separate terminal using:

$ node color-client.js

The client finds the service using the mesh network. In this simple case, the color-service is configured as a base node, which means that it listens on a pre-defined local UDP port. The client checks for base nodes on this port.

Notice that the client did not need any infomation about the service location.

To join a network, you do need to know where the base nodes are. Once you've joined, you don't even need the bases anymore, as the network keeps you informed of new services.

To find base nodes, seneca-mesh provides support for discovery via configuration, multicast, service registries, and custom approaches. Base nodes are not used for service discovery. They serve only as a convenient means for new nodes to join the network.

In the above example, UDP multicast was used by default. In production you'll need to choose a discovery mechanism suitable for your network.

The examples folder contains code for this example, and other scenarios demonstrating more complex network configurations:

  • local-dev-mesh: local development, including a web service API.
  • multicast-discovery: multicast allows base nodes to discover each other - zero configuration!
  • consul-discovery: base node discovery using a service registry, when multicast is not available.

As a counterpoint to mesh-based configuration, the local-dev example is a reminder of the burden of traditional service location.

Development monitor

You can monitor the status of your local development network using the monitor option:

// monitor.js
Seneca({tag: 'rgb', log: 'silent'})
  .use('mesh', {
    monitor: true
  })

This prints a table of known services to the terminal. Use keys Ctrl-C to quit, and p to prune failed services. In the case of the multicast-discovery example, the monitor will output something like:

Deployment

Seneca-mesh has been tested under the following deployment configurations:

  • Single development machine using localhost (loopback network interface)
  • Multiple machines using VirtualBox (enable host network)
  • Docker containers using host networking (--net="host")
  • Docker swarm using an overlay network (not multicast not supported here by Docker)
  • Amazon Web Services on multiple instances (multicast not supported by Amazon)

See the test and test/docker folders for example code.

See also the [Full system](#Full systems) examples for deployment configurations.

Multicast service discovery is the most desirable from an ease of deployment perspective, as you don't have to do anything - base nodes discover each other, and services discover base nodes. Unfortunately multicast networking is often not supported by the underlying network.

As best-practice deployment model, consider running a least one base node per machine. This provides considerable redundancy for services joining the network.

Base discovery

Once a service has joined the SWIM network, it will find all the other services. SWIM solves that problem for you, which is why it is so awesome.

But you stil have to join the network initially. You can do so by pointing a new service at any other service, and it will "just work". However in practice it is useful to have the concept of a base node that provides bootstrapping functionality as a its primary purpose. The problem then reduces to finding base nodes.

Note: not all base nodes need to alive - you can provide a list of base nodes containing nodes that are down. SWIM will continue anyway so long as at least one node is up.

Seneca-mesh provides the following strategies:

  • defined: the base nodes are pre-defined and provided to the service via configuration or environment variables. This is no worse than having other kinds of well-known services in your system, such as databases. By following a consistent approach you can provide a list of nodes dynamically - e.g. using the AWS CLI to list all instances in your VPC (aws ec2 describe-instances).

  • custom: you can provide a custom function that returns a list of bases, resolved by your own custom approach.

  • registry: load the list of bases from a key-value registry such as Consul. This strategy leverages the seneca-registry set of plugins, so you can use not only consul, but also etcd, ZooKeeper, and so on.

  • multicast: base nodes broadcast their existence via IP multicast. New services briefly listen to the broadcast to get the list of base nodes, and then drop out. This keeps broadcast traffic to a minimum. Note: you need to get the broadcast address right for your network - time to run ifconfig -a!

  • guess: If a base node is running locally, then the service can find it by searching at the default location: UDP 127.0.0.1:39999. If you've specified a different IP for the service to bind to, then that IP will also be checked. This is the usual mode for local development.

The strategies are executed in the order listed above. By default, seneca-mesh only moves onto the next strategy if the current one failed to produce any bases (this is configurable).

Message flows

Each service speficies the messages patterns that it cares about using the pin setting. As a convenience, you can use pin at the top level of the options, however the more complete form is an array of patterns specifications listed in the listen option.

Thus

seneca.use('mesh', {
  pin: 'foo:bar'
})

is equivalent to:

seneca.use('mesh', {
  listen: [
    {pin: 'foo:bar'}
  ]
})

Each entry in the listen array specifies the listening models for a given pattern. In particular, you can specify that the listening model:

  • consume: assume the message is from a work queue; consume the message, and generate a reply. This is the default.
  • observe: assume the message is published to multiple services; do not generate a reply

As an example, consider a microservice that generates HTML content. The get:content message expects a reply containing the HTML content, and is intended for just one instance of the service, to avoid redundant work. The clear:cache message is published to all instances of the service to indicate that underlying data for the HTML content has changed, and the content must be regenerated for the next get:content message. Define the mesh patterns as follows:

seneca.use('mesh', {
  listen: [
    {pin: 'get:content'}, // model:consume; the default
    {pin: 'clear:cache', model:'observe'}
  ]
})

Seneca-mesh uses the HTTP transport by default. To use other transports, you can add additional options to each entry of the listen array. These options are passed to the transport system as if you have called seneca.listen directly:

seneca.use('redis-transport')
seneca.use('mesh', {
  listen: [
    {pin: 'get:content'}, // model:consume; the default
    {pin: 'clear:cache', model:'observe', type:'redis'}
  ]
})

Message Patterns

role:mesh,get:members

You can send this message to any node, and the response will be a list of all known patterns in the network.

Here's a useful little service that lets you submit messages to the network via a REPL:

require('seneca')({
  tag: 'repl',
  log: { level: 'none' }
})
  .use('mesh')
  .repl({
    port: 10001,
    alias: {
      m: 'role:mesh,get:members'
    }
  })

And on the command line:

# telnet localhost 10001

The alias m can be used as a shortcut.

Options

The seneca-mesh plugin accepts the following set of options. Specify these when loading the plugin:

require('seneca')
    .use('mesh', {
      // options go here
    })

The options are:

  • isbase: Make this node a base node. Default: false.

  • bases: An array of pre-defined base nodes. Specify strings in the format: 'IP:PORT'. Default: [].

  • pin: the action pattern that this service will respond to. Default: null

  • listen: an array of action patterns that this service will respond to. Default: null

  • stop: base node discovery stops as soon as a discovery strategies provides a list of suggested nodes. Default: true

  • discover: define the base node discovery options:

    • defined: use defined base nodes, specified via the bases option.

      • active: activate this discovery strategy. Default: true
    • custom: provide a function with signature function (seneca, options, bases, next) that returns an array of base nodes. See unit test single-custom for an example.

      • active: activate this discovery strategy. Default: true

      • find: the custom function

    • registry: use the role:registry patterns to load the list of base nodes. Set to false to disable. Default is a set of sub-options - see code for details.

      • active: activate this discovery strategy. Default: true
    • multicast: base nodes broadcast their existence via IP multicast. New services briefly listen to the broadcast to get the list of base nodes, and then drop out. This keeps broadcast traffic to a minimum. Note: you need to get the broadcast address right for your network - time to run ifconfig -a!

      • active: activate this discovery strategy. Default: true

      • address: the broadcast address of the network interface used for multicast.

    • guess: Guess the location of a base by assuming it is on the same host. Default: true.

      • active: activate this discovery strategy. Default: true

Full systems

You can review the source code of these example projects to see seneca-mesh in action:

Test

To run tests, use npm:

npm run test

Contributing

The Seneca.js org encourages open and safe participation.

If you feel you can help in any way, be it with documentation, examples, extra testing, or new features please get in touch.

License

Copyright (c) 2015-2016, Richard Rodger and other contributors. Licensed under MIT.

seneca-mesh's People

Contributors

dikarel avatar mcdonnelldean avatar mihaidma avatar rjrodger avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

seneca-mesh's Issues

seneca-mesh fires a warning message 'unknown_message_id' when 'model:observe' is used

This kind of warning message is fired:

2016-11-25T07:11:43.945Z cxr3pi64dn03/1480057900449/9508/- WARN	-	-	ACT	05dvr66o6n8p/jmm290cgl1mb	name:transport,plugin:define,role:seneca,seq:3,tag:undefined	plugin	transport	ACT	g3o0affyihgf/l7h781gglewa	hook:client,role:transport,type:web	client	unknown_message_id	{type:web,port:58218,host:localhost,path:/act,protocol:http,timeout:5555,max_listen_attempts:11,attempt_delay:2	{kind:res,res:{success:true},error:null,sync:true,id:5g2cjv86apgw/ki74z33vk0w5,origin:cxr3pi64dn03/148005790044

package.json

The dependencies used are:

"seneca": "~2.1.0",
"seneca-balance-client": "^0.6.0",
"seneca-mesh": "^0.9.0"

The mesh-base script

First, this basic mesh-base script is started in a terminal:

var seneca = require('seneca')();
seneca.ready(function(err) {
	seneca.use('mesh', {
		isbase: true,
		host: 'localhost'
	});
});

The microservice

The simple test plugin.js is:

module.exports = function plugin(options) {
	var seneca = this;
	seneca.add({role: 'test', cmd: 'test'}, test);
	function test(args, done) {
		console.log('test: ' + JSON.stringify(args));
		done(null, {success: 'true'});
	}
};

And the test microservice is started with this simple script:

const seneca = require('seneca')();
seneca.ready(function(err) {
	seneca
	.use('plugin')
	.use('mesh', {
		host: 'localhost',
		listen: [
			{pin: 'role:test,cmd:test', model: 'observe'}
		]
	});
});

Tests

The test.js script is:

var seneca = require('seneca')();
seneca.ready(function(err) {
	seneca.use('mesh', {
		host: 'localhost'
	});
	seneca.act({role: 'test', cmd: 'test', msg: 'Hello World!'}, (err, done) => {
		if (err) { throw err; }
		console.log('test-mesh done.');
	});
	seneca.close((err) => {
		if (err) { console.log(err); }
		else { console.log('seneca closed.'); }
	});
});

When only one instance of the microservice is running in a terminal, all is fine.
When a second instance of the microservice is running in another terminal, the test script fires one warning message.
And when a third instance is running in another terminal, the test script fires two warning messages.

What can be wrong?

Service not able to find other service after update

Sometimes I'm getting this weird behavior. It doesn't happen all the time, so it's very difficult to reproduce and solve. So, I'd like to know if anyone has clues on it.

Scenario:
Service A is running.
Service B is running.
Service B uses service A.

Steps:
Service B is updated.
Service A is running.
Service B doesn't find Service A anymore (No matching action pattern found for ......)

I restart service A and B
Everything works again

seneca-mesh version: 0.8 (Also tested with prior versions)

Any help would be appreciated.

Thanks

registry-consul not an npm package

hi, trying out the sample example given in "40-consul-discovery" which requires 'registry-consul' npm package, but the package does not exist in the npm repo.
Requesting for assistance to move further with the example.
Thanks

error and warning when using the readme example asyncrhonously

The code:


function base() {
  require('seneca')().use('mesh',{base:true});
}


function server() {
  var senecaServer = require('seneca')();

  senecaServer.use('mesh', { auto:true, pin:'service:fast-service' });

  senecaServer.add({ service:'fast-service', cmd:'hello' }, function (args, callback) {
    callback(null, { hello: 'world' });
  });

  senecaServer.listen();
}

function client() {
  var senecaClient = require('seneca')();

  senecaClient.use('mesh', { auto:true });

  senecaClient.act({service: 'fast-service', cmd: 'hello'}, function(err, result) {
    console.log('************', err, JSON.stringify(result, null, 2));
  });
}


base();
setTimeout(function() {
  server();
  setTimeout(function() {
    client();
  }, 1000);
}, 1000);

The warning and error:

2016-03-03T11:51:47.325Z j2wg59u0ojdc/1457005907058/17970/- WARN    act -           -   -   seneca: No matching action pattern found for { config:    { port: 56317,     model: 'actor',     type: 'web',     host: '0.0.0.0',     path: null,     role: 'transport',     hook: 'listen',     'ungate$': true,     'tx$': 'r5c2s4wvyth8',     'default$': null,     'meta$':       { id: '6p9idoc03oey/r5c2s4wvyth8',        tx: 'r5c2s4wvyth8',        start: 1457005902159,        pattern: 'hook:listen,role:transport,type:web',        action: '(0nlwa)',        entry: true,        chain: [] },     pin: 'role:mesh,base:true' },  role: 'transport',  type: 'balance',  add: 'client' }, and no default result provided (using a default$ property).    act_not_found   {args:{ config:    { port: 56317,     model: 'actor',     type: 'web',     host: '0.0.0.0',     path: null,     Error: seneca: No matching action pattern found for { config:    { port: 56317,     model: 'actor',     type: 'web',     host: '0.0.0.0',     path: null,     role: 'transport',     hook: 'listen',     'ungate$': true,     'tx$': 'r5c2s4wvyth8',     'default$': null,     'meta$':       { id: '6p9idoc03oey/r5c2s4wvyth8',        tx: 'r5c2s4wvyth8',        start: 1457005902159,        pattern: 'hook:listen,role:transport,type:web',        action: '(0nlwa)',        entry: true,        chain: [] },     pin: 'role:mesh,base:true' },  role: 'transport',  type: 'balance',  add: 'client' }, and no default result provided (using a default$ property).
    at Object.errormaker [as error] (/home/nherment/workspace/nearform/seneca-mesh-test/node_modules/eraro/eraro.js:94:15)
    at Object.execute_action [as fn] (/home/nherment/workspace/nearform/seneca-mesh-test/node_modules/seneca/seneca.js:1054:29)
    at Immediate._onImmediate (/home/nherment/workspace/nearform/seneca-mesh-test/node_modules/gate-executor/gate-executor.js:135:14)
    at processImmediate [as _immediateCallback] (timers.js:383:17)
2016-03-03T11:51:47.326Z j2wg59u0ojdc/1457005907058/17970/- ERROR   act -           OUT     -   4   {config:{port:56317,model:actor,type:web,host:0.0.0.0,path:null,role:transport,hook:listen},role:transport,type ENTRY       -   seneca: No matching action pattern found for { config:    { port: 56317,     model: 'actor',     type: 'web',     host: '0.0.0.0',     path: null,     role: 'transport',     hook: 'listen',     'ungate$': true,     'tx$': 'r5c2s4wvyth8',     'default$': null,     'meta$':       { id: '6p9idoc03oey/r5c2s4wvyth8',        tx: 'r5c2s4wvyth8',        start: 1457005902159,        pattern: 'hook:listen,role:transport,type:web',        action: '(0nlwa)',        entry: true,        chain: [] },     pin: 'role:mesh,base:true' },  role: 'transport',  type: 'balance',  add: 'client' }, and no default result provided (using a default$ property).    act_not_found   {args:{ config:    { port: 56317,     model: 'actor',     type: 'web',     host: '0.0.0.0',     path: null,     Error: seneca: No matching action pattern found for { config:    { port: 56317,     model: 'actor',     type: 'web',     host: '0.0.0.0',     path: null,     role: 'transport',     hook: 'listen',     'ungate$': true,     'tx$': 'r5c2s4wvyth8',     'default$': null,     'meta$':       { id: '6p9idoc03oey/r5c2s4wvyth8',        tx: 'r5c2s4wvyth8',        start: 1457005902159,        pattern: 'hook:listen,role:transport,type:web',        action: '(0nlwa)',        entry: true,        chain: [] },     pin: 'role:mesh,base:true' },  role: 'transport',  type: 'balance',  add: 'client' }, and no default result provided (using a default$ property).
    at Object.errormaker [as error] (/home/nherment/workspace/nearform/seneca-mesh-test/node_modules/eraro/eraro.js:94:15)
    at Object.execute_action [as fn] (/home/nherment/workspace/nearform/seneca-mesh-test/node_modules/seneca/seneca.js:1054:29)
    at Immediate._onImmediate (/home/nherment/workspace/nearform/seneca-mesh-test/node_modules/gate-executor/gate-executor.js:135:14)

The full logs:

2016-03-03T11:55:01.379Z rgdjiszwdafm/1457006101362/18028/- INFO    hello   Seneca/1.3.0/rgdjiszwdafm/1457006101362/18028/- 
2016-03-03T11:55:01.747Z rgdjiszwdafm/1457006101362/18028/- INFO    listen  {pin:role:mesh,base:true,model:actor}   
2016-03-03T11:55:02.670Z djsd3vi83wj3/1457006102663/18028/- INFO    hello   Seneca/1.3.0/djsd3vi83wj3/1457006102663/18028/- 
2016-03-03T11:55:02.680Z djsd3vi83wj3/1457006102663/18028/- INFO    listen      
2016-03-03T11:55:02.714Z djsd3vi83wj3/1457006102663/18028/- INFO    listen  {pin:service:fast-service,model:actor}  
2016-03-03T11:55:02.728Z rgdjiszwdafm/1457006101362/18028/- INFO    client  {type:balance,pin:null:true,model:null} 
2016-03-03T11:55:02.730Z rgdjiszwdafm/1457006101362/18028/- INFO    -   -   ACT 2u8eqp2jjrg9/mmiewfp1fb6s   name:mesh,plugin:define,role:seneca,seq:6,tag:undefined plugin  mesh        ACT 0k8japccphpo/l7ed8abr41gh   add:client,role:transport,type:balance  client  {type:web,port:10101,host:0.0.0.0,path:null,role:transport,hook:listen,pin:null:true}   
2016-03-03T11:55:02.928Z djsd3vi83wj3/1457006102663/18028/- INFO    client  {type:balance,pin:role:mesh,base:true,model:actor}  
2016-03-03T11:55:02.937Z djsd3vi83wj3/1457006102663/18028/- WARN    act -           -   -   seneca: No matching action pattern found for { config:    { port: 58056,     model: 'actor',     type: 'web',     host: '0.0.0.0',     path: null,     role: 'transport',     hook: 'listen',     'ungate$': true,     'tx$': 'l7ed8abr41gh',     'default$': null,     'meta$':       { id: 'fbvhig010w9q/l7ed8abr41gh',        tx: 'l7ed8abr41gh',        start: 1457006101759,        pattern: 'hook:listen,role:transport,type:web',        action: '(54z42)',        entry: true,        chain: [] },     pin: 'role:mesh,base:true' },  role: 'transport',  type: 'balance',  add: 'client' }, and no default result provided (using a default$ property).    act_not_found   {args:{ config:    { port: 58056,     model: 'actor',     type: 'web',     host: '0.0.0.0',     path: null,     Error: seneca: No matching action pattern found for { config:    { port: 58056,     model: 'actor',     type: 'web',     host: '0.0.0.0',     path: null,     role: 'transport',     hook: 'listen',     'ungate$': true,     'tx$': 'l7ed8abr41gh',     'default$': null,     'meta$':       { id: 'fbvhig010w9q/l7ed8abr41gh',        tx: 'l7ed8abr41gh',        start: 1457006101759,        pattern: 'hook:listen,role:transport,type:web',        action: '(54z42)',        entry: true,        chain: [] },     pin: 'role:mesh,base:true' },  role: 'transport',  type: 'balance',  add: 'client' }, and no default result provided (using a default$ property).
    at Object.errormaker [as error] (/home/nherment/workspace/nearform/seneca-mesh-test/node_modules/eraro/eraro.js:94:15)
    at Object.execute_action [as fn] (/home/nherment/workspace/nearform/seneca-mesh-test/node_modules/seneca/seneca.js:1054:29)
    at Immediate._onImmediate (/home/nherment/workspace/nearform/seneca-mesh-test/node_modules/gate-executor/gate-executor.js:135:14)
    at processImmediate [as _immediateCallback] (timers.js:383:17)
2016-03-03T11:55:02.938Z djsd3vi83wj3/1457006102663/18028/- ERROR   act -           OUT     -   8   {config:{port:58056,model:actor,type:web,host:0.0.0.0,path:null,role:transport,hook:listen},role:transport,type ENTRY       -   seneca: No matching action pattern found for { config:    { port: 58056,     model: 'actor',     type: 'web',     host: '0.0.0.0',     path: null,     role: 'transport',     hook: 'listen',     'ungate$': true,     'tx$': 'l7ed8abr41gh',     'default$': null,     'meta$':       { id: 'fbvhig010w9q/l7ed8abr41gh',        tx: 'l7ed8abr41gh',        start: 1457006101759,        pattern: 'hook:listen,role:transport,type:web',        action: '(54z42)',        entry: true,        chain: [] },     pin: 'role:mesh,base:true' },  role: 'transport',  type: 'balance',  add: 'client' }, and no default result provided (using a default$ property).    act_not_found   {args:{ config:    { port: 58056,     model: 'actor',     type: 'web',     host: '0.0.0.0',     path: null,     Error: seneca: No matching action pattern found for { config:    { port: 58056,     model: 'actor',     type: 'web',     host: '0.0.0.0',     path: null,     role: 'transport',     hook: 'listen',     'ungate$': true,     'tx$': 'l7ed8abr41gh',     'default$': null,     'meta$':       { id: 'fbvhig010w9q/l7ed8abr41gh',        tx: 'l7ed8abr41gh',        start: 1457006101759,        pattern: 'hook:listen,role:transport,type:web',        action: '(54z42)',        entry: true,        chain: [] },     pin: 'role:mesh,base:true' },  role: 'transport',  type: 'balance',  add: 'client' }, and no default result provided (using a default$ property).
    at Object.errormaker [as error] (/home/nherment/workspace/nearform/seneca-mesh-test/node_modules/eraro/eraro.js:94:15)
    at Object.execute_action [as fn] (/home/nherment/workspace/nearform/seneca-mesh-test/node_modules/seneca/seneca.js:1054:29)
    at Immediate._onImmediate (/home/nherment/workspace/nearform/seneca-mesh-test/node_modules/gate-executor/gate-executor.js:135:14)
    at processImmediate [as _immediateCallback] (timers.js:383:17)  
2016-03-03T11:55:02.950Z rgdjiszwdafm/1457006101362/18028/- INFO    client  {type:balance,pin:service:fast-service,model:actor} 
2016-03-03T11:55:02.953Z rgdjiszwdafm/1457006101362/18028/- INFO    -   -   ACT 2u8eqp2jjrg9/mmiewfp1fb6s   name:mesh,plugin:define,role:seneca,seq:6,tag:undefined plugin  mesh        ACT mrd4z8zo2c6l/l7ed8abr41gh   add:client,role:transport,type:balance  client  {port:58096,model:actor,type:web,host:0.0.0.0,path:null,role:transport,hook:listen} 
2016-03-03T11:55:03.151Z djsd3vi83wj3/1457006102663/18028/- INFO    -   -   ACT z14yu2t9ty1w/gj76f5nw608z   name:mesh,plugin:define,role:seneca,seq:6,tag:undefined plugin  mesh        ACT 9b0kriv5mq5h/8a3e8dlyyi3r   add:client,role:transport,type:balance  client  {port:58056,model:actor,type:web,host:0.0.0.0,path:null,role:transport,hook:listen} 
2016-03-03T11:55:03.708Z ebm75ky3l8mz/1457006103707/18028/- INFO    hello   Seneca/1.3.0/ebm75ky3l8mz/1457006103707/18028/- 
2016-03-03T11:55:03.741Z ebm75ky3l8mz/1457006103707/18028/- INFO    listen  {pin:null,model:actor}  
2016-03-03T11:55:03.749Z rgdjiszwdafm/1457006101362/18028/- INFO    -   -   ACT 2u8eqp2jjrg9/mmiewfp1fb6s   name:mesh,plugin:define,role:seneca,seq:6,tag:undefined plugin  mesh        ACT 8vg8ir7b1w19/l7ed8abr41gh   add:client,role:transport,type:balance  client  {port:50763,model:actor,type:web,host:0.0.0.0,path:null,role:transport,hook:listen} 
2016-03-03T11:55:03.789Z djsd3vi83wj3/1457006102663/18028/- INFO    client  {type:balance,pin:null:true,model:actor}    
2016-03-03T11:55:03.790Z djsd3vi83wj3/1457006102663/18028/- INFO    -   -   ACT z14yu2t9ty1w/gj76f5nw608z   name:mesh,plugin:define,role:seneca,seq:6,tag:undefined plugin  mesh        ACT znxbm1sbxxe5/0xigd5xrfy6l   add:client,role:transport,type:balance  client  {port:50763,model:actor,type:web,host:0.0.0.0,path:null,role:transport,hook:listen} 
2016-03-03T11:55:03.856Z djsd3vi83wj3/1457006102663/18028/- INFO    -   -   ACT z14yu2t9ty1w/gj76f5nw608z   name:mesh,plugin:define,role:seneca,seq:6,tag:undefined plugin  mesh        ACT dskveosphn3e/8a3e8dlyyi3r   add:client,role:transport,type:balance  client  {port:50763,model:actor,type:web,host:0.0.0.0,path:null,role:transport,hook:listen} 
2016-03-03T11:55:03.949Z ebm75ky3l8mz/1457006103707/18028/- INFO    client  {type:balance,pin:null:true,model:null} 
2016-03-03T11:55:03.950Z ebm75ky3l8mz/1457006103707/18028/- INFO    client  {type:balance,pin:service:fast-service,model:actor} 
2016-03-03T11:55:03.951Z ebm75ky3l8mz/1457006103707/18028/- INFO    client  {type:balance,pin:role:mesh,base:true,model:actor}  
2016-03-03T11:55:03.952Z ebm75ky3l8mz/1457006103707/18028/- INFO    -   -   ACT da1p89kvd83s/4k2r3u45qacj   name:mesh,plugin:define,role:seneca,seq:6,tag:undefined plugin  mesh        ACT tnh2xavpd0e8/fnwxwxx48oyr   add:client,role:transport,type:balance  client  {type:web,port:10101,host:0.0.0.0,path:null,role:transport,hook:listen,pin:null:true}   
2016-03-03T11:55:03.953Z ebm75ky3l8mz/1457006103707/18028/- INFO    -   -   ACT da1p89kvd83s/4k2r3u45qacj   name:mesh,plugin:define,role:seneca,seq:6,tag:undefined plugin  mesh        ACT oe9wumbt347w/fnwxwxx48oyr   add:client,role:transport,type:balance  client  {port:58096,model:actor,type:web,host:0.0.0.0,path:null,role:transport,hook:listen} 
2016-03-03T11:55:03.954Z ebm75ky3l8mz/1457006103707/18028/- INFO    -   -   ACT da1p89kvd83s/4k2r3u45qacj   name:mesh,plugin:define,role:seneca,seq:6,tag:undefined plugin  mesh        ACT vzaq4dij74q0/fnwxwxx48oyr   add:client,role:transport,type:balance  client  {port:58056,model:actor,type:web,host:0.0.0.0,path:null,role:transport,hook:listen} 
************ null {
  "hello": "world"
}

Root cause for "Maximum stack size exceeded" error

If different mesh processes use semantically same, but alphabetically different pins then it fails with "Max call stack size exceeded" error

i.e. if 2 processes both have
{auto:true, listen:[{pins:['ns:m,what:a,cmd:u'], model:'publish'}]}
this works

if 1 process has
{auto:true, listen:[{pins:['ns:m,what:a,cmd:u'], model:'publish'}]}
and another one has
{auto:true, listen:[{pins:['ns:m,cmd:u,what:a'], model:'publish'}]}
It fails with the error above!!!

Auto argument

Is not documented the utility of using auto and the effect with other arguments as setting the bases

When number and length of pattern fields exceed certain number, the mesh with multiple pins does not work

Here is the example

Server

!/opt/local/bin/node

require('seneca')()
//.use('mesh', {auto:true, listen:[ {pins:['ns:mmmmm,app:coi,cmd:fetch,ds:ba,w:a123456', 'ns:mmmmm,app:coi,cmd:publish,ds:ba,w:a123456'], model:'publish'}]})
.use('mesh', {auto:true, listen:[ {pins:['ns:mmmmm,app:coi,cmd:fetch,ds:ba,w:a12345', 'ns:mmmmm,app:coi,cmd:publish,ds:ba,w:a12345'], model:'publish'}]})
.ready(function(){
var s = this;
//s.add('ns:mmmmm,app:coi,cmd:fetch,ds:ba,w:a123456', function(msg, done){
s.add('ns:mmmmm,app:coi,cmd:fetch,ds:ba,w:a12345', function(msg, done){
console.log('Server|Fetch|Message: ' + JSON.stringify(msg));
done(null, {status:'ok', one:'fetch'});
});
//s.add('ns:mmmmm,app:coi,cmd:publish,ds:ba,w:a123456', function(msg, done){
s.add('ns:mmmmm,app:coi,cmd:publish,ds:ba,w:a12345', function(msg, done){
console.log('Server|Publish|Message: ' + JSON.stringify(msg));
done(null, {status:'ok', another:'publish'});
});
})
.listen({port:6666})

seneca-mesh install fails at node-gyp rebuid

i have the latest build of npm and node.js installed but i get the following error.

[email protected] install /root/Desktop/node progs/node_modules/farmhash
node-gyp rebuild

gyp WARN install got an error, rolling back install
gyp ERR! configure error
gyp ERR! stack Error: tunneling socket could not be established, cause=connect ETIMEDOUT 92.242.132.27:6050
gyp ERR! stack at ClientRequest.onError (/usr/local/lib/node_modules/npm/node_modules/request/node_modules/tunnel-agent/index.js:176:17)
gyp ERR! stack at ClientRequest.g (events.js:260:16)
gyp ERR! stack at emitOne (events.js:77:13)
gyp ERR! stack at ClientRequest.emit (events.js:169:7)
gyp ERR! stack at Socket.socketErrorListener (_http_client.js:269:9)

npm ERR! [email protected] install: node-gyp rebuild
npm ERR! Exit status 1
npm ERR!
npm ERR! Failed at the [email protected] install script 'node-gyp rebuild'.
npm ERR! Make sure you have the latest version of node.js and npm installed.
npm ERR! If you do, this is most likely a problem with the farmhash package,
npm ERR! not with npm itself.
npm ERR! Tell the author that this fails on your system:
npm ERR! node-gyp rebuild

The plugin does not work in windows system

In windows 7, service can't register into base service with the plugin. bug is in the join function in source code, add config.host = options.host; works well.

function join( instance, config, done ) {
config = config || {}

if( !config.pin ) {
  config.pin = 'null:true'
}


var host = options.host + ( options.port ? 
                           ':'+(_.isFunction(options.port) ? 
                                options.port() : options.port ) : '' )

config.host = options.host;
var meta = {
  who: host,
  listen: config,
  instance: instance.id
}

Will this plugin work with transport different than http?

I looked at the source code and did not find anything bound to http.

But, does it have any architectural/whatever contraints that prevent using it with other transport?
I am particularly interested in seneca-amqp-transport of seneca-rabbitmq-transport

Security

I've been learning about Node, Seneca, and Microservices. Couldn't figure out how to create dynamic references to the network location of services, found Rodger's blog, and ended up here!

For some reason, I don't have the ability to tag this as a question, but a key question I have is about security with SWARM and Mesh. This may be an idiotic questions, but I'm guessing this approach assumes that all the services operate in a private network (with maybe 1 public gateway)? I have a very vague understanding of the protocol, but my next area I find confusing is how to keep services you don't create from being added into the picture. Please feel free to let me know if there's a better venue to ask this question!

new version release

hey, I was about to provide a PR to ignore the duplicates. Then I saw that you already fixed it yesterday ๐Ÿ˜„
I just tested it and it would be awesome if you could publish those changes.

Many thanks!

Quick Example doesn't work

Trying to run the quick example on Windows 8.1 Pro and the client explodes with this error (the server started successfully with no errors):

D:\Git\seneca-test>node src/color-client.js
{"notice":"seneca: No matching action pattern found for { format: 'hex', color: 'red' }, and no default result provided (using a default$ property).",
"code":"act_not_found","err":{"eraro":true,"orig":null,"code":"act_not_found","seneca":true,"package":"seneca","msg":"seneca: No matching action patte
rn found for { format: 'hex', color: 'red' }, and no default result provided (using a default$ property).","details":{"args":"{ format: 'hex', color:
'red' }","plugin":{}},"callpoint":"at executable_action (D:\\Git\\seneca-test\\node_modules\\seneca\\seneca.js:1155:23)"},"msg":{"format":"hex","color
":"red"},"entry":true,"prior":[],"meta":{},"listen":false,"transport":{},"kind":"act","case":"ERR","duration":526,"level":"error","seneca":"it88c872hr
o3/1474354122861/412784/3.1.0/-","when":1474354123731}
{"msg":{"format":"hex","color":"red"},"entry":true,"prior":[],"meta":{},"listen":false,"transport":{},"kind":"act","case":"ERR","info":"seneca: Action
 undefined callback threw: Cannot read property 'color' of undefined.","code":"act_callback","err":{"eraro":true,"orig":{},"code":"act_callback","sene
ca":true,"package":"seneca","msg":"seneca: Action undefined callback threw: Cannot read property 'color' of undefined.","details":{"message":"Cannot r
ead property 'color' of undefined","instance":"Seneca/it88c872hro3/1474354122861/412784/3.1.0/-","orig$":{},"message$":"Cannot read property 'color' o
f undefined","plugin":{}},"callpoint":"at Seneca.<anonymous> (D:\\Git\\seneca-test\\src\\color-client.js:18:20)"},"duration":526,"level":"error","sene
ca":"it88c872hro3/1474354122861/412784/3.1.0/-","when":1474354123738}

package.json below:

{
  "name": "seneca-test",
  "version": "0.0.1",
  "private": true,
  "scripts": {
  },
  "devDependencies": {
    "seneca": "^3.0.0",
    "seneca-balance-client": "^0.6.0",
    "seneca-mesh": "^0.9.0"
  }
}

Is there something special I need to do on a Windows machine?

Seneca-mesh on default http transport fails after ~2000 acts

Seneca mesh fails after "processing" ~2000 acts.

Part of "benchmarking code":

seneca()
  .use('consul-registry', {
    host: '127.0.0.1'
  })
  .use('mesh', {
    discover: {
      multicast: {
        active: false
      }
    }
  })
  .ready(function () {
    var counter = 0;
    var self = this;
    console.time('bench act');
    for (var i = 0; i < 10000; i++) {
      self.act({
          role: 'service',
          type: 'number',
          action: 'getNumber'
        },
        function (err, out) {
          // do nothing
          counter++;
          if (counter % 500 === 0) {
            console.log(`${counter} processed`);
          }
          if (counter === 10000) {
            console.timeEnd('bench act');
          }
        });
    }
  });

and then it starts failing with:

["client","invalid_origin",{"type":"web","port":59003,"host":"0.0.0.0","path":"/act","protocol":"http","timeout":5555,"max_listen_attempts":11,"attempt_delay":222,"serverOptions":{},"model":"actor","msgprefix":"seneca_","callmax":111111,"msgidlen":12,"role":"transport","hook":"client","pin":"role:service","id":"attempt_delay:222,callmax:111111,hook:listen,host:0.0.0.0,max_listen_attempts:11,model:actor,msgidlen:12,msgprefix:seneca_,path:/act,pin:role:service,port:59003,protocol:http,role:transport,serverOptions:[object Object],timeout:5555,type:web~hb9410is6epb/1474980457178/10366/3.1.0/number-service~role:service~1474980457554","pg":"role:service","plugin$":{"name":"mesh","tag":"-"},"tx$":"18tk7y23et5w","fatal$":true,"meta$":{"id":"8f0fgu095vi4/18tk7y23et5w","tx":"18tk7y23et5w","start":1474986134519,"pattern":"hook:client,role:transport,type:web","action":"(12o83d2799i9)","entry":true,"chain":[],"sync":true,"plugin_name":"transport","plugin_tag":"-"}},{"kind":"res","res":null,"error":{"isBoom":true,"isServer":true,"output":{"statusCode":504,"payload":{"statusCode":504,"error":"Gateway Time-out","message":"Client request timeout"},"headers":{}}},"sync":true,"time":{"client_recv":1474986140931}}]

Deployment inside Docker container

Hi,

Could you please guide me as how to deploy this inside Docker container. I mean in case of Docker deployment do i need to manually assign host, bases, port etc or it can automatically detect ?

Regards,

  • Manoj

Message: seneca: use-plugin: Could not load plugin mesh defined in seneca-mesh due to error: %1 is n ot a valid Win32 application.

Not sure if this is a duplicate but this appears to be a different issue with the existing issue/bug stating that the plugin does not work in windows. #3

I tried running the quick examples in the readme section but I was given the following error.

Message: seneca: use-plugin: Could not load plugin mesh defined in seneca-mesh due to error: %1 is n
ot a valid Win32 application.
?\C:\Users\sarriola\node_modules\farmhash\build\Release\farmhash.node.

Code: plugin_load_failed

Details: { 'orig$':
{ Error: use-plugin: Could not load plugin mesh defined in seneca-mesh due to error: %1 is not a
valid Win32 application.

sample code doesn't work on mac

I just run the color example from the doc, but it doesn't work.

This is the output from color-service.js:
{"kind":"notice","notice":"hello seneca ymghac9vx8nt/1478268430479/13374/3.2.2/-","level":"info","when":1478268430555}
{"kind":"mesh","bases":["127.0.0.1:39999"],"options":{"isbase":true,"pin":"format:hex","model":"actor","auto":true,"discover":{"defined":{"active":true},"guess":{"active":true},"multicast":{"active":true,"address":null,"max_search":22,"search_interval":111},"registry":{"active":true,"refresh_interval":1111,"prune_first_probability":0.01,"prune_bound":11},"custom":{"active":true},"stop":true},"dumpnet":false,"sneeze":null},"level":"info","actid":"l8tlpr7eic9t/3dnr73hsp2uh","plugin_name":"mesh","pattern":"name:mesh,plugin:define,role:seneca,seq:2,tag:undefined","when":1478268433700}

This is the output from color-client.js:
{"kind":"notice","notice":"hello seneca dylr1bgbpode/1478268441913/13376/3.2.2/-","level":"info","when":1478268441980}
{"kind":"mesh","bases":["127.0.0.1:39999"],"options":{"isbase":false,"model":"actor","auto":true,"discover":{"defined":{"active":true},"guess":{"active":true},"multicast":{"active":true,"address":null,"max_search":22,"search_interval":111},"registry":{"active":true,"refresh_interval":1111,"prune_first_probability":0.01,"prune_bound":11},"custom":{"active":true},"stop":true},"dumpnet":false,"sneeze":null},"level":"info","actid":"q7vs7uhkm7sm/exg0widcdsxj","plugin_name":"mesh","pattern":"name:mesh,plugin:define,role:seneca,seq:2,tag:undefined","when":1478268443034}
{"err":{},"level":"warn","when":1478268443057}
{"notice":"seneca: No matching action pattern found for { format: 'hex', color: 'red' }, and no default result provided (using a default$ property).","code":"act_not_found","err":{"eraro":true,"orig":null,"code":"act_not_found","seneca":true,"package":"seneca","msg":"seneca: No matching action pattern found for { format: 'hex', color: 'red' }, and no default result provided (using a default$ property).","details":{"args":"{ format: 'hex', color: 'red' }","plugin":{}},"callpoint":"at handle_inward_break (/Users/cxwcfea/Myfiles/code/node/micro_services/node_modules/seneca/seneca.js:1155:23)"},"actid":"byqbu4mt5daa/p4m8mygf37fs","msg":{"format":"hex","color":"red","meta$":{"id":"byqbu4mt5daa/p4m8mygf37fs","tx":"p4m8mygf37fs"}},"meta":{},"listen":false,"transport":{},"kind":"act","case":"ERR","duration":786,"level":"error","when":1478268443058}
{"actid":"byqbu4mt5daa/p4m8mygf37fs","msg":{"format":"hex","color":"red","meta$":{"id":"byqbu4mt5daa/p4m8mygf37fs","tx":"p4m8mygf37fs"}},"meta":{},"listen":false,"transport":{},"kind":"act","case":"ERR","info":"seneca: Action undefined callback threw: Cannot read property 'color' of undefined.","code":"act_callback","err":{"eraro":true,"orig":{},"code":"act_callback","seneca":true,"package":"seneca","msg":"seneca: Action undefined callback threw: Cannot read property 'color' of undefined.","details":{"message":"Cannot read property 'color' of undefined","instance":"Seneca/dylr1bgbpode/1478268441913/13376/3.2.2/-","orig$":{},"message$":"Cannot read property 'color' of undefined","plugin":{}},"callpoint":"at Seneca. (/Users/cxwcfea/Myfiles/code/node/micro_services/test.js:6:20)"},"duration":786,"level":"error","when":1478268443061}

MacOS version: 10.12.1
Node version: v5.9.0
seneca version: 3.2.2
seneca-mesh: 0.9.0

Could not load plugin mesh defined in seneca-mesh as a require call inside the plugin

I am trying to install Seneca mesh but I get an error:

Seneca Fatal Error
==================
Message: seneca: use-plugin: Could not load plugin mesh defined in seneca-mesh as a require call inside the plugin (or a module required by the plugin) failed: Error: Cannot find module '/root/gmh-backend-solution/node_modules/msgpack/lib/../build/Release/msgpackBinding' at Function._load (/usr/local/lib/node_modules/pm2/node_modules/pmx/lib/transaction.js:62:21) at require (internal/module.js:20:19) at Object. (/root/gmh-backend-solution/node_modules/msgpack/lib/msgpack.js:6:14).

Needless to say that the mesh is not starting at all...

Running on node v6.6

I got this error

{"actid":"ovlusnyo3je3/ry6yiqc31j49","msg":{"type":"web","host":"0.0.0.0","path":"/act","protocol":"http","timeout":5555,"max_listen_attempts":11,"attempt_delay":222,"serverOptions":{},"pin":"salestax","model":"actor","msgprefix":"seneca_","callmax":111111,"msgidlen":12,"role":"transport","hook":"listen","plugin$":{"name":"mesh","tag":"-"},"tx$":"ry6yiqc31j49","meta$":{"id":"z1guu98rgcsg/ry6yiqc31j49","tx":"ry6yiqc31j49","pattern":"hook:listen,role:transport,type:web","action":"(aax0e24x8tol)","plugin_name":"transport","plugin_tag":"-","prior":{"chain":[],"entry":true,"depth":0},"start":1482487829534,"sync":true}},"entry":true,"prior":[],"meta":{"plugin_name":"transport","plugin_tag":"-","plugin_fullname":"transport","raw":{"role":"transport","hook":"listen","type":"web"},"sub":false,"client":false,"args":{"role":"transport","hook":"listen","type":"web"},"rules":{},"id":"(aax0e24x8tol)","pattern":"hook:listen,role:transport,type:web","msgcanon":{"hook":"listen","role":"transport","type":"web"},"priorpath":""},"client":false,"listen":false,"transport":{},"kind":"act","case":"ERR","info":"Expected \":\" but \"}\" found.","code":"act_callback","err":{"expected":[{"type":"literal","value":":","description":"\":\""}],"found":"}","offset":9,"line":1,"column":10,"name":"SyntaxError","eraro":true,"orig":{"message":"Expected \":\" but \"}\" found.","expected":[{"type":"literal","value":":","description":"\":\""}],"found":"}","offset":9,"line":1,"column":10,"name":"SyntaxError"},"code":"act_callback","seneca":true,"package":"seneca","msg":"seneca: Action hook:listen,role:transport,type:web callback threw: Expected \":\" but \"}\" found..","details":{"message":"Expected \":\" but \"}\" found.","pattern":"hook:listen,role:transport,type:web","instance":"Seneca/3zsswehvo3im/1482487829211/40722/3.2.2/-","orig$":{"message":"Expected \":\" but \"}\" found.","expected":[{"type":"literal","value":":","description":"\":\""}],"found":"}","offset":9,"line":1,"column":10,"name":"SyntaxError"},"message$":"Expected \":\" but \"}\" found.","plugin":{}},"callpoint":""},"duration":13,"level":"error","plugin_name":"transport","plugin_tag":"-","pattern":"cmd:listen,role:transport","when":1482487829552}

running a very simple service of mine

const seneca = require('seneca')()


seneca.add({cmd: 'salestax'}, function (msg, done) {
  var rate  = 0.23
  var total = msg.net * (1 + rate)
  console.log('Calculating ', msg.net)
  done(null, {total: total})
})

seneca.use('mesh', {
  isbase: true,
  pin: 'salestax'
})

Well known entrypoint

@rjrodger

So here is something stupidly nice. It turns out you can cURL or used postman on any node in the mesh and get back a valid response. This means you can pretty much manipulate the whole system from a single point. Epic right!

With this in mind, is there a way to have a well known point for accessing a mesh system. This could be configurable but it would be nice if you could set a single port as an 'entrypoint' basically it would just funnel the input via standard transport channels.

The other option is if you exposed a pattern to call to get all the current nodes. That way I could call this periodically on the base node and have it periodically emit the ports to logs (since it's not doing anything else anyway).

But for sure this works, I've tried all patterns on about 10 different ports now (that I know are meshed) and it works.

Connection between nodes is not stable

@rjrodger:

Using mesh in Concorda project.

when concorda-dashboard is using Concorda as microservice I have this problem:

  • first requests are correctly executed. After some requests (2-3) the connection is broken:

on Concorda-dashboard I have this error:

2016-02-19T11:33:28.632Z ma19ai76clxz/1455881573489/30993/- DEBUG   act web         IN  fb6gkr6nw6l0/ep267xz3c2on   do:startware,role:web   {req:{domain:{domain:null,_events:{},_eventsCount:1,_maxListeners:null,members:[],_disposed:null},_events:{},_e ENTRY   (r4qzf) -   -   -   
2016-02-19T11:33:28.635Z ma19ai76clxz/1455881573489/30993/- DEBUG   act web         OUT fb6gkr6nw6l0/ep267xz3c2on   do:startware,role:web   null    EXIT    (r4qzf) -   -   3   -   
2016-02-19T11:33:28.637Z ma19ai76clxz/1455881573489/30993/- DEBUG   act concorda    IN  8apwys7bruk3/ep267xz3c2on   cmd:publicGetClient,role:concorda   {clientName:Concorda,cmd:publicGetClient,role:concorda} ENTRY   (dumhh) -   --  
2016-02-19T11:33:28.639Z ma19ai76clxz/1455881573489/30993/- DEBUG   act client$         IN  gu5hgprltht8/9ufh57zbmgyd   role:concorda-communication {clientName:Concorda,cmd:publicGetClient,role:concorda-communication}   ENTRY   (6sgym)CLIENT   -   -   
2016-02-19T11:33:28.641Z ma19ai76clxz/1455881573489/30993/- DEBUG   -   -   ACT gu37hjxfbldx/9ufh57zbmgyd   name:seneca-8t2tjw,plugin:define,role:seneca,seq:6,tag:undefined    plugin  concorda    ACT va6abcmuqse8/9ufh57zbmgyd   name:balance-client,plugin:define,role:seneca,seq:10,tag:mesh~quxg7l    plugin  balance-client/mesh~quxg7l  client  send    seneca_role_concorda_communication__res {type:balance,pin:role: concorda-communication,model:actor,id:kgi61q,role:transport,hook:client}    {did:(abtjg),fixedargs:{},context:{module:{id:/home/malex/workspace/nearForm/concorda-dashboard/node_modules/ch
2016-02-19T11:33:28.649Z ma19ai76clxz/1455881573489/30993/- ERROR   act client$         OUT     role:concorda-communication 9   {clientName:Concorda,cmd:publicGetClient,role:concorda-communication}   ENTRY   (6sgym) -   seneca: no-target   no-target   {plugin:{}} Error: seneca: no-target
    at errormaker (/home/malex/workspace/nearForm/concorda-dashboard/node_modules/eraro/eraro.js:94:15)
    at Seneca.<anonymous> (/home/malex/workspace/nearForm/concorda-dashboard/node_modules/seneca-balance-client/balance-client.js:159:27)
    at /home/malex/workspace/nearForm/concorda-dashboard/node_modules/seneca-transport/lib/transport-utils.js:305:14
    at /home/malex/workspace/nearForm/concorda-dashboard/node_modules/seneca-transport/lib/transport-utils.js:355:7
    at make_send (/home/malex/workspace/nearForm/concorda-dashboard/node_modules/seneca-balance-client/balance-client.js:150:7)
    at /home/malex/workspace/nearForm/concorda-dashboard/node_modules/seneca-transport/lib/transport-utils.js:350:5
    at Seneca.client.send (/home/malex/workspace/nearForm/concorda-dashboard/node_modules/seneca-transport/lib/transport-utils.js:301:7)
    at Seneca.transport_client (/home/malex/workspace/nearForm/concorda-dashboard/node_modules/chairo/node_modules/seneca/lib/transport.js:88:25)
    at actorModel (/home/malex/workspace/nearForm/concorda-dashboard/node_modules/seneca-balance-client/balance-client.js:197:27)
    at Seneca.<anonymous> (/home/malex/workspace/nearForm/concorda-dashboard/node_modules/seneca-balance-client/balance-client.js:155:11)   
2016-02-19T11:33:28.651Z ma19ai76clxz/1455881573489/30993/- FATAL   -   -   ACT gu37hjxfbldx/9ufh57zbmgyd   name:seneca-8t2tjw,plugin:define,role:seneca,seq:6,tag:undefined    plugin  concorda    ACT zt83y62rkmwa/9ufh57zbmgyd   name:seneca-l1uklt,plugin:define,role:seneca,seq:8,tag:undefined    plugin  concorda-core-redirect  sys seneca  1.1.0   ma19ai76clxz/1455881573489/30993/-  no-target   seneca: no-target   {plugin:{}} all-errors-fatal

On the other mesh node I have this:

  • when request was correctly executed:
2016-02-19T11:33:16.952Z k2m4xbhk51te/1455881433977/30874/- DEBUG   act concorda    IN  5usv479rayo8/9ufh57zbmgyd   role:concorda-communication {clientName:Concorda,cmd:publicGetClient,role:concorda-communication}   ENTRY   (d4od5) LISTEN  ma19ai76clxz/1455881573489/30993/-  -   
2016-02-19T11:33:16.953Z k2m4xbhk51te/1455881433977/30874/- DEBUG   act concorda    IN  toycmdf95r6o/2cnaueltp16l   cmd:publicGetClient,role:concorda   {clientName:Concorda,cmd:publicGetClient,role:concorda} ENTRY   (u4k1w) LISTEN  ma19ai76clxz/1455881573489/30993/-  -   
2016-02-19T11:33:16.955Z k2m4xbhk51te/1455881433977/30874/- DEBUG   act mem-store/1 IN  zqnr8n3oepqm/2cnaueltp16l   cmd:load,role:entity    {qent:{},q:{name:Concorda},cmd:load,role:entity,ent:{},name:data,base:client,zone:null} ENTRY   (hs5rn) -   -   -   
2016-02-19T11:33:16.956Z k2m4xbhk51te/1455881433977/30874/- DEBUG   -   -   ACT qopisddi4yg4/1qadqqfhjo4u   name:seneca-4prqnu,plugin:define,role:seneca,seq:2,tag:undefined    plugin  mem-store/1ACT  zqnr8n3oepqm/2cnaueltp16l   cmd:load,role:entity    load    {name:Concorda} -/client/data   {name:Concorda,configured:false,id:i7nrc7}  mem-store~1~-/-/-
2016-02-19T11:33:16.957Z k2m4xbhk51te/1455881433977/30874/- DEBUG   act mem-store/1 OUT zqnr8n3oepqm/2cnaueltp16l   cmd:load,role:entity    {name:Concorda,configured:false,id:i7nrc7}  EXIT    (hs5rn) -   -   2   -   
2016-02-19T11:33:16.958Z k2m4xbhk51te/1455881433977/30874/- DEBUG   act concorda    OUT toycmdf95r6o/2cnaueltp16l   cmd:publicGetClient,role:concorda   {ok:true,data:{name:Concorda,configured:false,id:i7nrc7}}   EXIT    (u4k1w) LISTEN  ma19ai76clxz/1455881573489/30993/-  5   -   
2016-02-19T11:33:16.958Z k2m4xbhk51te/1455881433977/30874/- DEBUG   act concorda    OUT 5usv479rayo8/9ufh57zbmgyd   role:concorda-communication {ok:true,data:{name:Concorda,configured:false,id:i7nrc7}}   EXIT    (d4od5) LISTEN  ma19ai76clxz/1455881573489/30993/-  6   -
  • when request was not OK
2016-02-19T11:33:28.853Z k2m4xbhk51te/1455881433977/30874/- DEBUG   act balance-client/mesh~ukatseIN    hfu2as82lpu0/0a6rnjlfikou   remove:client,role:transport,type:balance   {config:{port:58172,model:actor,type:web,host:0.0.0.0,path:null,role:transport,hook:listen},role:transport,type ENTRY   (68sj7) -   -   -   
2016-02-19T11:33:28.855Z k2m4xbhk51te/1455881433977/30874/- DEBUG   act balance-client/mesh~ukatseOUT   hfu2as82lpu0/0a6rnjlfikou   remove:client,role:transport,type:balance   null    EXIT    (68sj7) -   -   3   -   
2016-02-19T11:33:29.001Z k2m4xbhk51te/1455881433977/30874/- DEBUG   act balance-client/mesh~ukatseIN    49xn26hguhf0/0a6rnjlfikou   remove:client,role:transport,type:balance   {config:{port:58948,model:actor,type:web,host:0.0.0.0,path:null,role:transport,hook:listen},role:transport,type ENTRY   (68sj7) -   -   -   
2016-02-19T11:33:29.002Z k2m4xbhk51te/1455881433977/30874/- DEBUG   act balance-client/mesh~ukatseOUT   49xn26hguhf0/0a6rnjlfikou   remove:client,role:transport,type:balance   null    EXIT    (68sj7) -   -   2   -   
2016-02-19T11:33:29.076Z k2m4xbhk51te/1455881433977/30874/- DEBUG   act balance-client/mesh~ukatseIN    rekeagu97euf/0a6rnjlfikou   remove:client,role:transport,type:balance   {config:{pin:null:true},role:transport,type:balance,remove:client}  ENTRY   (68sj7) -   -   -   
2016-02-19T11:33:29.078Z k2m4xbhk51te/1455881433977/30874/- DEBUG   act balance-client/mesh~ukatseOUT   rekeagu97euf/0a6rnjlfikou   remove:client,role:transport,type:balance   null    EXIT    (68sj7) -   -   2   -

Question: meshing multiple pins

@rjrodger I'm trying to play with more complex meshing. I have a number of services that now do point to point, plus listen, plus publish. I'd trying to figure out which way I define these so that they correctly publish or run point to point. I know how to make all or none, one or the other, but not how to define pins in the granular context below.

Service A

role:foo, info:bar <-- I want to publish this to anyone who cares
role:foo <-- Except the pin above I want to handle these point to point
role:zig <-- I want to listen and respond point to point

Service B

role:foo, info:bar <-- I'm on of the services that cares about this message
role:zig, cmd: * <-- I'm going to send a bunch of these to service A point to point
role:zen <-- I want to handle any messages that match point to point
roles:zen, info:* <-- I want to publish these to anyone who cares

tcp transport does not seem to work

Hello,

As I understood the default protocol being used is http/web.
I am not sure if I am using correct parameters to override transport type or there is special way to configure balance client.

So please let me know.

I tried this example (https://github.com/rjrodger/seneca-mesh/tree/master/examples/05-readme) to see if they work with tcp by using global option --seneca.options.transport.type=tcp:

node color-service.js --seneca.options.transport.type=tcp
node color-client.js --seneca.options.transport.type=tcp

And I got an error:

2016-08-02T23:17:39.170Z 9wx044423wo2/1470179857112/31088/- ERROR   act -           OUT     -   1722    {format:hex,color:red}  ENTRY       -   seneca: No matching action pattern found for { format: 'hex', color: 'red' }, and no default result provided (using a default$ property).   act_not_found   {args:{ format: 'hex', color: 'red' },plugin:{}}    Error: seneca: No matching action pattern found for { format: 'hex', color: 'red' }, and no default result provided (using a default$ property).
    at Object.errormaker [as error] (/Users/dsemenov/Views/seneca-mesh/node_modules/seneca/node_modules/eraro/eraro.js:94:15)
    at Object.execute_action [as fn] (/Users/dsemenov/Views/seneca-mesh/node_modules/seneca/seneca.js:1102:25)
    at Immediate._onImmediate (/Users/dsemenov/Views/seneca-mesh/node_modules/seneca/node_modules/gate-executor/gate-executor.js:136:14)
    at processImmediate [as _immediateCallback] (timers.js:383:17)

It works with default transport.

Thanks,
Dmytro

Not working with different transports

Hi, I try to use it with different transports like amqp, redis, tcp and not get working properly.

  • TPC: It send message, but seneca-transport has declared non close issue with tcp. After a restart of node it fail.
  • AMQP/REDIS: With both of this same issue, no matching pattern bla bla...

To check this I use your examples on 30-multicast-discovery.

I'm really new on this of seneca and maybe lose something.

Can you check this? I'm working on a fork to help you with examples because are not working as is.

Regards.

Question: Correct way to defer acts until available

@rjrodger

When I spin up a service I use mesh to add a user via seneca-user's register method. Right now I need to add a timeout of around 3 seconds to ensure this happens. The problem seems to be the variable amount of time it takes for services to mesh together (I don't think it actually takes 3 seconds, it's just a safe bet). I assume we can never reliably depend on timeouts since network and mesh size are variable.

Is there a hook in mesh that I could take advantage off to emit when a pin is available or gets meshed? I don't mind adding this in myself.

Or as an alternative, what recipes do you recommend that don't depend on timeouts?

no longer works with currently released seneca

The currently released version of this package is dependent on seneca master branch.

This is the error:

seneca: Action cmd:listen,role:transport callback threw: seneca.util.pincanon is not a function.    act_callback    {message:seneca.util.pincanon is not a function,pattern:cmd:listen,role:transport,instance:Seneca/1.3.0/4v/-,pl TypeError: seneca.util.pincanon is not a function
    at join (/Users/adrian/Projects/nearform/nodezoo-search/node_modules/seneca-mesh/mesh.js:95:19)
    at Seneca.<anonymous> (/Users/adrian/Projects/nearform/nodezoo-search/node_modules/seneca-mesh/mesh.js:78:7)
    at act_done (/Users/adrian/Projects/nearform/nodezoo-search/node_modules/seneca/seneca.js:1220:21)
    at Seneca.<anonymous> (/Users/adrian/Projects/nearform/nodezoo-search/node_modules/seneca/node_modules/gate-executor/gate-executor.js:155:20)
    at act_done (/Users/adrian/Projects/nearform/nodezoo-search/node_modules/seneca/seneca.js:1220:21)
    at /Users/adrian/Projects/nearform/nodezoo-search/node_modules/seneca/node_modules/gate-executor/gate-executor.js:155:20
    at Server.<anonymous> (/Users/adrian/Projects/nearform/nodezoo-search/node_modules/seneca/node_modules/seneca-transport/lib/http.js:52:7)
    at emitNone (events.js:67:13)
    at Server.emit (events.js:166:7)
    at emitListeningNT (net.js:1262:10) 

Client won't pick up the local service first when I have two base node.

I have two base node on two different machine and let them build the same services.
I use the client to connect base1 on machine1 and call the service, I expect the called services will be the local one (mean machine1), but it's machine2.
Did I lost some setting?

*## Base1 & service "foo:1" on machine1 *

require('seneca')()  .add( 'foo:1', function (msg, done) {
done( null, {x:1,v:100+msg.v} )})
 .use('mesh',
  {pin:'foo:1',
   isbase:true,
   host: ip1,
   port: port1,
   bases:[ip2:port2]
  })

*## Base2 & service "foo:1" on machine2 *

require('seneca')()  .add( 'foo:1', function (msg, done) {
done( null, {x:1,v:100+msg.v} )})
 .use('mesh',
  {pin:'foo:1',
   isbase:true,
   host: ip2,
   port: port2,
   bases:[ip1:port1]
  })

## Client on machine1 "

require('seneca')()
 .use('mesh', {  host: 'ip1',  bases:[ip1:port1,ip2:port2] })
  .ready( function () {
    var seneca = this
     seneca.act('foo:1,v:2', console.log)
  })

Heroku Deployment Support

Hi Everyone,

i need to deploy my services to multiple heroku apps and allow them to connect together using a base service with specific port on heroku.

for ex. i have (mesh-base) app that acts as a base node

var seneca = require('seneca')({
  timeout: 30000,
  tag: 'base node',
})
.use('mesh',
  {
     port: process.env.PORT || 39999,
        isbase: true,
  });

as it might seems i can't bind the mesh-base to external port on heroku so other instances can reach it
even i can't route the external port 80 to the internal port allowed by heroku(process.env.PORT).
do i miss something ?
any help will be appreciated?
Regards

timing problems

I'm trying to fetch a series of actions once everything has meshed, but I can't seem to get it to go without a liberal use of setTimeout.

I saw in #4 that it should be possible to emit from the base node when it is ready, but even then it doesn't seem to work.

I hit this in my project with just 4 actions on a microservice, only 2 of them would show up without setTimeout.... Here is a contrived / reduced test case detailing the problem:

var senecaBase = require('seneca')()
senecaBase.use('mesh',{base:true})
senecaBase.ready(() => {
  // for `ready: true` to be available, the setTimeout needs to be present, otherwise act_not_found
  //setTimeout(() => {
    senecaBase.act('ready:true')
  //}, 500)
})

var senecaServer = require('seneca')()
var services = {}
for (var x=0; x<10; x++) {
  services['service:echo,n:' + x] = (args, callback) => { callback(null, args); }
}

var listeners = Object.keys(services).map(pin => { return {pin} })
senecaServer.use('mesh', {auto: true, listen: listeners})
Object.keys(services).forEach(pin => {
  senecaServer.add(pin, services[pin])
})

var senecaClient = require('seneca')()
senecaClient.use('mesh', {auto:true, pin: 'ready:true'})
senecaClient.add('ready:true', (msg, cb) => {
  // even though this fires after ready, a timeout is required to get all actions
  // and for me at least, the full 10 seconds is required to get all 10 to show up.
  //setTimeout(() => {
    console.log(senecaClient.list('service:echo'))
  //}, 10000)
  cb()
})

here is package.json:

{
  "name": "seneca-tests",
  "version": "0.0.0",
  "dependencies": {
    "seneca": "^3.0.0",
    "seneca-balance-client": "^0.6.0",
    "seneca-mesh": "^0.9.0"
  }
}

It seems like I may be going about this the wrong way, and I don't have a lot of underlying knowledge of how mesh/etc. work behind the scenes.

Is there a way to wait until all actions have been loaded & meshed before calling into an act_not_found error?

My services loose their connection to network

I am getting an intermittent issue where the services loose their connection to the mesh network and when called I get an error that says:

{
  "result": "error",
  "err": {
    "eraro": true,
    "orig": null,
    "code": "no-current-target",
    "seneca": true,
    "package": "seneca",
    "msg": "seneca: No targets are currently active for message"
...

How do I customise the mesh network code to add some functionality to reconnect to the mesh network when a connection is lost.

I am currently using the consul_registry so I would need to check against the registered base nodes to find the network.

Message: seneca: gate-executor: [TIMEOUT] with dockers

it used to work before on dockers. bringing up a service gives me gate-executor exception. i've the mesh-base running on docker. this is the error

Seneca Fatal Error

Message: seneca: gate-executor: [TIMEOUT:z7en3mapswpc/dkj6xm1uexzi:11111<1465163235895-1465163224784:undefined]
Code: transport_listen
Details: { type: 'web',
port: [Function],
host: '0.0.0.0',
path: '/act',
protocol: 'http',
timeout: 5555,
max_listen_attempts: 11,
attempt_delay: 222,
serverOptions: {},
pin: { role: 'karmasoc-web-server' },
.............
at null._onTimeout (/src/node_modules/seneca/node_modules/gate-executor/gate-executor.js:112:21)

this is my docker file

karmasoc-web-server

FROM node:4
RUN mkdir /src
ADD . /src/
WORKDIR /src
RUN npm install --unsafe-perm=true
EXPOSE 8200
EXPOSE 44000
EXPOSE 43000
CMD ["npm", "start"]

build and run:

$ docker build -t karmasoc-web-server .
$ docker run -d -h $(docker-machine ip default) -p 8200:8200 -p 44000:44000 -p 43000:43000 -e HOST=$(docker-machine ip default) -e JWT_SECRET=* -e REDISCLOUD_URL=* -e PATH_LOGFILE=** karmasoc-web-server

appreciate any help. let me know if you need any more details

Bug in mesh 0.5.0

The code below works with 0.4.0 and fails with 0.5.0

  1. Run base
  2. Run subcsriber1
  3. Run subscriber2
  4. Run publisher

Mesh-base fails if invalid pin submitted for registration

!/opt/local/bin/node

require('seneca')()
.use('mesh', {auto:true, listen:[ {pins:['ns:mmmmm,what:aaaaaaaa,cmd:updates','typea:'], model:'publish'}]})
.ready(function(){
var s = this;
s.add('ns:mmmmm,cmd:updates,what:aaaaaaaa', function(msg, done){
console.log('Subscriber1|Updates|Message: ' + JSON.stringify(msg));
done(null, {status:'ok', src:'subcriber1'});
});
});

mesh-base in production

My understanding is that seneca-mesh is using a centralized location for knowledge of the other services. That centralized location is used as an address book and allows microservices to communicate in a P2P fashion.

Hence a few questions:

  • Is the mesh-base a single point of failure ?
  • What is the recovery scenario when the base fails (host down) ?

Terminate on retrun an error

When i use http or tcp type and return (err,res) where err is not null, service terminate!
Is it a normal behavior?
If yes, how we can return an error with err-res pattern?

 var Seneca = require('seneca');
 Seneca({log: 'test', timeout: '1000'})
        .use('seneca-transport')
        .use('mesh', {
            isbase: false,
            listen: [
                {pin: 'cat:test,cmd:run1', timeout: 1000, type: 'tcp'}
            ]
        })
        .add('cat:test,cmd:run1',function(msg,callback){
            callback(new Error('my error'));
        });

And here is act result that call from another service :

Seneca Fatal Error
==================
Message: seneca: Action cat:test,cmd:run1 failed: my error.
Code: act_execute
Details: { message: 'my error',
pattern: 'cat:test,cmd:run1',
instance: 'Seneca/fglbckoc6k4a/1479906487908/2721/3.2.2/-',
'orig$': {},
'message$': 'my error',
plugin: {} }
Stack:
at internals.Utils.handle_response (./node_modules/seneca-transport/lib/transport-utils.js:70:11)
at Duplex.messager._write (./node_modules/seneca-transport/lib/tcp.js:186:19)
...
...
SENECA TERMINATED at 2016-11-23T13:08:30.022Z. See above for error report.

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    ๐Ÿ–– Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. ๐Ÿ“Š๐Ÿ“ˆ๐ŸŽ‰

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google โค๏ธ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.