Search in sources :

Example 6 with ClusterInfoSession

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);
        }
    }
}
Also used : TestInfrastructure(net.dempsy.util.TestInfrastructure) ClusterId(net.dempsy.config.ClusterId) ContainerAddress(net.dempsy.router.RoutingStrategy.ContainerAddress) RoutingInboundManager(net.dempsy.router.RoutingInboundManager) GroupDetails(net.dempsy.router.group.intern.GroupDetails) Utils(net.dempsy.router.shardutils.Utils) RoutingStrategy(net.dempsy.router.RoutingStrategy) NodeAddress(net.dempsy.transport.NodeAddress) ClusterInfoSession(net.dempsy.cluster.ClusterInfoSession) Test(org.junit.Test)

Example 7 with ClusterInfoSession

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_SESSION, 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_SESSION.warn("[{}] A node directory was empty at " + subdir, thisNodeId);
                        return false;
                    }
                    // see if node info is dupped.
                    if (alreadySeen.contains(ni)) {
                        LOGGER_SESSION.warn("[{}] The node " + ni.nodeAddress + " seems to be registed more than once.", thisNodeId);
                        continue;
                    }
                    if (ni.clusterInfoByClusterId.size() == 0) {
                        // it's ALL adaptor so there's no sense in dealing with it
                        LOGGER_SESSION.trace("[{}] NodeInformation {} appears to be only an Adaptor.", thisNodeId, 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()) {
                    LOGGER_SESSION.info("[{}] Topology change notification resulted in no changes.", thisNodeId);
                    isReady.set(true);
                    // nothing to update.
                    return true;
                } else if (LOGGER_SESSION.isTraceEnabled())
                    LOGGER_SESSION.info("[{}] Topology change notification resulted in changes ", 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, thisNodeId);
                    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_SESSION.warn("[{}] Unexpected exception while applying a topology update", thisNodeId, rte);
                    outbounds.set(obs);
                    throw rte;
                }
            } catch (final ClusterInfoException e) {
                final String message = "Failed to find outgoing route information. Will retry shortly.";
                if (LOGGER_SESSION.isTraceEnabled())
                    LOGGER_SESSION.debug("[{}] {}", new Object[] { thisNodeId, message, e });
                else
                    LOGGER_SESSION.debug("[{}] {}", thisNodeId, message);
                return false;
            }
        }

        @Override
        public String toString() {
            return thisNodeId + " find nodes to route to";
        }
    };
    outbounds.set(new ApplicationState(tmanager, thisNode, new ConcurrentHashMap<>()));
    isRunning.set(true);
    checkup.process();
}
Also used : HashSet(java.util.HashSet) Set(java.util.Set) NodeInformation(net.dempsy.NodeInformation) ClusterInfoException(net.dempsy.cluster.ClusterInfoException) SafeString(net.dempsy.util.SafeString) PersistentTask(net.dempsy.utils.PersistentTask) Collection(java.util.Collection) ClusterInfoSession(net.dempsy.cluster.ClusterInfoSession) ConcurrentHashMap(java.util.concurrent.ConcurrentHashMap)

Example 8 with ClusterInfoSession

use of net.dempsy.cluster.ClusterInfoSession in project Dempsy by Dempsy.

the class TestElasticity method testForProfiler.

