Archive for the '16211' Category

AjFabriq en NodeJs (Parte 3) Una Aplicación Distribuida Simple

Thursday, September 15th, 2011

Anterior Post

Ejecutemos nuestra “killer app” (un simple contador) en dos nodos. En el repositorio, en examples\numbers, hay un programa appserver.js:

Es similar a mi ejemplo local. La diferencia es que el procesador de mensajes principal escucha por una puerta:

/**
 * Host.
 */
var host = ajfabriq.createLocalHost();
/**
 * Application configuration.
 */
 
var app = host.createProcessor('numbers', 'application');
var node = app.createProcessor('processor', 'node');
node.on('decrement', function (message) {
	console.log("Processing number " + message.number);
	
	if (message.number <= 1) {
		console.log("End Processing");
		return;
		}
		
	var number = message.number-1;
	
	this.post({ action: 'decrement', number: number });
});
host.listen(3000);
host.process({ application: 'numbers', node: 'processor', action: 'decrement', number: 10 });

En este código estoy usando ajfabriq.createLocalHost() en vez de .createProcessor(). Y host.listen(3000) comienza a aceptar mensajes desde otros nodos.

Ejecuto otro programa: appclient.js. Tiene los mismos procesadores locales:

/**
 * Application configuration.
 */
 
var app = host.createProcessor('numbers', 'application');
var node = app.createProcessor('processor', 'node');
node.on('decrement', function (message) {
	console.log("Processing number " + message.number);
	if (message.number <= 1)
		return;
		
	var number = message.number-1;
	
	this.post({ action: 'decrement', number: number });
});

Pero se conecta con el primer server y envía un nuevo mensaje:

var socket = new net.Socket();
socket.connect(3000, 'localhost',
	function() {
		host.connect(new ajfabriq.Channel(socket), true);
		socket.write(JSON.stringify({name : 'ajfmessage', message: { application: 'numbers', node: 'processor', action: 'decrement', number: 10 }}));
	}
);
	

ajfabriq.Channel es el canal bidireccional entre dos servidores ajfabriq.

Esta es la salida del segundo servidor:

Noten el intercambio de mensajes entre los dos servidores, al comienzo. Estan informando de sus procesadores de mensajes locales al otro servidor. De esta forma, cada servidor sabe qué mensajes puede procesar otro nodo.

Esta es la actividad del primer servidor luego del mensaje enviado por el segundo servidor:

Algunos de los números son procesados por el segundo servidor, y otros son ruteados al primer servidor. El ruteo es una simple elección al azar. Los objetos LocalHost tiene un nuevo método .post:

LocalHost.prototype.post = function (message) {
	var hosts = [ this ];
	
	for (var remote in this.remotes) {
		if (this.remotes[remote].accepts(message)) {
			hosts.push(this.remotes[remote]);
		}
	}
	var n = Math.floor(Math.random() * hosts.length);
	
	hosts[n].process(message);
};

Próximos pasos: un mejor ruteo, mejorar la comunicación de sockets (debo manejar mensajes JSON grandes, que pueden venir en varias comunicaciones, no en un solo read), logueo, más ejemplos de aplicaciones, ejemplos con más de dos nodos.

Nos leemos!

Angel “Java” Lopez

http://www.ajlopez.com

http://twitter.com/ajlopez

AjFabriq en NodeJs (Parte 2) Una aplicación local simple

Wednesday, September 14th, 2011

Anterior Post 
Siguiente Post

Veamos de explorar cómo usar AjFabriq en NodeJs. Hay una simple aplicación:

https://github.com/ajlopez/AjFabriqJs/tree/master/examples/numbers

Implementa la última “killer application”: recibe un mensaje con un número, y postea un mensaje con ese número decrementado en uno ;-). Veamos có se define la aplicación:

/**
 * Module dependencies.
 */
 
var ajf = require('ajfabriq');

 

 

Incluí al directorio c:\Git en mi variable de ambiente NODE_PATH, y hay ahí un c:\Git\ajfabriq conteniendo mi repositorio git local de lo que estoy desarrollando. Pueden clonar el repo en el directorio node_modules donde está el NodeJs 5.x (see Playing With NodeJs (1) Running on Windows (and Azure), Jugando con NodeJs (1) En Windows (y en Azure)) .

AjFabriq define un objeto que expone algunos métodos. Esta es la manera de crear un procesador de mensajes que es local, y éste no es expuesto a otros servidor (en el próximo post explicaré una aplicación distribuida):

/**
 * Host.
 */
var host = ajf.createProcessor();

 

 

El procesador de mensajes (ver anterior post) puede contener otros procesadores, es un “composite”. El método aprocessor.createProcessor crea un nuevo procesador y lo agrega a su procesador padre:

/**
 * Application configuration.
 */
 
var app = host.createProcessor('numbers', 'application');
var node = app.createProcessor('processor', 'node');

 

 

El primer procesador, en la variable app, aceptará y procesará mensajes con la propiedad “application” teniendo como valor a “numbers”. Su procesador hijo procesará mensajes con la propiedad “node” con valor “processor”. De esta forma, podemos definir un árbol de procesadores de mensajes. Las propiedades del mensajes y sus valores forman entonces su información de ruteo, así que cada mensaje será enviado al procesador apropiado.

Pero ¿cómo definir la conducta del procesador hijo final? Para estar alineado con el procesamiento asincrónico de NodeJs, cada procesador hereda de un EventEmitter. Desde el anterior post, definí al Processor como una “subclase” de process.EventEmitter en el código de AjFabriq:

var EventEmitter = process.EventEmitter;
// ...
function Processor(name, kind)
{
	this.name = name;
	this.kind = kind;
	this.processors = [];
}
Processor.prototype.__proto__ = EventEmitter.prototype;

 

 

Ahora, podemos definir el procesador hijo final:

node.on('decrement', function (message) {
	console.log("Processing number " + message.number);
	
	if (message.number <= 1) {
		console.log("End Processing");
		return;
		}
		
	var number = message.number-1;
	
	this.post({ action: 'decrement', number: number });
});

 

 

El procesamiento de mensajes detecta una propiedad llamada “action”, y dispara el correspondiente evento. Noten el método emit en este código de AjFabriq:

Processor.prototype.process = function (message)
{
	if (this.processors == null || this.processors.length == 0) {
		this.emit(message.action, message);
		return;
	}
	
	for (var processor in this.processors)
		if (this.processors[processor].accepts(message)) 
		{
			this.processors[processor].process(message);
		}
}

 

 

 

Al final de mi “killer app”, un mensaje es enviado al procesador inicial:

host.process({ application: 'numbers', node: 'processor', action: 'decrement', number: 10 });

 

 

La salida:

Pero, esperen! ¿vieron el código de ‘decrement’ que mostré más arriba? Hay un:

this.post({ action: 'decrement', number: number });

 

 

No hay propiedad aplication, ni node. Y funciona igual. Si uno postea un mensaje a un procesador (en este caso al que está en la variable node), los procesadores padres llena las propiedades faltantes. Así, la propiedad application toma el valor “numbers”, y la propiedad node toma el valor de “processor”. Si quieren enviar un mensaje a otra aplicación, podemos poner explícitamente la propiedad correspondiente en el nuevo mensaje a enviar. Noten que la práctica recomendada es: no cambien el mensaje original. Puede que sea procesado por otros procesadores.

Para futuros posts: nuevas aplicaciones, un ejemplo distribuido

Nos leemos!

Angel “Java” Lopez

http://www.ajlopez.com
http://twitter.com/ajlopez