/** Locates the internal address of the node on which a deployment is deployed. */ private void findDeploymentAddress( final String deploymentID, Handler<AsyncResult<String>> resultHandler) { context.execute( new Action<String>() { @Override public String perform() { synchronized (deployments) { JsonObject locatedInfo = null; Collection<String> sdeploymentsInfo = deployments.get(group); for (String sdeploymentInfo : sdeploymentsInfo) { JsonObject deploymentInfo = new JsonObject(sdeploymentInfo); if (deploymentInfo.getString("id").equals(deploymentID)) { locatedInfo = deploymentInfo; break; } } if (locatedInfo != null) { return locatedInfo.getString("address"); } return null; } } }, resultHandler); }
/** Removes a deployment from the deployments map and returns the real deploymentID. */ private void removeDeployment( final String deploymentID, Handler<AsyncResult<String>> doneHandler) { context.execute( new Action<String>() { @Override public String perform() { Collection<String> groupDeployments = deployments.get(group); if (groupDeployments != null) { String deployment = null; for (String sdeployment : groupDeployments) { JsonObject info = new JsonObject(sdeployment); if (info.getString("id").equals(deploymentID)) { deployment = sdeployment; break; } } if (deployment != null) { deployments.remove(group, deployment); return new JsonObject(deployment).getString("realID"); } } return null; } }, doneHandler); }
/** Lists nodes in the group. */ private void doListNode(final Message<JsonObject> message) { context.execute( new Action<Collection<String>>() { @Override public Collection<String> perform() { return groups.get(group); } }, new Handler<AsyncResult<Collection<String>>>() { @Override public void handle(AsyncResult<Collection<String>> result) { if (result.failed()) { message.reply( new JsonObject() .putString("status", "error") .putString("message", result.cause().getMessage())); } else if (result.result() == null) { message.reply( new JsonObject().putString("status", "ok").putArray("result", new JsonArray())); } else { message.reply( new JsonObject() .putString("status", "ok") .putArray( "result", new JsonArray( result.result().toArray(new String[result.result().size()])))); } } }); }
/** Called when a node leaves the cluster. */ private synchronized void doNodeLeft(final String nodeID) { log.info(String.format("%s - %s left the cluster", this, nodeID)); context.run( new Runnable() { @Override public void run() { // Redeploy any failed deployments. synchronized (deployments) { Collection<String> sdeploymentsInfo = deployments.get(group); for (final String sdeploymentInfo : sdeploymentsInfo) { final JsonObject deploymentInfo = new JsonObject(sdeploymentInfo); // If the deployment node is equal to the node that left the cluster then // remove the deployment from the deployments list and attempt to redeploy it. if (deploymentInfo.getString("node").equals(nodeID)) { // If the deployment is an HA deployment then attempt to redeploy it on this node. if (deployments.remove(group, sdeploymentInfo) && deploymentInfo.getBoolean("ha", false)) { doRedeploy(deploymentInfo); } } } } } }); }
@Override public void stop(final Handler<AsyncResult<Void>> doneHandler) { synchronized (registry) { registry.remove(local); } context.execute( new Action<Void>() { @Override public Void perform() { groups.remove(group); return null; } }, new Handler<AsyncResult<Void>>() { @Override public void handle(AsyncResult<Void> result) { vertx.eventBus().unregisterHandler(group, messageHandler, doneHandler); listener.unregisterJoinHandler(null); listener.unregisterLeaveHandler(null); final CountingCompletionHandler<Void> counter = new CountingCompletionHandler<Void>(3) .setHandler( new Handler<AsyncResult<Void>>() { @Override public void handle(AsyncResult<Void> result) { clearDeployments(doneHandler); } }); vertx.eventBus().unregisterHandler(local, messageHandler, counter); vertx.eventBus().unregisterHandler(internal, internalHandler, counter); vertx.eventBus().unregisterHandler(group, messageHandler, counter); } }); }
/** Selects a node in the group. */ private void doSelectNode(final Message<JsonObject> message) { final Object key = message.body().getValue("key"); if (key == null) { message.reply( new JsonObject().putString("status", "error").putString("message", "No key specified.")); } else { context.execute( new Action<String>() { @Override public String perform() { String address = nodeSelectors.get(key); if (address != null) { return address; } Collection<String> nodes = groups.get(group); int index = new Random().nextInt(nodes.size()); int i = 0; for (String node : nodes) { if (i == index) { nodeSelectors.put(key, node); return node; } i++; } return null; } }, new Handler<AsyncResult<String>>() { @Override public void handle(AsyncResult<String> result) { if (result.failed()) { message.reply( new JsonObject() .putString("status", "error") .putString("message", result.cause().getMessage())); } else if (result.result() == null) { message.reply( new JsonObject() .putString("status", "error") .putString("message", "No nodes to select.")); } else { message.reply( new JsonObject() .putString("status", "ok") .putString("result", result.result())); } } }); } }
/** Adds a changed deployment to the deployments map. */ private void addMappedDeployment( final String deploymentID, final JsonObject deploymentInfo, Handler<AsyncResult<String>> doneHandler) { context.execute( new Action<String>() { @Override public String perform() { deploymentInfo.putString("realID", deploymentID); deploymentInfo.putString("node", listener.nodeId()); deploymentInfo.putString("address", internal); deployments.put(group, deploymentInfo.encode()); return deploymentID; } }, doneHandler); }
/** * When the cluster is shutdown properly we need to remove deployments from the deployments map in * order to ensure that deployments aren't redeployed if this node leaves the cluster. */ private void clearDeployments(final Handler<AsyncResult<Void>> doneHandler) { context.execute( new Action<Void>() { @Override public Void perform() { Collection<String> sdeploymentsInfo = deployments.get(group); for (String sdeploymentInfo : sdeploymentsInfo) { JsonObject deploymentInfo = new JsonObject(sdeploymentInfo); if (deploymentInfo.getString("address").equals(internal)) { deployments.remove(group, sdeploymentInfo); } } return null; } }, doneHandler); }
/** Finds a node in the group. */ private void doFindNode(final Message<JsonObject> message) { String nodeName = message.body().getString("node"); if (nodeName == null) { message.reply( new JsonObject().putString("status", "error").putString("message", "No node specified.")); return; } final String address = String.format("%s.%s", group, nodeName); context.execute( new Action<Boolean>() { @Override public Boolean perform() { return groups.containsEntry(group, address); } }, new Handler<AsyncResult<Boolean>>() { @Override public void handle(AsyncResult<Boolean> result) { if (result.failed()) { message.reply( new JsonObject() .putString("status", "error") .putString("message", result.cause().getMessage())); } else if (!result.result()) { message.reply( new JsonObject() .putString("status", "error") .putString("message", "Invalid node.")); } else { message.reply( new JsonObject().putString("status", "ok").putString("result", address)); } } }); }