@Test
public void testForProfiler() throws Throwable {
    try {
        // set up the test.
        final Number[] numbers = new Number[profilerTestNumberCount];
        final Random random = new Random();
        for (int i = 0; i < numbers.length; i++) numbers[i] = new Number(random.nextInt(1000), 0);
        final KeyExtractor ke = new KeyExtractor();
        runCombos("testForProfiler", (r, c, s, t, ser) -> isElasticRoutingStrategy(r), actxPath, new String[][][] { null, { { "min_nodes", "3" } }, { { "min_nodes", "3" } }, { { "min_nodes", "3" } }, null }, ns -> {
            final List<NodeManagerWithContext> nodes = ns.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);
            try (final ClusterInfoSession session = ns.sessionFactory.createSession()) {
                waitForEvenShardDistribution(session, "test-cluster1", 3, nodes);
                // get the Adaptor Router's statCollector
                final List<NodeMetricGetters> scs = nodes.stream().map(nwm -> nwm.manager).map(nm -> nm.getNodeStatsCollector()).map(sc -> (NodeMetricGetters) sc).collect(Collectors.toList());
                // 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;
                final long startTime = System.currentTimeMillis();
                for (int i = 0; i < numbers.length; i++) dispatcher.dispatch(ke.extract(numbers[i]));
                LOGGER.info("====> Checking exact count.");
                // keep going as long as they are trickling in.
                assertTrue(() -> {
                    IntStream.range(0, scs.size()).forEach(i -> {
                        System.out.println("======> " + i);
                        final NodeMetricGetters mg = scs.get(i);
                        if (mg != null) {
                            System.out.println("discarded: " + mg.getDiscardedMessageCount());
                            System.out.println("not sent: " + mg.getMessagesNotSentCount());
                        }
                    });
                    return "expected: " + profilerTestNumberCount + " but was: " + (rank.totalMessages.get() + scs.get(0).getMessagesNotSentCount()) + ", (delivered: " + rank.totalMessages.get() + ", not sent: " + scs.get(0).getMessagesNotSentCount() + ")";
                }, poll(o -> profilerTestNumberCount == (rank.totalMessages.get() + scs.stream().map(sc -> Long.valueOf(sc.getMessagesNotSentCount())).reduce(Long.valueOf(0), (v1, v2) -> Long.valueOf(v1.longValue() + v2.longValue()).longValue()))));
                // assert that at least SOMETHING went through
                assertTrue(rank.totalMessages.get() > 0);
                LOGGER.info("testForProfiler time " + (System.currentTimeMillis() - startTime));
                @SuppressWarnings("unchecked") final AtomicLong count = nodes.stream().map(// get the NumberCounter Mp
                nmwc -> (MessageProcessor<NumberCounter>) nmwc.manager.getMp("test-cluster1")).filter(// if it exists
                l -> l != null).map(// pull the prototype
                l -> l.getPrototype().messageCount).reduce(new AtomicLong(0), // sum up all of the counts
                (v1, v2) -> new AtomicLong(v1.get() + v2.get()));
                assertEquals(profilerTestNumberCount, count.get());
            }
        });
    } catch (final Throwable th) {
        th.printStackTrace();
        throw th;
    }
}
Also used : IntStream(java.util.stream.IntStream) MessageProcessor(net.dempsy.lifecycle.annotation.MessageProcessor) Mp(net.dempsy.lifecycle.annotation.Mp) ClusterInfoSession(net.dempsy.cluster.ClusterInfoSession) MessageType(net.dempsy.lifecycle.annotation.MessageType) Dispatcher(net.dempsy.messages.Dispatcher) NodeAddress(net.dempsy.transport.NodeAddress) LoggerFactory(org.slf4j.LoggerFactory) AtomicBoolean(java.util.concurrent.atomic.AtomicBoolean) Random(java.util.Random) AtomicReference(java.util.concurrent.atomic.AtomicReference) Function(java.util.function.Function) ArrayList(java.util.ArrayList) AtomicInteger(java.util.concurrent.atomic.AtomicInteger) Map(java.util.Map) ThreadingModel(net.dempsy.threading.ThreadingModel) ClusterId(net.dempsy.config.ClusterId) MessageKey(net.dempsy.lifecycle.annotation.MessageKey) Logger(org.slf4j.Logger) NodeMetricGetters(net.dempsy.container.NodeMetricGetters) MessageHandler(net.dempsy.lifecycle.annotation.MessageHandler) Functional.uncheck(net.dempsy.util.Functional.uncheck) ConcurrentHashMap(java.util.concurrent.ConcurrentHashMap) ClusterMetricGetters(net.dempsy.container.ClusterMetricGetters) Assert.assertTrue(org.junit.Assert.assertTrue) Set(java.util.Set) Test(org.junit.Test) Activation(net.dempsy.lifecycle.annotation.Activation) KeyExtractor(net.dempsy.lifecycle.annotation.utils.KeyExtractor) Collectors(java.util.stream.Collectors) Serializable(java.io.Serializable) AtomicLong(java.util.concurrent.atomic.AtomicLong) List(java.util.List) Adaptor(net.dempsy.messages.Adaptor) ConditionPoll.poll(net.dempsy.utils.test.ConditionPoll.poll) Functional.chain(net.dempsy.util.Functional.chain) ConditionPoll.assertTrue(net.dempsy.utils.test.ConditionPoll.assertTrue) Collections(java.util.Collections) Assert.assertEquals(org.junit.Assert.assertEquals) MessageProcessor(net.dempsy.lifecycle.annotation.MessageProcessor) NodeMetricGetters(net.dempsy.container.NodeMetricGetters) Dispatcher(net.dempsy.messages.Dispatcher) AtomicLong(java.util.concurrent.atomic.AtomicLong) Random(java.util.Random) KeyExtractor(net.dempsy.lifecycle.annotation.utils.KeyExtractor) ClusterInfoSession(net.dempsy.cluster.ClusterInfoSession) Test(org.junit.Test)

