Correlaciones como colas FIFO

Con WebSphere eXtreme Scale, puede proporcionar una prestación parecida a una cola FIFO (primero en entrar, primero en salir) para todas las correlaciones. WebSphere eXtreme Scale realiza un seguimiento del orden de inserción de todas las correlaciones. Un cliente puede solicitar una correlación para la siguiente entrada desbloqueada en una correlación en el orden de inserción y bloquear la entrada. Este proceso permite a varios clientes consumir entradas de la correlación de una forma eficaz.

Ejemplo FIFO

El siguiente fragmento de código muestra un cliente entrando un bucle para procesar entradas en la correlación hasta que la correlación se agota. El bucle inicia una transacción y luego llama al método ObjectMap.getNextKey(5000). Este método devuelve la clave de la siguiente entrada desbloqueada disponible y la bloquea. Si la transacción está bloqueada durante más de 5000 milisegundos, el método devuelve un valor nulo.
Session session = ...;
ObjectMap map = session.getMap("xxx");
// esto es necesario establecerlo en algún lugar para detener este bucle
boolean timeToStop = false;

while(!timeToStop)
{
  session.begin();
  Object msgKey = map.getNextKey(5000);
  if(msgKey == null)
  {
    // la partición actual se ha agotado, invóquela de nuevo en
    // una nueva transacción para pasar a la partición siguiente
    session.rollback();
    continue;
  }
  Message m = (Message)map.get(msgKey);
  // ahora consumir el mensaje
  ...
  // es necesario suprimirlo
  map.remove(msgKey);
  session.commit();
}

Modalidad local frente a modalidad de cliente

Si la aplicación utiliza un núcleo principal, es decir, no es un cliente, el mecanismo funciona tal como se describe anteriormente.

Para la modalidad de cliente, si la JVM (Java Virtual Machine) es un cliente, el cliente se conecta inicialmente a un primario de partición aleatoria. Si no hay trabajo en esa partición, el cliente pasa a la siguiente en busca de trabajo. El cliente encuentra una partición con entradas o realiza un bucle y vuelve a la partición aleatoria inicial. Si el cliente realiza un bucle y vuelve a la partición inicial, devolverá un valor nulo a la aplicación. Si el cliente encuentra una partición con una correlación que tenga entradas, consumirá entradas de la misma hasta que no haya entradas disponibles durante el periodo de tiempo de espera. Una vez que ha transcurrido el tiempo de espera, se devuelve el valor nulo. Esta acción significa que cuando se devuelve nulo y se utiliza una correlación particionada, se debe iniciar una nueva transacción y reanudar la escucha. El fragmento de ejemplo de código anterior tiene este comportamiento.

Ejemplo

Cuando ejecute como cliente y se devuelva una clave, esa transacción ahora está enlazada a la partición con la entrada para esa clave. Si no desea actualizar ninguna otra correlación durante la transacción, no existe ningún problema. Si no desea actualizar, sólo puede actualizar correlaciones de la misma partición que la correlación de la que ha obtenido la clave. La entradas devuelta del método getNextKey debe ofrecer a la aplicación un método para descubrir los datos relevantes de dicha partición. Como ejemplo, si tiene dos correlaciones, una para los sucesos y otra para los trabajos que se ven afectados por los sucesos. Defina las dos correlaciones con las siguientes entidades:
Job.java
package tutorial.fifo;

import com.ibm.websphere.projector.annotations.Entity;
import com.ibm.websphere.projector.annotations.Id;

@Entity
public class Job
{
	@Id String jobId;

	int jobState;
}
JobEvent.java
package tutorial.fifo;

import com.ibm.websphere.projector.annotations.Entity;
import com.ibm.websphere.projector.annotations.Id;
import com.ibm.websphere.projector.annotations.OneToOne;

@Entity
public class JobEvent
{
	@Id String eventId;
	@OneToOne Job job;
}
El trabajo tiene un ID y un estado, que es un entero. Suponga que desea incrementar el estado cuando llega un suceso. Los sucesos se almacenan en la correlación JobEvent. Cada entrada tiene una referencia al trabajo asociado con el suceso. El código para que el escucha haga esto se parece al siguiente ejemplo:
JobEventListener.java
package tutorial.fifo;

import com.ibm.websphere.objectgrid.ObjectGridException;
import com.ibm.websphere.objectgrid.ObjectMap;
import com.ibm.websphere.objectgrid.Session;
import com.ibm.websphere.objectgrid.em.EntityManager;

public class JobEventListener
{
	boolean stopListening;

	public synchronized void stopListening()
	{
		stopListening = true;
	}

	synchronized boolean isStopped()
	{
		return stopListening;
	}

	public void processJobEvents(Session session)
		throws ObjectGridException
	{
		EntityManager em = session.getEntityManager();
		ObjectMap jobEvents = session.getMap("JobEvent");
		while(!isStopped())
		{
			em.getTransaction().begin();

			Object jobEventKey = jobEvents.getNextKey(5000);
			if(jobEventKey == null)
			{
				em.getTransaction().rollback();
				continue;
			}
			JobEvent event = (JobEvent)em.find(JobEvent.class, jobEventKey);
			// procesar el suceso, aquí sólo se incrementa el
			// estado de trabajo
			event.job.jobState++;
			em.getTransaction().commit();
		}
	}
}

La aplicación inicia el escucha en una hebra. El escucha se ejecuta hasta que se llama al método stopListening. El método processJobEvents se ejecuta en una hebra hasta que se llama al método stopListening. El bucle bloquea la espera de eventKey de la correlación JobEvent y luego utiliza EntityManager para acceder al objeto de suceso, elimina la referencia al trabajo e incrementa el estado.

La API de EntityManager no tiene un método getNextKey, pero ObjectMap sí lo tiene. Por lo tanto, el código utiliza la ObjectMap para que JobEvent obtenga la clave. Si se utiliza una correlación con entidades, no almacenará más objetos. En su lugar, almacenará tuples; un objeto Tuple para la clave y un objeto Tuple para el valor. El método EntityManager.find acepta un Tuple para la clave.

El código para crear un suceso se parece al siguiente ejemplo:
em.getTransaction().begin();
Job job = em.find(Job.class, "Job Key");
JobEvent event = new JobEvent();
event.id = Random.toString();
event.job = job;
em.persist(event); // insert it
em.getTransaction().commit();
Para buscar el trabajo para el suceso, construya un suceso, haga que apunte al trabajo, insértelo en la correlación JobEvent y confirme la transacción.

Cargadores y correlaciones FIFO

Si desea respaldar una correlación que se utiliza como cola FIFO con un cargador, puede que sea necesario realizar algún trabajo adicional. Si el orden de las entradas de la correlación no es importante, no tendrá trabajo adicional. Si el orden es importante, es necesario añadir un número de secuencia a todos los registros insertados cuando se persisten los registros en el programa de fondo. El mecanismo de precarga debe grabarse para insertar los registro durante el inicio utilizando este orden.