use of net.dempsy.cluster.ClusterInfoSession in project Dempsy by Dempsy.
the class OutgoingDispatcher method start.
@Override
public void start(final Infrastructure infra) {
final ClusterInfoSession session = infra.getCollaborator();
final String nodesDir = infra.getRootPaths().nodesDir;
checkup = new PersistentTask(LOGGER, isRunning, infra.getScheduler(), RETRY_TIMEOUT) {
@Override
public boolean execute() {
try {
// collect up all NodeInfo's known about.
session.recursiveMkdir(nodesDir, null, DirMode.PERSISTENT, DirMode.PERSISTENT);
final Collection<String> nodeDirs = session.getSubdirs(nodesDir, this);
final Set<NodeInformation> alreadySeen = new HashSet<>();
// get all of the subdirectories NodeInformations
for (final String subdir : nodeDirs) {
final NodeInformation ni = (NodeInformation) session.getData(nodesDir + "/" + subdir, null);
if (ni == null) {
LOGGER.warn("A node directory was empty at " + subdir);
return false;
}
// see if node info is dupped.
if (alreadySeen.contains(ni)) {
LOGGER.warn("The node " + ni.nodeAddress + " seems to be registed more than once.");
continue;
}
if (ni.clusterInfoByClusterId.size() == 0) {
// it's ALL adaptor so there's no sense in dealing with it
LOGGER.trace("NodeInformation {} appears to be only an Adaptor.", ni);
continue;
}
alreadySeen.add(ni);
}
// check to see if there's new nodes.
final ApplicationState.Update ud = outbounds.get().update(alreadySeen, thisNode, thisNodeId);
if (!ud.change()) {
isReady.set(true);
// nothing to update.
return true;
} else if (LOGGER.isTraceEnabled())
LOGGER.trace("Updating for " + thisNodeId);
// otherwise we will be making changes so remove the current ApplicationState
// this can cause instability.
final ApplicationState obs = outbounds.getAndSet(null);
try {
final ApplicationState newState = obs.apply(ud, tmanager, statsCollector, manager);
outbounds.set(newState);
isReady.set(true);
return true;
} catch (final RuntimeException rte) {
// if we threw an exception after clearing the outbounds we need to restore it.
// This is likely a configuration error so we should probably warn about it.
LOGGER.warn("Unexpected exception while applying a topology update", rte);
outbounds.set(obs);
throw rte;
}
} catch (final ClusterInfoException e) {
final String message = "Failed to find outgoing route information. Will retry shortly.";
if (LOGGER.isTraceEnabled())
LOGGER.debug(message, e);
else
LOGGER.debug(message);
return false;
}
}
@Override
public String toString() {
return "find nodes to route to";
}
};
outbounds.set(new ApplicationState(tmanager, thisNode));
isRunning.set(true);
checkup.process();
}
use of net.dempsy.cluster.ClusterInfoSession in project Dempsy by Dempsy.
the class TestManagedRoutingStrategy method testInboundWithOutbound.
@Test
public void testInboundWithOutbound() throws Exception {
final int numShardsToExpect = Integer.parseInt(Utils.DEFAULT_TOTAL_SHARDS);
final Manager<RoutingStrategy.Inbound> manager = new Manager<>(RoutingStrategy.Inbound.class);
try (final RoutingStrategy.Inbound ib = manager.getAssociatedInstance(ManagedInbound.class.getPackage().getName())) {
final ClusterId cid = setTestName("testInboundWithOutbound");
final ContainerAddress oca = new ContainerAddress(new DummyNodeAddress("here"), 0);
final Infrastructure infra = makeInfra(session, sched);
final Utils<ContainerAddress> msutils = new Utils<>(infra, cid.clusterName, oca);
ib.setContainerDetails(cid, oca, (l, m) -> {
});
ib.start(infra);
checkForShardDistribution(session, msutils, numShardsToExpect, 1);
try (final ClusterInfoSession ses2 = sessFact.createSession();
final RoutingStrategyManager obman = chain(new RoutingStrategyManager(), o -> o.start(makeInfra(ses2, sched)));
final RoutingStrategy.Factory obf = obman.getAssociatedInstance(ManagedInbound.class.getPackage().getName())) {
obf.start(makeInfra(ses2, sched));
assertTrue(poll(o -> obf.isReady()));
final RoutingStrategy.Router ob = obf.getStrategy(cid);
assertTrue(poll(o -> obf.isReady()));
final KeyedMessageWithType km = new KeyedMessageWithType(new Object(), new Object(), "");
assertTrue(poll(o -> ob.selectDestinationForMessage(km) != null));
final ContainerAddress ca = ob.selectDestinationForMessage(km);
assertNotNull(ca);
assertEquals("here", ((DummyNodeAddress) ca.node).name);
// now disrupt the session
session.close();
try (ClusterInfoSession ses3 = sessFact.createSession();
RoutingStrategy.Inbound ib2 = manager.getAssociatedInstance(ManagedInbound.class.getPackage().getName())) {
ib2.setContainerDetails(cid, ca, (l, m) -> {
});
ib2.start(makeInfra(ses3, sched));
assertTrue(poll(o -> ob.selectDestinationForMessage(km) != null));
}
}
}
}
use of net.dempsy.cluster.ClusterInfoSession in project Dempsy by Dempsy.
the class TestManagedRoutingStrategy method testInboundDoubleHappyPathRegister.
@Test
public void testInboundDoubleHappyPathRegister() throws Exception {
final int numShardsToExpect = Integer.parseInt(Utils.DEFAULT_TOTAL_SHARDS);
try (final RoutingStrategy.Inbound ib1 = new Manager<>(RoutingStrategy.Inbound.class).getAssociatedInstance(ManagedInbound.class.getPackage().getName());
final RoutingStrategy.Inbound ib2 = new Manager<>(RoutingStrategy.Inbound.class).getAssociatedInstance(ManagedInbound.class.getPackage().getName())) {
final ClusterId clusterId = new ClusterId("test", "test");
final ContainerAddress node1Ca = new ContainerAddress(new DummyNodeAddress("node1"), 0);
final Utils<ContainerAddress> utils = new Utils<>(infra, clusterId.clusterName, node1Ca);
ib1.setContainerDetails(clusterId, node1Ca, (l, m) -> {
});
ib1.start(infra);
final ContainerAddress node2Ca = new ContainerAddress(new DummyNodeAddress("node2"), 0);
ib2.setContainerDetails(clusterId, node2Ca, (l, m) -> {
});
try (final ClusterInfoSession session2 = sessFact.createSession()) {
ib2.start(new TestInfrastructure(session2, infra.getScheduler()));
assertTrue(waitForShards(session, utils, numShardsToExpect));
// if this worked right then numShardsToExpect/2 should be owned by each ... eventually.
checkForShardDistribution(session, utils, numShardsToExpect, 2);
// disrupt the session. This should cause a reshuffle but not fail
disruptor.accept(session2);
// everything should settle back
checkForShardDistribution(session, utils, numShardsToExpect, 2);
// now kill the second session.
// this will disconnect the second Inbound and so the first should take over
session2.close();
// see if we now have 1 session and it has all shards
checkForShardDistribution(session, utils, numShardsToExpect, 1);
}
}
}
use of net.dempsy.cluster.ClusterInfoSession in project Dempsy by Dempsy.
the class TestElasticity method testNumberCountAddOneThenDrop.
@Test
public void testNumberCountAddOneThenDrop() throws Throwable {
runCombos("testNumberCountAddOneThenDrop", (r, c, s, t, ser) -> isElasticRoutingStrategy(r), actxPath, ns -> {
// keepGoing is for the separate thread that pumps messages into the system.
final AtomicBoolean keepGoing = new AtomicBoolean(true);
try {
LOGGER.trace("==== <- Starting");
final List<NodeManagerWithContext> nodes = new ArrayList<>(ns.nodes);
// grab the adaptor from the 0'th cluster + the 0'th (only) node.
final NumberProducer adaptor = nodes.get(0).ctx.getBean(NumberProducer.class);
// grab access to the Dispatcher from the Adaptor
final Dispatcher dispatcher = adaptor.dispatcher;
// This is a Runnable that will pump messages to the dispatcher until keepGoing is
// flipped to 'false.' It's stateless so it can be reused as needed.
final AtomicInteger rankIndexToSend = new AtomicInteger(0);
final Runnable sendMessages = () -> {
// for an integer is the integer itself so we can get every shard by sending
while (keepGoing.get()) {
for (int num = 0; num < 20; num++) {
final int number = num;
dispatcher.dispatch(uncheck(() -> ke.extract(new Number(number, rankIndexToSend.get()))));
}
}
};
try (final ClusterInfoSession session = ns.sessionFactory.createSession()) {
waitForEvenShardDistribution(session, "test-cluster1", 3, nodes);
// Grab the one NumberRank Mp from the single Node in the third (0 base 2nd) cluster.
final NumberRank rank = nodes.get(4).ctx.getBean(NumberRank.class);
runACycle(keepGoing, rankIndexToSend.get(), rank, sendMessages);
// now, bring online another instance.
LOGGER.trace("==== starting a new one");
nodes.add(makeNode(new String[] { "elasticity/mp-num-count.xml" }));
waitForEvenShardDistribution(session, "test-cluster1", 4, nodes);
// make sure everything still goes through
runACycle(keepGoing, rankIndexToSend.incrementAndGet(), rank, sendMessages);
// now kill a node.
final NodeManagerWithContext nm = nodes.remove(2);
LOGGER.trace("==== Stopping middle node servicing shards ");
nm.manager.stop();
waitForEvenShardDistribution(session, "test-cluster1", 3, nodes);
LOGGER.trace("==== Stopped middle Dempsy");
// make sure everything still goes through
runACycle(keepGoing, rankIndexToSend.incrementAndGet(), rank, sendMessages);
}
} finally {
keepGoing.set(false);
LOGGER.trace("==== Exiting test.");
}
});
}
use of net.dempsy.cluster.ClusterInfoSession in project Dempsy by Dempsy.
the class TestGroupRoutingStrategy method testInboundDoubleHappyPathRegister.
@Test
public void testInboundDoubleHappyPathRegister() throws Exception {
final int numShardsToExpect = Integer.parseInt(Utils.DEFAULT_TOTAL_SHARDS);
final String groupName = "testInboundDoubleHappyPathRegister";
try (final RoutingStrategy.Inbound ib1 = new RoutingInboundManager().getAssociatedInstance(ClusterGroupInbound.class.getPackage().getName() + ":" + groupName);
final RoutingStrategy.Inbound ib2 = new RoutingInboundManager().getAssociatedInstance(ClusterGroupInbound.class.getPackage().getName() + ":" + groupName)) {
final ClusterId clusterId = new ClusterId("test", "test");
final NodeAddress node1Addr = new DummyNodeAddress("node1");
final GroupDetails gd1 = new GroupDetails(groupName, node1Addr);
final ContainerAddress node1Ca = new ContainerAddress(node1Addr, 0);
final Utils<GroupDetails> utils = new Utils<>(infra, groupName, gd1);
ib1.setContainerDetails(clusterId, node1Ca, (l, m) -> {
});
ib1.start(infra);
final NodeAddress node2Addr = new DummyNodeAddress("node2");
final ContainerAddress node2Ca = new ContainerAddress(node2Addr, 0);
ib2.setContainerDetails(clusterId, node2Ca, (l, m) -> {
});
try (final ClusterInfoSession session2 = sessFact.createSession()) {
ib2.start(new TestInfrastructure(session2, infra.getScheduler()));
assertTrue(waitForShards(session, utils, numShardsToExpect));
// if this worked right then numShardsToExpect/2 should be owned by each ... eventually.
checkForShardDistribution(session, utils, numShardsToExpect, 2);
// disrupt the session. This should cause a reshuffle but not fail
disruptor.accept(session2);
// everything should settle back
checkForShardDistribution(session, utils, numShardsToExpect, 2);
// now kill the second session.
// this will disconnect the second Inbound and so the first should take over
session2.close();
// see if we now have 1 session and it has all shards
checkForShardDistribution(session, utils, numShardsToExpect, 1);
}
}
}
Aggregations