Example 9 with ClusterInfoSession

use of net.dempsy.cluster.ClusterInfoSession in project Dempsy by Dempsy.

the class TestElasticity method testExpansionPassivation.

@Test
public void testExpansionPassivation() throws Exception {
    final String[][] actxPath = { { "elasticity/adaptor.xml" }, { "elasticity/mp-num-count.xml" }, { "elasticity/mp-num-rank.xml" } };
    runCombos("testExpansionPassivation", (r, c, s, t, ser) -> isElasticRoutingStrategy(r), actxPath, ns -> {
        final AtomicBoolean keepGoing = new AtomicBoolean(true);
        try {
            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;
            final AtomicInteger rankIndexToSend = new AtomicInteger(0);
            final Runnable sendMessages = () -> {
                // for an integer is the integer itself so we can get every shard by sending
                try {
                    while (keepGoing.get()) {
                        for (int num = 0; num < 20; num++) {
                            final int number = num;
                            dispatcher.dispatch(uncheck(() -> ke.extract(new Number(number, rankIndexToSend.get()))));
                        }
                    }
                } catch (final InterruptedException ie) {
                    if (keepGoing.get())
                        LOGGER.info("send message thread interrupted but still running.");
                }
            };
            try (final ClusterInfoSession session = ns.sessionFactory.createSession()) {
                waitForEvenShardDistribution(session, "test-cluster1", 1, nodes);
                final NumberRank rank = nodes.get(2).ctx.getBean(NumberRank.class);
                runACycle(keepGoing, rankIndexToSend.get(), rank, sendMessages);
                // now we have 20 Mps in test-cluster1
                final ClusterMetricGetters sc = (ClusterMetricGetters) nodes.get(1).manager.getClusterStatsCollector(new ClusterId(currentAppName, "test-cluster1"));
                assertEquals(20L, sc.getMessageProcessorCount());
                // add a second node for the cluster test-cluster1
                nodes.add(makeNode(new String[] { "elasticity/mp-num-count.xml" }));
                waitForEvenShardDistribution(session, "test-cluster1", 2, nodes);
                // about 1/2 should drop out.
                assertTrue(poll(o -> {
                    // System.err.println(sc.getMessageProcessorCount());
                    return sc.getMessageProcessorCount() < 15L;
                }));
            }
        } finally {
            keepGoing.set(false);
        }
    });
}
Also used : IntStream(java.util.stream.IntStream) MessageProcessor(net.dempsy.lifecycle.annotation.MessageProcessor) Mp(net.dempsy.lifecycle.annotation.Mp) ClusterInfoSession(net.dempsy.cluster.ClusterInfoSession) MessageType(net.dempsy.lifecycle.annotation.MessageType) Dispatcher(net.dempsy.messages.Dispatcher) NodeAddress(net.dempsy.transport.NodeAddress) LoggerFactory(org.slf4j.LoggerFactory) AtomicBoolean(java.util.concurrent.atomic.AtomicBoolean) Random(java.util.Random) AtomicReference(java.util.concurrent.atomic.AtomicReference) Function(java.util.function.Function) ArrayList(java.util.ArrayList) AtomicInteger(java.util.concurrent.atomic.AtomicInteger) Map(java.util.Map) ThreadingModel(net.dempsy.threading.ThreadingModel) ClusterId(net.dempsy.config.ClusterId) MessageKey(net.dempsy.lifecycle.annotation.MessageKey) Logger(org.slf4j.Logger) NodeMetricGetters(net.dempsy.container.NodeMetricGetters) MessageHandler(net.dempsy.lifecycle.annotation.MessageHandler) Functional.uncheck(net.dempsy.util.Functional.uncheck) ConcurrentHashMap(java.util.concurrent.ConcurrentHashMap) ClusterMetricGetters(net.dempsy.container.ClusterMetricGetters) Assert.assertTrue(org.junit.Assert.assertTrue) Set(java.util.Set) Test(org.junit.Test) Activation(net.dempsy.lifecycle.annotation.Activation) KeyExtractor(net.dempsy.lifecycle.annotation.utils.KeyExtractor) Collectors(java.util.stream.Collectors) Serializable(java.io.Serializable) AtomicLong(java.util.concurrent.atomic.AtomicLong) List(java.util.List) Adaptor(net.dempsy.messages.Adaptor) ConditionPoll.poll(net.dempsy.utils.test.ConditionPoll.poll) Functional.chain(net.dempsy.util.Functional.chain) ConditionPoll.assertTrue(net.dempsy.utils.test.ConditionPoll.assertTrue) Collections(java.util.Collections) Assert.assertEquals(org.junit.Assert.assertEquals) ClusterId(net.dempsy.config.ClusterId) ArrayList(java.util.ArrayList) Dispatcher(net.dempsy.messages.Dispatcher) AtomicBoolean(java.util.concurrent.atomic.AtomicBoolean) AtomicInteger(java.util.concurrent.atomic.AtomicInteger) ClusterMetricGetters(net.dempsy.container.ClusterMetricGetters) ClusterInfoSession(net.dempsy.cluster.ClusterInfoSession) Test(org.junit.Test)

