use of io.atomix.messaging.Endpoint in project atomix by atomix.
the class DefaultClusterEventingServiceTest method testClusterEventService.
@Test
public void testClusterEventService() throws Exception {
TestMessagingServiceFactory factory = new TestMessagingServiceFactory();
ClusterMetadata clusterMetadata = buildClusterMetadata(1, 1, 2, 3);
Node localNode1 = buildNode(1, Node.Type.CORE);
MessagingService messagingService1 = factory.newMessagingService(localNode1.endpoint()).start().join();
ClusterService clusterService1 = new DefaultClusterService(localNode1, new TestClusterMetadataService(clusterMetadata), messagingService1).start().join();
ClusterEventingService eventService1 = new DefaultClusterEventingService(clusterService1, messagingService1).start().join();
Node localNode2 = buildNode(2, Node.Type.CORE);
MessagingService messagingService2 = factory.newMessagingService(localNode2.endpoint()).start().join();
ClusterService clusterService2 = new DefaultClusterService(localNode2, new TestClusterMetadataService(clusterMetadata), messagingService2).start().join();
ClusterEventingService eventService2 = new DefaultClusterEventingService(clusterService2, messagingService2).start().join();
Node localNode3 = buildNode(3, Node.Type.CORE);
MessagingService messagingService3 = factory.newMessagingService(localNode3.endpoint()).start().join();
ClusterService clusterService3 = new DefaultClusterService(localNode3, new TestClusterMetadataService(clusterMetadata), messagingService3).start().join();
ClusterEventingService eventService3 = new DefaultClusterEventingService(clusterService3, messagingService3).start().join();
Thread.sleep(100);
Set<Integer> events = new CopyOnWriteArraySet<>();
eventService1.<String>subscribe("test1", SERIALIZER::decode, message -> {
assertEquals(message, "Hello world!");
events.add(1);
}, MoreExecutors.directExecutor()).join();
eventService2.<String>subscribe("test1", SERIALIZER::decode, message -> {
assertEquals(message, "Hello world!");
events.add(2);
}, MoreExecutors.directExecutor()).join();
eventService2.<String>subscribe("test1", SERIALIZER::decode, message -> {
assertEquals(message, "Hello world!");
events.add(3);
}, MoreExecutors.directExecutor()).join();
eventService3.broadcast("test1", "Hello world!", SERIALIZER::encode);
Thread.sleep(100);
assertEquals(3, events.size());
events.clear();
eventService3.unicast("test1", "Hello world!");
Thread.sleep(100);
assertEquals(1, events.size());
assertTrue(events.contains(3));
events.clear();
eventService3.unicast("test1", "Hello world!");
Thread.sleep(100);
assertEquals(1, events.size());
assertTrue(events.contains(1));
events.clear();
eventService3.unicast("test1", "Hello world!");
Thread.sleep(100);
assertEquals(1, events.size());
assertTrue(events.contains(2));
events.clear();
eventService3.unicast("test1", "Hello world!");
Thread.sleep(100);
assertEquals(1, events.size());
assertTrue(events.contains(3));
events.clear();
eventService1.<String, String>subscribe("test2", SERIALIZER::decode, message -> {
events.add(1);
return message;
}, SERIALIZER::encode, MoreExecutors.directExecutor()).join();
eventService2.<String, String>subscribe("test2", SERIALIZER::decode, message -> {
events.add(2);
return message;
}, SERIALIZER::encode, MoreExecutors.directExecutor()).join();
assertEquals("Hello world!", eventService3.send("test2", "Hello world!").join());
assertEquals(1, events.size());
assertTrue(events.contains(1));
events.clear();
assertEquals("Hello world!", eventService3.send("test2", "Hello world!").join());
assertEquals(1, events.size());
assertTrue(events.contains(2));
events.clear();
assertEquals("Hello world!", eventService3.send("test2", "Hello world!").join());
assertEquals(1, events.size());
assertTrue(events.contains(1));
}
use of io.atomix.messaging.Endpoint in project atomix by atomix.
the class DefaultClusterMetadataService method bootstrap.
/**
* Bootstraps the cluster metadata.
*/
private CompletableFuture<Void> bootstrap() {
Set<Endpoint> peers = nodes.values().stream().map(Node::endpoint).filter(endpoint -> !endpoint.equals(messagingService.endpoint())).collect(Collectors.toSet());
final int totalPeers = peers.size();
if (totalPeers == 0) {
return CompletableFuture.completedFuture(null);
}
AtomicBoolean successful = new AtomicBoolean();
AtomicInteger totalCount = new AtomicInteger();
AtomicReference<Throwable> lastError = new AtomicReference<>();
// Iterate through all of the peers and send a bootstrap request. On the first peer that returns
// a successful bootstrap response, complete the future. Otherwise, if no peers respond with any
// successful bootstrap response, the future will be completed with the last exception.
CompletableFuture<Void> future = new CompletableFuture<>();
peers.forEach(peer -> {
bootstrap(peer).whenComplete((result, error) -> {
if (error == null) {
if (successful.compareAndSet(false, true)) {
future.complete(null);
} else if (totalCount.incrementAndGet() == totalPeers) {
Throwable e = lastError.get();
if (e != null) {
future.completeExceptionally(e);
}
}
} else {
if (!successful.get() && totalCount.incrementAndGet() == totalPeers) {
future.completeExceptionally(error);
} else {
lastError.set(error);
}
}
});
});
return future;
}
use of io.atomix.messaging.Endpoint in project atomix by atomix.
the class AtomixAgent method parseEndpoint.
static Endpoint parseEndpoint(String[] address) {
String host;
int port;
if (address.length == 3) {
host = address[1];
port = Integer.parseInt(address[2]);
} else if (address.length == 2) {
try {
host = address[0];
port = Integer.parseInt(address[1]);
} catch (NumberFormatException e) {
host = address[1];
port = NettyMessagingService.DEFAULT_PORT;
}
} else {
try {
InetAddress.getByName(address[0]);
host = address[0];
} catch (UnknownHostException e) {
host = "0.0.0.0";
}
port = NettyMessagingService.DEFAULT_PORT;
}
try {
return new Endpoint(InetAddress.getByName(host), port);
} catch (UnknownHostException e) {
throw new IllegalArgumentException("Failed to resolve host", e);
}
}
use of io.atomix.messaging.Endpoint in project atomix by atomix.
the class AtomixAgent method main.
public static void main(String[] args) throws Exception {
ArgumentType<Node> nodeArgumentType = (ArgumentParser argumentParser, Argument argument, String value) -> {
String[] address = parseAddress(value);
return Node.builder(parseNodeId(address)).withType(Node.Type.CORE).withEndpoint(parseEndpoint(address)).build();
};
ArgumentType<Node.Type> typeArgumentType = (ArgumentParser argumentParser, Argument argument, String value) -> Node.Type.valueOf(value.toUpperCase());
ArgumentType<File> fileArgumentType = (ArgumentParser argumentParser, Argument argument, String value) -> new File(value);
ArgumentParser parser = ArgumentParsers.newArgumentParser("AtomixServer").defaultHelp(true).description("Atomix server");
parser.addArgument("node").type(nodeArgumentType).nargs("?").metavar("NAME:HOST:PORT").setDefault(Node.builder("local").withType(Node.Type.CORE).withEndpoint(new Endpoint(InetAddress.getByName("127.0.0.1"), NettyMessagingService.DEFAULT_PORT)).build()).help("The local node info");
parser.addArgument("--type", "-t").type(typeArgumentType).metavar("TYPE").choices("core", "data", "client").setDefault(Node.Type.CORE).help("Indicates the local node type");
parser.addArgument("--bootstrap", "-b").nargs("*").type(nodeArgumentType).metavar("NAME:HOST:PORT").required(false).help("Bootstraps a new cluster");
parser.addArgument("--http-port", "-p").type(Integer.class).metavar("PORT").required(false).setDefault(5678).help("An optional HTTP server port");
parser.addArgument("--data-dir", "-dd").type(fileArgumentType).metavar("FILE").required(false).setDefault(new File(System.getProperty("user.dir"), "data")).help("The server data directory");
parser.addArgument("--core-partitions", "-cp").type(Integer.class).metavar("NUM").required(false).setDefault(7).help("The number of core partitions");
parser.addArgument("--data-partitions", "-dp").type(Integer.class).metavar("NUM").required(false).setDefault(71).help("The number of data partitions");
Namespace namespace = null;
try {
namespace = parser.parseArgs(args);
} catch (ArgumentParserException e) {
parser.handleError(e);
System.exit(1);
}
Node localNode = namespace.get("node");
Node.Type type = namespace.get("type");
localNode = Node.builder(localNode.id()).withType(type).withEndpoint(localNode.endpoint()).build();
List<Node> bootstrap = namespace.getList("bootstrap");
if (bootstrap == null) {
bootstrap = Collections.singletonList(localNode);
}
File dataDir = namespace.get("data_dir");
Integer httpPort = namespace.getInt("http_port");
Integer corePartitions = namespace.getInt("core_partitions");
Integer dataPartitions = namespace.getInt("data_partitions");
LOGGER.info("node: {}", localNode);
LOGGER.info("bootstrap: {}", bootstrap);
LOGGER.info("data-dir: {}", dataDir);
Atomix atomix = Atomix.builder().withLocalNode(localNode).withBootstrapNodes(bootstrap).withDataDirectory(dataDir).withCorePartitions(corePartitions).withDataPartitions(dataPartitions).build();
Runtime.getRuntime().addShutdownHook(new Thread(() -> {
atomix.stop().join();
}));
atomix.start().join();
LOGGER.info("Atomix listening at {}:{}", localNode.endpoint().host().getHostAddress(), localNode.endpoint().port());
ManagedRestService rest = RestService.builder().withAtomix(atomix).withEndpoint(Endpoint.from(localNode.endpoint().host().getHostAddress(), httpPort)).build();
rest.start().join();
LOGGER.info("HTTP server listening at {}:{}", localNode.endpoint().host().getHostAddress(), httpPort);
synchronized (Atomix.class) {
while (atomix.isRunning()) {
Atomix.class.wait();
}
}
}
Aggregations