Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Rest return CompletableFuture #30

Closed
tnguyen-lh opened this issue Jul 12, 2018 · 1 comment
Closed

Rest return CompletableFuture #30

tnguyen-lh opened this issue Jul 12, 2018 · 1 comment

Comments

@tnguyen-lh
Copy link

tnguyen-lh commented Jul 12, 2018

This is not quite a bug, but when I use the example of return Future, the return is actually the future object, not the Dummy content, I have modified this way, it is working and return the the json. However, I don't know whether I am blocking vertx main thread or not. Could you please advice?

        @POST
	@Path("/save")
	@Consumes(MediaType.APPLICATION_JSON)
	@Produces(MediaType.APPLICATION_JSON)
	public Product save(Product product) throws InterruptedException, ExecutionException {
		CompletableFuture<Product> result = productService.saveProduct(product);
		result.thenAccept(p -> {
			System.out.println("Product: " + p);
		});
		return result.get();

	}
@drejc
Copy link
Member

drejc commented Jul 12, 2018

The difference between the Future<> and "normal" execution is in the way vert.x is thread pool is used.

In the "normal" way vert.x is called:

context -> context.vertx().executeBlocking(
			// code execution,
			false, // not ordered
			// produce response)

As per vertx documentation:

By default, if executeBlocking is called several times from the same context (e.g. the same verticle instance) then the different executeBlocking are executed serially (i.e. one after another).
If you don’t care about ordering you can call executeBlocking specifying false as the argument to ordered. In this case any executeBlocking may be executed in parallel on the worker pool.
An alternative way to run blocking code is to use a worker verticle
A worker verticle is always executed with a thread from the worker pool.
By default blocking code is executed on the Vert.x worker pool, configured with setWorkerPoolSize.

in the "future" way vert.x is called:

return context -> {		
				Future result = method.invoke(toInvoke, args);
					result.setHandler(handler -> {
// produce response
})

Meaning you have control over the thread pool execution part and executor used.

So you can manually create an execution pool of your own ... for instance:

WorkerExecutor executor = vertx.createSharedWorkerExecutor("myExecutor", 10);   

and in your service you use the executor:

@GET
	@Path("executor")
	@Produces(MediaType.APPLICATION_JSON)
	public Future<Dummy> executor(@Context Vertx vertx) throws InterruptedException {
		Future<Dummy> res = Future.future();
		service.asyncExecutor(executor, res);
		System.out.println("Rest finished");
		return res;
	}

Where:

public void asyncExecutor(WorkerExecutor executor, Future<Dummy> value) {
		executor.executeBlocking(fut -> {
			                         System.out.println("Process started!");
			                        // do something
			                         fut.complete();
		                         },
		                         false,
		                         fut -> {
                                              System.out.println("Process finished!");
		                         });
	}

In this case console output would be:

Rest finished
Process started!
Process finished!

It might be useful to create a wrapper to hide the Future<> implementation and provide a way to create a thread execution pool via annotations ... not sure if this is a good idea.

To get back to your question ... in my book I would avoid using the Future<> type implementation and configure vert.x pool to handle the appropriate load.
If you really need control over the WorkerPool then go with the Future<> type

Hope this gives a clearer picture ... will try to improve the documentation on this part as it is a little vague.

PS: I'm in the process of implementing an Event type system to send messages to the vert.x EventBus for long operations or other non critical async operations. This is very useful in case you need to do something but don't want to block the REST thread ... for instance count how many times an API has been invoked, log something ... or just start a long operation and immediately return a response, ... so stay tuned for that.

@drejc drejc closed this as completed Jul 12, 2018
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

2 participants