use of net.dempsy.messages.KeyedMessageWithType in project Dempsy by Dempsy.
the class TestInstanceManager method testOutputShortCircuitsIfNoOutputMethod.
@Test
public void testOutputShortCircuitsIfNoOutputMethod() throws Exception {
final CombinedMP prototype = new CombinedMP();
final Container manager = setupContainer(new MessageProcessor<CombinedMP>(prototype));
final DummyDispatcher dispatcher = ((DummyDispatcher) manager.getDispatcher());
// we need to dispatch messages to create MP instances
final KeyedMessageWithType message1 = km(new MessageOne(1));
final KeyedMessageWithType message2 = km(new MessageOne(2));
manager.dispatch(message1, Operation.handle, true);
manager.dispatch(message2, Operation.handle, true);
assertEquals(new ReturnString("MessageOne"), dispatcher.lastDispatched.message);
manager.invokeOutput();
// output messages are NOT considered "processed" if there is no output method on the MP.
assertEquals("number of processed messages should include outputs.", 2, ((ClusterMetricGetters) statsCollector).getProcessedMessageCount());
}
use of net.dempsy.messages.KeyedMessageWithType in project Dempsy by Dempsy.
the class TestInstanceManager method testMultipleInstanceCreation.
@Test
public void testMultipleInstanceCreation() throws Exception {
final CombinedMP prototype = new CombinedMP();
try (final LockingContainer manager = setupContainer(new MessageProcessor<CombinedMP>(prototype))) {
final DummyDispatcher dispatcher = ((DummyDispatcher) manager.getDispatcher());
assertEquals("starts with no instances", 0, manager.getProcessorCount());
final KeyedMessageWithType message1 = km(new MessageOne(123));
final InstanceWrapper wrapper1 = manager.getInstanceForKey(message1.key, message1.message);
manager.dispatch(message1, Operation.handle, true);
final CombinedMP instance1 = (CombinedMP) wrapper1.getInstance();
final KeyedMessageWithType message2 = km(new MessageOne(456));
final InstanceWrapper wrapper2 = manager.getInstanceForKey(message2.key, message2.message);
manager.dispatch(message2, Operation.handle, true);
final CombinedMP instance2 = (CombinedMP) wrapper2.getInstance();
assertEquals("instances were created", 2, manager.getProcessorCount());
assertEquals(new ReturnString("MessageOne"), dispatcher.lastDispatched.message);
assertEquals("message count to instance1", 1, instance1.messages.size());
assertEquals("message count to instance2", 1, instance2.messages.size());
assertSame("message1 went to instance1", message1.message, instance1.messages.get(0));
assertSame("message2 went to instance2", message2.message, instance2.messages.get(0));
assertEquals(new ReturnString("MessageOne"), dispatcher.lastDispatched.message);
}
}
use of net.dempsy.messages.KeyedMessageWithType in project Dempsy by Dempsy.
the class TestInstanceManager method testSingleInstanceOneMessage.
@Test
public void testSingleInstanceOneMessage() throws Throwable {
final CombinedMP prototype = new CombinedMP();
try (final LockingContainer manager = setupContainer(new MessageProcessor<CombinedMP>(prototype))) {
assertEquals("starts with no instances", 0, manager.getProcessorCount());
final KeyedMessageWithType message = km(new MessageOne(123));
final InstanceWrapper wrapper = manager.getInstanceForKey(message.key, message.message);
assertEquals("instance was created", 1, manager.getProcessorCount());
final CombinedMP instance = (CombinedMP) wrapper.getInstance();
// activation is now inline with insantiation so it's active immediately
// assertEquals("instance not already activated", 0, instance.activationCount);
assertEquals("instance activated", 1, instance.activationCount);
assertEquals("instance has no existing messages", -1, instance.firstMessageTime);
// assertNull("instance has no message list", instance.messages);
assertTrue("real activation time", instance.activationTime > 0);
assertEquals("message count", 0, instance.messages.size());
// dispatch the message
// wrapper.run();
manager.dispatch(message, Operation.handle, true);
assertEquals("instance activated", 1, instance.activationCount);
assertTrue("real activation time", instance.activationTime > 0);
assertSame("instance received message", message.message, instance.messages.get(0));
assertEquals("message count", 1, instance.messages.size());
assertTrue("activated before first message", instance.activationTime < instance.firstMessageTime);
// The return value cannot be routed.
assertEquals(new ReturnString("MessageOne"), ((DummyDispatcher) manager.getDispatcher()).lastDispatched.message);
assertEquals("prototype not activated", 0, prototype.activationCount);
assertEquals("prototype did not receive messages", -1, prototype.firstMessageTime);
assertNull("prototype has no message list", prototype.messages);
}
}
use of net.dempsy.messages.KeyedMessageWithType in project Dempsy by Dempsy.
the class TestInstanceManager method testSingleInstanceTwoMessagesSameClassSeparateExecution.
@Test
public void testSingleInstanceTwoMessagesSameClassSeparateExecution() throws Exception {
final CombinedMP prototype = new CombinedMP();
try (final LockingContainer manager = setupContainer(new MessageProcessor<CombinedMP>(prototype))) {
final DummyDispatcher dispatcher = ((DummyDispatcher) manager.getDispatcher());
assertEquals("starts with no instances", 0, manager.getProcessorCount());
final KeyedMessageWithType message1 = km(new MessageOne(123));
final InstanceWrapper wrapper1 = manager.getInstanceForKey(message1.key, message1.message);
manager.dispatch(message1, Operation.handle, true);
final CombinedMP instance = (CombinedMP) wrapper1.getInstance();
assertEquals("instance was created", 1, manager.getProcessorCount());
assertEquals("instance activated", 1, instance.activationCount);
assertTrue("real activation time", instance.activationTime > 0);
assertSame("instance received message", message1.message, instance.messages.get(0));
assertEquals("message count", 1, instance.messages.size());
assertTrue("activated before first message", instance.activationTime < instance.firstMessageTime);
assertEquals(new ReturnString("MessageOne"), dispatcher.lastDispatched.message);
final KeyedMessageWithType message2 = km(new MessageOne(123));
final InstanceWrapper wrapper2 = manager.getInstanceForKey(message2.key, message2.message);
manager.dispatch(message2, Operation.handle, true);
assertSame("same wrapper returned for second message", wrapper1, wrapper2);
assertEquals("no other instance was created", 1, manager.getProcessorCount());
assertEquals("no second activation", 1, instance.activationCount);
assertEquals("both messages delivered", 2, instance.messages.size());
assertSame("message1 delivered first", message1.message, instance.messages.get(0));
assertSame("message2 delivered second", message2.message, instance.messages.get(1));
assertEquals(new ReturnString("MessageOne"), dispatcher.lastDispatched.message);
}
}
use of net.dempsy.messages.KeyedMessageWithType in project Dempsy by Dempsy.
the class OutgoingDispatcher method dispatch.
@Override
public void dispatch(final KeyedMessageWithType messageParam, final MessageResourceManager disposer) throws InterruptedException {
final boolean traceEnabled = LOGGER.isTraceEnabled();
if (messageParam == null)
throw new NullPointerException("Attempt to dispatch a null message.");
final Object messageKey = messageParam.key;
if (messageKey == null)
throw new NullPointerException("Message " + SafeString.objectDescription(messageParam) + " has a null key.");
boolean messageSentSomewhere = false;
try (ResourceManagerClosable x = new ResourceManagerClosable(disposer, messageParam)) {
final KeyedMessageWithType message = x.toUse;
ApplicationState tmp = outbounds.get();
// if we're in the midst of an update then we really want to wait for the new state.
while (tmp == null) {
if (!isRunning.get()) {
LOGGER.debug("[{}] Router dispatch called while stopped.", thisNodeId);
return;
}
if (// however, if we never were ready then we're not in the midst
!isReady.get())
// of an update.
throw new IllegalStateException("Dispatch used before Router is ready.");
// let the other threads do their thing. Maybe we'll be updated sooner.
Thread.yield();
// are we updated yet?
tmp = outbounds.get();
}
final ApplicationState cur = tmp;
final Map<String, RoutingStrategy.Router[]> outboundsByMessageType = cur.outboundsByMessageType;
// =================================================================================
// For each message type, determine the set of Routers. The goal of this loop is to set
// 'containerByNodeAddress'
final Map<NodeAddress, ContainerAddress> containerByNodeAddress = new HashMap<>();
for (final String mt : message.messageTypes) {
final RoutingStrategy.Router[] routers = outboundsByMessageType.get(mt);
if (routers == null) {
if (traceEnabled)
LOGGER.trace("[{}] No cluster that handles messages of type {}", thisNodeId, mt);
} else {
// the set of ContainerAddresses that this message will be sent to.
for (int i = 0; i < routers.length; i++) {
final ContainerAddress ca = routers[i].selectDestinationForMessage(message);
// it's possible 'ca' is null when we don't know where to send the message.
if (ca == null) {
if (LOGGER.isDebugEnabled())
LOGGER.debug("[{}] No way to send the message {} to specific cluster for the time being", thisNodeId, message.message);
} else {
// When the message will be sent to 2 different clusters, but both clusters
// are hosted in the same node, then we send 1 message to 1 ContainerAddress
// where the 'clusters' field contains both container ids.
final ContainerAddress already = containerByNodeAddress.get(ca.node);
if (already != null) {
final int[] ia = new int[already.clusters.length + ca.clusters.length];
System.arraycopy(already.clusters, 0, ia, 0, already.clusters.length);
System.arraycopy(ca.clusters, 0, ia, already.clusters.length, ca.clusters.length);
containerByNodeAddress.put(ca.node, new ContainerAddress(ca.node, ia));
} else
containerByNodeAddress.put(ca.node, ca);
}
}
}
}
if (containerByNodeAddress.size() == 0) {
if (traceEnabled)
LOGGER.trace("[{}] There appears to be no valid destination addresses for the message {}", thisNodeId, SafeString.objectDescription(message.message));
}
for (final Map.Entry<NodeAddress, ContainerAddress> e : containerByNodeAddress.entrySet()) {
final NodeAddress curNode = e.getKey();
final ContainerAddress curAddr = e.getValue();
// If we're local then just send this message directly back to our own node.
if (curNode.equals(thisNode)) {
if (traceEnabled)
LOGGER.trace("Sending local {}", message);
// if the message is a resource then the disposer will be used to dispose of the message
// but it needs an additional replicate. See propogateMessageToNode javadoc.
nodeReciever.propogateMessageToNode(new RoutedMessage(curAddr.clusters, messageKey, disposer == null ? message.message : disposer.replicate(message.message)), // this shouldn't count since Router is an OUTGOING class
false, disposer);
messageSentSomewhere = true;
} else {
if (traceEnabled)
LOGGER.trace("Sending {} to {}", message, curNode);
final Sender sender = cur.getSender(curNode);
if (sender == null) {
// router update is probably behind the routing strategy update
if (isRunning.get())
LOGGER.error("[{}] Couldn't send message to " + curNode + " from " + thisNodeId + " because there's no " + Sender.class.getSimpleName(), thisNodeId);
} else {
sender.send(new RoutedMessage(curAddr.clusters, messageKey, sender.considerMessageOwnsershipTransfered() ? (disposer == null ? message.message : disposer.replicate(message.message)) : message.message));
messageSentSomewhere = true;
}
}
}
} finally {
if (!messageSentSomewhere) {
if (traceEnabled)
LOGGER.trace("Message not sent.");
statsCollector.messageNotSent();
}
}
}
Aggregations