use of net.dempsy.config.Node in project Dempsy by Dempsy.
the class DempsyBaseTest method runCombos.
protected void runCombos(final String testName, final ComboFilter filter, final String[][] ctxs, final String[][][] perNodeProps, final TestToRun test) throws Exception {
if (filter != null && !filter.filter(routerId, containerId, sessionType, transportType, serializerType))
return;
final long comboSequence = runComboSequence.getAndIncrement();
currentAppName = testName + "-" + comboSequence;
LOGGER.info("=====================================================================================");
LOGGER.info("======== Running (" + comboSequence + ") " + testName + " with " + routerId + ", " + containerId + ", " + sessionType + ", " + threadingModelDescription + ", " + transportType + "/" + serializerType);
try (final ServiceTracker tr = new ServiceTracker()) {
currentlyTracking = tr;
tr.track(new SystemPropertyManager()).set("routing-strategy", ROUTER_ID_PREFIX + routerId).set("container-type", CONTAINER_ID_PREFIX + containerId).set("test-name", currentAppName).setIfAbsent("total_shards", Integer.toString(NUM_MICROSHARDS));
// instantiate session factory
final ClusterInfoSessionFactory sessFact = tr.track(new ClassPathXmlApplicationContext(COLLAB_CTX_PREFIX + sessionType + COLLAB_CTX_SUFFIX)).getBean(ClusterInfoSessionFactory.class);
currentSessionFactory = sessFact;
final List<NodeManagerWithContext> reverseCpCtxs = reverseRange(0, ctxs.length).mapToObj(i -> {
try (final SystemPropertyManager p2 = new SystemPropertyManager()) {
if (perNodeProps != null && perNodeProps[i] != null) {
for (final String[] kv : perNodeProps[i]) {
if (kv != null) {
if (kv.length != 2)
throw new IllegalArgumentException("Invalid KV Pair passed for per-node property");
p2.set(kv[0], kv[1]);
}
}
}
final NodeManagerWithContext ret = makeNode(ctxs[i]);
// we can only do this level of polling when the min_nodes isn't set or is set to 1.
final String minNodesProp = System.getProperty("min_nodes");
if (minNodesProp != null && Integer.parseInt(minNodesProp) == 1)
assertTrue(qpoll(ret, o -> o.manager.isReady()));
return ret;
}
}).collect(Collectors.toList());
final List<NodeManagerWithContext> cpCtxs = reverseRange(0, reverseCpCtxs.size()).mapToObj(i -> reverseCpCtxs.get(i)).collect(Collectors.toList());
for (final NodeManagerWithContext n : cpCtxs) assertTrue(poll(o -> n.manager.isReady()));
test.test(new Nodes(cpCtxs, sessFact));
currentlyTracking = null;
} finally {
LocalClusterSessionFactory.completeReset();
BlockingQueueAddress.completeReset();
ClassTracker.dumpResults();
}
test.postShutdown();
System.gc();
System.gc();
System.gc();
System.gc();
System.gc();
System.gc();
for (final long endTime = System.currentTimeMillis() + TEN_SECONDS; Thread.activeCount() > 3; ) {
ignore(() -> Thread.sleep(10));
if (Thread.activeCount() > 3 && (System.currentTimeMillis() > endTime)) {
LOGGER.error("There appears to be an incomplete shutdown! There are {} threads running after stop.", Thread.activeCount());
break;
}
}
}
use of net.dempsy.config.Node in project Dempsy by Dempsy.
the class TestContainer method addOutputCatchStage.
public NodeManager addOutputCatchStage() throws InterruptedException {
// =======================================================
// configure an output catcher tier
final Node out = new Node.Builder("test-app").defaultRoutingStrategyId("net.dempsy.router.simple").receiver(new BlockingQueueReceiver(new ArrayBlockingQueue<>(16))).nodeStatsCollector(new BasicNodeStatsCollector()).cluster("output-catch").mp(new MessageProcessor<OutputCatcher>(new OutputCatcher())).build();
out.validate();
final NodeManager nman = track(new NodeManager()).node(out).collaborator(track(sessionFactory.createSession())).start();
// wait until we can actually reach the output-catch cluster from the main node
assertTrue(poll(o -> {
try {
return canReach(getRouter(manager), "output-catch", new KeyExtractor().extract(new OutputMessage("foo", 1, 1)).iterator().next());
} catch (final Exception e) {
return false;
}
}));
// =======================================================
return nman;
}
use of net.dempsy.config.Node in project Dempsy by Dempsy.
the class NodeManager method start.
public NodeManager start() throws DempsyException {
validate();
nodeStatsCollector = tr.track((NodeStatsCollector) node.getNodeStatsCollector());
// TODO: cleaner?
statsCollectorFactory = tr.track(new Manager<>(ClusterStatsCollectorFactory.class).getAssociatedInstance(node.getClusterStatsCollectorFactoryId()));
// =====================================
// set the dispatcher on adaptors and create containers for mp clusters
final AtomicReference<String> firstAdaptorClusterName = new AtomicReference<>(null);
node.getClusters().forEach(c -> {
if (c.isAdaptor()) {
if (firstAdaptorClusterName.get() == null)
firstAdaptorClusterName.set(c.getClusterId().clusterName);
final Adaptor adaptor = c.getAdaptor();
adaptors.put(c.getClusterId(), adaptor);
if (c.getRoutingStrategyId() != null && !"".equals(c.getRoutingStrategyId().trim()) && !" ".equals(c.getRoutingStrategyId().trim()))
LOGGER.warn("The cluster " + c.getClusterId() + " contains an adaptor but also has the routingStrategy set. The routingStrategy will be ignored.");
if (c.getOutputScheduler() != null)
LOGGER.warn("The cluster " + c.getClusterId() + " contains an adaptor but also has an output executor set. The output executor will never be used.");
} else {
String containerTypeId = c.getContainerTypeId();
if (containerTypeId == null)
// can't be null
containerTypeId = node.getContainerTypeId();
final Container con = makeContainer(containerTypeId).setMessageProcessor(c.getMessageProcessor()).setClusterId(c.getClusterId()).setMaxPendingMessagesPerContainer(c.getMaxPendingMessagesPerContainer());
// TODO: This is a hack for now.
final Manager<RoutingStrategy.Inbound> inboundManager = new RoutingInboundManager();
final RoutingStrategy.Inbound is = inboundManager.getAssociatedInstance(c.getRoutingStrategyId());
final boolean outputSupported = c.getMessageProcessor().isOutputSupported();
final Object outputScheduler = c.getOutputScheduler();
// if there mp handles output but there's no output scheduler then we should warn.
if (outputSupported && outputScheduler == null)
LOGGER.warn("The cluster " + c.getClusterId() + " contains a message processor that supports an output cycle but there's no executor set so it will never be invoked.");
if (!outputSupported && outputScheduler != null)
LOGGER.warn("The cluster " + c.getClusterId() + " contains a message processor that doesn't support an output cycle but there's an output cycle executor set. The output cycle executor will never be used.");
final OutputScheduler os = (outputSupported && outputScheduler != null) ? (OutputScheduler) outputScheduler : null;
containers.add(new PerContainer(con, is, c, os));
}
});
// it we're all adaptor then don't bother to get the receiver.
if (containers.size() == 0) {
// here there's no point in a receiver since there's nothing to receive.
if (firstAdaptorClusterName.get() == null)
throw new IllegalStateException("There seems to be no clusters or adaptors defined for this node \"" + node.toString() + "\"");
} else {
receiver = (Receiver) node.getReceiver();
if (// otherwise we're all adaptor
receiver != null)
nodeAddress = receiver.getAddress(this);
else if (firstAdaptorClusterName.get() == null)
throw new IllegalStateException("There seems to be no clusters or adaptors defined for this node \"" + node.toString() + "\"");
}
nodeId = Optional.ofNullable(nodeAddress).map(n -> n.getGuid()).orElse(firstAdaptorClusterName.get());
if (nodeStatsCollector == null) {
LOGGER.warn("There is no {} set for the the application '{}'", StatsCollector.class.getSimpleName(), node.application);
nodeStatsCollector = new DummyNodeStatsCollector();
}
nodeStatsCollector.setNodeId(nodeId);
if (nodeAddress == null && node.getReceiver() != null)
LOGGER.warn("The node at " + nodeId + " contains no message processors but has a Reciever set. The receiver will never be started.");
if (nodeAddress == null && node.getDefaultRoutingStrategyId() != null)
LOGGER.warn("The node at " + nodeId + " contains no message processors but has a defaultRoutingStrategyId set. The routingStrategyId will never be used.");
if (threading == null)
threading = tr.track(new DefaultThreadingModel(nodeId)).configure(node.getConfiguration()).start(nodeId);
else if (!threading.isStarted())
threading.start(nodeId);
nodeStatsCollector.setMessagesPendingGauge(() -> threading.getNumberLimitedPending());
final NodeReceiver nodeReciever = receiver == null ? null : tr.track(new NodeReceiver(containers.stream().map(pc -> pc.container).collect(Collectors.toList()), threading, nodeStatsCollector));
final Map<ClusterId, ClusterInformation> messageTypesByClusterId = new HashMap<>();
containers.stream().map(pc -> pc.clusterDefinition).forEach(c -> {
messageTypesByClusterId.put(c.getClusterId(), new ClusterInformation(c.getRoutingStrategyId(), c.getClusterId(), c.getMessageProcessor().messagesTypesHandled()));
});
final NodeInformation nodeInfo = nodeAddress != null ? new NodeInformation(receiver.transportTypeId(), nodeAddress, messageTypesByClusterId) : null;
// Then actually register the Node
if (nodeInfo != null) {
keepNodeRegstered = new PersistentTask(LOGGER, isRunning, persistenceScheduler, RETRY_PERIOND_MILLIS) {
@Override
public boolean execute() {
try {
session.recursiveMkdir(rootPaths.clustersDir, null, DirMode.PERSISTENT, DirMode.PERSISTENT);
session.recursiveMkdir(rootPaths.nodesDir, null, DirMode.PERSISTENT, DirMode.PERSISTENT);
final String nodePath = rootPaths.nodesDir + "/" + nodeId;
session.mkdir(nodePath, nodeInfo, DirMode.EPHEMERAL);
final NodeInformation reread = (NodeInformation) session.getData(nodePath, this);
final boolean ret = nodeInfo.equals(reread);
if (ret == true)
ptaskReady.set(true);
return ret;
} catch (final ClusterInfoException e) {
final String logmessage = "Failed to register the node. Retrying in " + RETRY_PERIOND_MILLIS + " milliseconds.";
if (LOGGER.isDebugEnabled())
LOGGER.info(logmessage, e);
else
LOGGER.info(logmessage, e);
}
return false;
}
@Override
public String toString() {
return "register node information";
}
};
}
// =====================================
// The layering works this way.
//
// Receiver -> NodeReceiver -> adaptor -> container -> OutgoingDispatcher -> RoutingStrategyOB -> Transport
//
// starting needs to happen in reverse.
// =====================================
isRunning.set(true);
this.tManager = tr.start(new TransportManager(), this);
this.rsManager = tr.start(new RoutingStrategyManager(), this);
// create the router but don't start it yet.
this.router = new OutgoingDispatcher(rsManager, nodeAddress, nodeId, nodeReciever, tManager, nodeStatsCollector);
// set up containers
containers.forEach(pc -> pc.container.setDispatcher(router).setEvictionCycle(pc.clusterDefinition.getEvictionFrequency().evictionFrequency, pc.clusterDefinition.getEvictionFrequency().evictionTimeUnit));
// IB routing strategy
final int numContainers = containers.size();
for (int i = 0; i < numContainers; i++) {
final PerContainer c = containers.get(i);
c.inboundStrategy.setContainerDetails(c.clusterDefinition.getClusterId(), new ContainerAddress(nodeAddress, i), c.container);
}
// setup the output executors by passing the containers
containers.stream().filter(pc -> pc.outputScheduler != null).forEach(pc -> pc.outputScheduler.setOutputInvoker(pc.container));
// set up adaptors
adaptors.values().forEach(a -> a.setDispatcher(router));
// start containers after setting inbound
containers.forEach(pc -> tr.start(pc.container.setInbound(pc.inboundStrategy), this));
// start the output schedulers now that the containers have been started.
containers.stream().map(pc -> pc.outputScheduler).filter(os -> os != null).forEach(os -> tr.start(os, this));
// start IB routing strategy
containers.forEach(pc -> tr.start(pc.inboundStrategy, this));
// start router
tr.start(this.router, this);
final PersistentTask startAdaptorAfterRouterIsRunning = new PersistentTask(LOGGER, isRunning, this.persistenceScheduler, 500) {
@Override
public boolean execute() {
if (!router.isReady())
return false;
adaptors.entrySet().forEach(e -> threading.runDaemon(() -> tr.track(e.getValue()).start(), "Adaptor-" + e.getKey().clusterName));
return true;
}
};
// make sure the router is running. Once it is, start the adaptor(s)
startAdaptorAfterRouterIsRunning.process();
if (receiver != null)
tr.track(receiver).start(nodeReciever, this);
// close this session when we're done.
tr.track(session);
// make it known we're here and ready
if (keepNodeRegstered != null)
keepNodeRegstered.process();
else
ptaskReady.set(true);
return this;
}
use of net.dempsy.config.Node in project Dempsy by Dempsy.
the class TestContainer method setUp.
@Before
public void setUp() throws Exception {
justThrowMe = null;
throwMeInActivation = null;
track(new SystemPropertyManager()).set("container-type", containerId);
context = track(new ClassPathXmlApplicationContext(ctx));
sessionFactory = new LocalClusterSessionFactory();
final Node node = context.getBean(Node.class);
manager = track(new NodeManager()).node(node).collaborator(track(sessionFactory.createSession())).start();
statsCollector = manager.getClusterStatsCollector(new ClusterId("test-app", "test-cluster"));
container = manager.getContainers().get(0);
assertTrue(poll(manager, m -> m.isReady()));
}
use of net.dempsy.config.Node in project Dempsy by Dempsy.
the class TestAlmostSimple method testSimple.
@Test
public void testSimple() throws Exception {
final MpEven mpEven = new MpEven();
final MpOdd mpOdd = new MpOdd();
final AtomicLong count = new AtomicLong(0);
Adaptor adaptor = null;
try (final DefaultThreadingModel tm = new DefaultThreadingModel("TB", -1, 1);
final NodeManager nm = new NodeManager()) {
final Node n = new Node.Builder("test-app").defaultRoutingStrategyId("net.dempsy.router.simple").containerTypeId(containerTypeId).receiver(new Dummy()).cluster("start").adaptor(adaptor = new Adaptor() {
private Dispatcher disp;
boolean done = false;
int cur = 0;
AtomicBoolean exitedLoop = new AtomicBoolean(false);
@Override
public void stop() {
done = true;
while (!exitedLoop.get()) Thread.yield();
}
@Override
public void start() {
try {
while (!done) {
uncheck(() -> disp.dispatchAnnotated(new Message(cur++)));
count.incrementAndGet();
}
} finally {
exitedLoop.set(true);
}
}
@Override
public void setDispatcher(final Dispatcher dispatcher) {
this.disp = dispatcher;
}
}).cluster("mpEven").mp(new MessageProcessor<>(mpEven)).evictionFrequency(1, TimeUnit.SECONDS).cluster("mpOdd").mp(new MessageProcessor<>(mpOdd)).build();
nm.node(n).collaborator(new LocalClusterSessionFactory().createSession()).threadingModel(tm.start(n.application));
nm.start();
assertTrue(ConditionPoll.poll(c -> count.get() > 100000));
// make sure an eviction happened before closing
// at this point all of the mps should have been checked for eviction
assertTrue(ConditionPoll.poll(o -> 2 == mpEven.allMps.size()));
mpEven.allMps.forEach(m -> uncheck(() -> assertTrue(ConditionPoll.poll(o -> m.evictCalled))));
// now enable them to actually be removed from the container.
// we need to stop the adaptor or we'll keep recreating them
adaptor.stop();
// need to wait for all of the adaptor messages to play through before evicting
Thread.sleep(2000);
MpEven.allowEviction.set(true);
final List<Container> containers = nm.getContainers().stream().filter(c -> "mpEven".equals(c.getClusterId().clusterName)).collect(Collectors.toList());
assertEquals(1, containers.size());
final Container container = containers.get(0);
assertTrue(ConditionPoll.poll(o -> 0 == container.getProcessorCount()));
}
Thread.sleep(2000);
// make sure the messages were distributed correctly.
assertEquals(2, mpEven.allMps.size());
assertEquals(2, mpOdd.allMps.size());
final MpEven mpEvenYes = mpEven.allMps.stream().filter(m -> "yes".equals(m.key)).findAny().get();
// all messages here should be even numbers
assertTrue(mpEvenYes.received.stream().allMatch(m -> (m.message & 0x01) == 0));
final MpEven mpEvenNo = mpEven.allMps.stream().filter(m -> "no".equals(m.key)).findAny().get();
// all messages here should be odd numbers
assertTrue(mpEvenNo.received.stream().allMatch(m -> (m.message & 0x01) == 1));
final MpOdd mpOddYes = mpOdd.allMps.stream().filter(m -> "yes".equals(m.key)).findAny().get();
// all messages here should be odd numbers
assertTrue(mpOddYes.received.stream().allMatch(m -> (m.message & 0x01) == 1));
final MpOdd mpOddNo = mpOdd.allMps.stream().filter(m -> "no".equals(m.key)).findAny().get();
// all messages here should be even numbers
assertTrue(mpOddNo.received.stream().allMatch(m -> (m.message & 0x01) == 0));
}
Aggregations