use of io.scalecube.transport.Message in project scalecube by scalecube.
the class ServiceProxyFactory method createProxy.
/**
* createProxy creates a java generic proxy instance by a given service interface.
*
* @param <T> service interface type
* @param serviceInterface the service interface, api, of the service.
* @param routerType the type of routing method class to be used.
* @param metrics optional performance metrics.
* @return newly created service proxy object.
*/
public <T> T createProxy(Class<T> serviceInterface, final Class<? extends Router> routerType, Duration timeout, Metrics metrics) {
ServiceDefinition serviceDefinition = serviceRegistry.registerInterface(serviceInterface);
dispatcher = microservices.dispatcher().router(routerType).timeout(timeout).create();
return Reflection.newProxy(serviceInterface, new InvocationHandler() {
@Override
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
Metrics.mark(serviceInterface, metrics, method, "request");
Object data = method.getParameterCount() != 0 ? args[0] : null;
final Message reqMsg = getRequestMessage(serviceDefinition, method, data);
if (method.getReturnType().equals(Observable.class)) {
if (Reflect.parameterizedReturnType(method).equals(Message.class)) {
return dispatcher.listen(reqMsg);
} else {
return dispatcher.listen(reqMsg).map(message -> message.data());
}
} else {
return toReturnValue(method, dispatcher.invoke(reqMsg));
}
}
private Message getRequestMessage(ServiceDefinition serviceDefinition, Method method, Object data) {
if (data instanceof Message) {
return Messages.builder().request(serviceDefinition.serviceName(), method.getName()).data(((Message) data).data()).build();
} else {
return Messages.builder().request(serviceDefinition.serviceName(), method.getName()).data(data).build();
}
}
private CompletableFuture<T> toReturnValue(final Method method, final CompletableFuture<Message> reuslt) {
final CompletableFuture<T> future = new CompletableFuture<>();
if (method.getReturnType().equals(Void.TYPE)) {
return (CompletableFuture<T>) CompletableFuture.completedFuture(Void.TYPE);
} else if (method.getReturnType().equals(CompletableFuture.class)) {
reuslt.whenComplete((value, ex) -> {
if (ex == null) {
Metrics.mark(serviceInterface, metrics, method, "response");
if (!Reflect.parameterizedReturnType(method).equals(Message.class)) {
future.complete(value.data());
} else {
future.complete((T) value);
}
} else {
Metrics.mark(serviceInterface, metrics, method, "error");
LOGGER.error("return value is exception: {}", ex);
future.completeExceptionally(ex);
}
});
return future;
} else {
LOGGER.error("return value is not supported type.");
future.completeExceptionally(new UnsupportedOperationException());
}
return future;
}
});
}
use of io.scalecube.transport.Message in project scalecube by scalecube.
the class TestStreamingService method test_unknown_method.
@Test
public void test_unknown_method() throws InterruptedException {
Microservices gateway = Microservices.builder().build();
Microservices node = Microservices.builder().seeds(gateway.cluster().address()).services(new SimpleQuoteService()).build();
ServiceCall service = gateway.dispatcher().create();
final CountDownLatch latch1 = new CountDownLatch(1);
Message scheduled = Messages.builder().request(QuoteService.NAME, "unknonwn").build();
try {
service.listen(scheduled);
} catch (Exception ex) {
if (ex.getMessage().contains("No reachable member with such service: unknonwn")) {
latch1.countDown();
}
}
latch1.await(2, TimeUnit.SECONDS);
assertTrue(latch1.getCount() == 0);
node.shutdown();
gateway.shutdown();
}
use of io.scalecube.transport.Message in project scalecube by scalecube.
the class SimpleStressTest method test_naive_proxy_stress.
@Test
public void test_naive_proxy_stress() throws InterruptedException, ExecutionException {
// Create microservices cluster member.
Microservices provider = Microservices.builder().port(port.incrementAndGet()).services(new GreetingServiceImpl()).metrics(registry).build();
// Create microservices cluster member.
Microservices consumer = Microservices.builder().port(port.incrementAndGet()).seeds(provider.cluster().address()).metrics(registry).build();
reporter.start(10, TimeUnit.SECONDS);
// Get a proxy to the service api.
GreetingService service = consumer.proxy().api(// create proxy for GreetingService API
GreetingService.class).timeout(Duration.ofSeconds(30)).create();
// Measure
CountDownLatch countLatch = new CountDownLatch(count);
long startTime = System.currentTimeMillis();
for (int i = 0; i < count; i++) {
CompletableFuture<Message> future = service.greetingMessage(Message.fromData("naive_stress_test"));
future.whenComplete((success, error) -> {
if (error == null) {
countLatch.countDown();
} else {
System.out.println("failed: " + error);
fail("test_naive_stress_not_breaking_the_system failed: " + error);
}
});
}
System.out.println("Finished sending " + count + " messages in " + (System.currentTimeMillis() - startTime));
countLatch.await(60, TimeUnit.SECONDS);
System.out.println("Finished receiving " + (count - countLatch.getCount()) + " messages in " + (System.currentTimeMillis() - startTime));
System.out.println("Rate: " + ((count - countLatch.getCount()) / ((System.currentTimeMillis() - startTime) / 1000)) + " round-trips/sec");
reporter.stop();
assertTrue(countLatch.getCount() == 0);
provider.shutdown().get();
consumer.shutdown().get();
}
use of io.scalecube.transport.Message in project scalecube by scalecube.
the class GracefulShutdownTest method test_gracefull_shutdown.
@Test
public void test_gracefull_shutdown() throws InterruptedException {
// create cluster members with 3 nodes: gateway, node1, node2
// node 1 and 2 provision GreetingService instance (each).
Members members = Members.create();
// get a proxy to the service api.
ServiceCall service = members.gateway().dispatcher().create();
// call the service.
AtomicInteger count = new AtomicInteger(3);
Message request = Messages.builder().request(GreetingService.class, "greeting").data("joe").build();
AtomicInteger postShutdown = new AtomicInteger(3);
// continue with the test while node1 is still active in the cluster
while (members.gateway().cluster().member(members.node1().cluster().address()).isPresent() || postShutdown.get() >= 0) {
CompletableFuture<Message> future = service.invoke(request);
future.whenComplete((result, ex) -> {
if (ex == null) {
// print the greeting.
assertTrue(result.data().equals(" hello to: joe"));
System.out.println(count.get() + " - Response from node: " + result.sender());
count.decrementAndGet();
} else {
// if one request fails fail the test
fail();
// print the greeting.
System.out.println(ex);
Exceptions.propagate(ex);
}
});
if (count.get() == 0) {
// node1 leave the cluster after on 0.
members.node1().cluster().shutdown();
}
// node still answer requests as its only half stopped.
if (!members.gateway().cluster().member(members.node1().cluster().address()).isPresent()) {
postShutdown.decrementAndGet();
}
sleep(1000);
}
members.shutdown();
}
use of io.scalecube.transport.Message in project scalecube by scalecube.
the class DispatchingFutureTest method test_dispatching_future.
@Test
public void test_dispatching_future() throws Exception {
Microservices member = Microservices.builder().build();
ServiceResponse response = ServiceResponse.correlationId(IdGenerator.generateId());
Message request = Message.builder().correlationId(response.correlationId()).header(ServiceHeaders.SERVICE_RESPONSE, "").build();
Field field = Message.class.getDeclaredField("sender");
field.setAccessible(true);
field.set(request, member.cluster().address());
DispatchingFuture dispatcher = DispatchingFuture.from(member.sender(), request);
dispatcher.complete(new Throwable());
CountDownLatch latch = new CountDownLatch(1);
response.future().whenComplete((result, error) -> {
assertTrue(error != null);
latch.countDown();
});
response.complete(Message.builder().header("exception", "true").data(new Exception()).build());
latch.await(1, TimeUnit.SECONDS);
assertTrue(latch.getCount() == 0);
member.shutdown();
}
Aggregations