Example 10 with ClusterInfoSession

use of net.dempsy.cluster.ClusterInfoSession in project Dempsy by Dempsy.

the class TestElasticity method testNumberCountDropOneAndReAdd.

@Test
public void testNumberCountDropOneAndReAdd() throws Throwable {
    runCombos("testNumberCountDropOneAndReAdd", (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
                try {
                    while (keepGoing.get()) {
                        for (int num = 0; num < 20; num++) {
                            final int number = num;
                            dispatcher.dispatch(uncheck(() -> ke.extract(new Number(number, rankIndexToSend.get()))));
                        }
                    }
                } catch (final InterruptedException ie) {
                    if (keepGoing.get())
                        LOGGER.info("send message thread interrupted but still running.");
                }
            };
            try (final ClusterInfoSession session = ns.sessionFactory.createSession()) {
                waitForEvenShardDistribution(session, "test-cluster1", 3, ns.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 kill a node.
                final NodeManagerWithContext nm = nodes.remove(2);
                LOGGER.trace("==== Stopping middle node servicing shards ");
                nm.manager.stop();
                waitForEvenShardDistribution(session, "test-cluster1", 2, nodes);
                LOGGER.trace("==== Stopped middle Dempsy");
                // make sure everything still goes through
                runACycle(keepGoing, rankIndexToSend.incrementAndGet(), 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", 3, nodes);
                // make sure everything still goes through
                runACycle(keepGoing, rankIndexToSend.incrementAndGet(), rank, sendMessages);
            }
        } finally {
            keepGoing.set(false);
            LOGGER.trace("==== Exiting test.");
        }
    });
}
Also used : ArrayList(java.util.ArrayList) Dispatcher(net.dempsy.messages.Dispatcher) AtomicBoolean(java.util.concurrent.atomic.AtomicBoolean) AtomicInteger(java.util.concurrent.atomic.AtomicInteger) ClusterInfoSession(net.dempsy.cluster.ClusterInfoSession) Test(org.junit.Test)

Aggregations

ClusterInfoSession (net.dempsy.cluster.ClusterInfoSession)12 Test (org.junit.Test)10 ClusterId (net.dempsy.config.ClusterId)8 NodeAddress (net.dempsy.transport.NodeAddress)7 Set (java.util.Set)6 AtomicInteger (java.util.concurrent.atomic.AtomicInteger)6 ContainerAddress (net.dempsy.router.RoutingStrategy.ContainerAddress)6 ConditionPoll.poll (net.dempsy.utils.test.ConditionPoll.poll)6 Assert.assertEquals (org.junit.Assert.assertEquals)6 Assert.assertTrue (org.junit.Assert.assertTrue)6 ArrayList (java.util.ArrayList)5 List (java.util.List)5 AtomicBoolean (java.util.concurrent.atomic.AtomicBoolean)5 ClusterInfoException (net.dempsy.cluster.ClusterInfoException)5 Functional.chain (net.dempsy.util.Functional.chain)5 Logger (org.slf4j.Logger)5 LoggerFactory (org.slf4j.LoggerFactory)5 Map (java.util.Map)4 Collectors (java.util.stream.Collectors)4 Dispatcher (net.dempsy.messages.Dispatcher)4