= Vertx-Sync

Vertx-sync is a set of utilities that allow you to perform asynchronous operations and receive events in a
synchronous way, but without blocking kernel threads.

== Introduction

One of the key advantages of Vert.x over many legacy application platforms is that it is almost entirely non-blocking
(of kernel threads) - this allows it to handle a lot of concurrency (e.g. handle many connections, or messages) using
a very small number of kernel threads, which allows it to scale very well.

The non blocking nature of Vert.x leads to asynchronous APIs. Asynchronous APIs can take various forms including
callback style, promises or Rx-style. Vert.x uses callback style in most places (although it also supports Rx).

In some cases, programming using asynchronous APIs can be more challenging than using a direct synchronous style, in
particular if you have several operations that you want to do in sequence. Also error propagation is often more complex
when using asynchronous APIs.

Vertx-sync allows you to work with asynchronous APIs, but using a direct synchronous style that you're already
familiar with.

It does this by using `fibers`. Fibers are very lightweight threads that do not correspond to underlying kernel threads.
When they are blocked they do not block a kernel thread.

Vert-sync uses http://docs.paralleluniverse.co/quasar/[Quasar] to implement the fibers.

NOTE: Vert-sync currently only works with Java.

== SyncVerticle

In order to use vertx-sync you must deploy your code as instances of `io.vertx.ext.sync.SyncVerticle`.
You should override the `start()` and (optionally) the `stop()` methods of the verticle.

Those methodsmust* be annotated with the `@Suspendable` annotation.

Once you've written your sync verticle(s) you deploy them in exactly the same way as any other verticle.

== Instrumentation

Vert.x uses Quasar which implements fibers by using bytecode instrumentation. This is done at run-time using a java
agent.

In order for this to work you must start the JVM specifying the java agent jar which is located in the quasar-core
jar.

TODO how to reference quasar core jar in fatjar?

----
-javaagent:/path/to/quasar/core/quasar-core.jar
----

If you are using the `vertx` command line tools, the agent configuration can be enabled by setting the `ENABLE_VERTX_SYNC_AGENT`
environment variable to `true`, before executing `vertx`.

You can also use a offline instrumentation as with the https://github.com/vy/quasar-maven-plugin[quasar-maven-plugin] or  or https://github.com/mtatheonly/quasar-gradle-plugin[quasar-gradle-plugin].
Check the http://docs.paralleluniverse.co/quasar/[Quasar documentation] for more details.

== Getting one-shot async results

Many async operations in Vert.x-land take a `Handler<AsyncResult<T>>` as the last argument. An example would
executing a find using the Vert.x Mongo client or sending an event bus message and getting a reply.

Vertx-sync allows you to get the result of a one-shot asynchronous operation in a synchronous way.

This is done by using the `link:../../apidocs/io/vertx/ext/sync/Sync.html#awaitResult-java.util.function.Consumer-[Sync.awaitResult]` method.

The method is executed specifying the asynchronous operation that you want to execute in the form of a `link:../../apidocs/java/util/function/Consumer.html[Consumer]`,
the consumer is passed the handler at run-time.

Here's an example:

[source,java]
----
EventBus eb = vertx.eventBus();

// Send a message and get the reply synchronously

Message<String> reply = awaitResult(h -> eb.request("someaddress", "ping", h));

System.out.println("Received reply " + reply.body());
----

In the above example the fiber is blocked until the reply is returned but no kernel thread is blocked.

== Getting one-shot events

Vertx-sync can be used to get one-shot events in a synchronous way, for example firings of timers, or the executing of
an end handler. This is achieved using the `link:../../apidocs/io/vertx/ext/sync/Sync.html#awaitEvent-java.util.function.Consumer-[Sync.awaitEvent]` method.

Here's an example:

[source,java]
----
long tid = awaitEvent(h -> vertx.setTimer(1000, h));

System.out.println("Timer has now fired");
----

== Streams of events

In many places in Vert.x streams of events are provided by passing them to handlers.

Examples include event bus message consumers and HTTP server requests on an HTTP server.

Vert-sync allows you to receive events from such streams in a synchronous way.

You do this with an instance of `link:../../apidocs/io/vertx/ext/sync/HandlerReceiverAdaptor.html[HandlerReceiverAdaptor]` which implements both
`link:../../apidocs/io/vertx/core/Handler.html[Handler]` and `link:../../apidocs/io/vertx/ext/sync/Receiver.html[Receiver]`. You create an instance using
`link:../../apidocs/io/vertx/ext/sync/Sync.html#streamAdaptor--[Sync.streamAdaptor]`.

You can set it as a normal handler and then use the methods on `link:../../apidocs/io/vertx/ext/sync/Receiver.html[Receiver]` to receive
events synchronously.

Here's an example using an event bus message consumer:

[source,java]
----
EventBus eb = vertx.eventBus();

HandlerReceiverAdaptor<Message<String>> adaptor = streamAdaptor();

eb.<String>consumer("some-address").handler(adaptor);

// Receive 10 messages from the consumer:
for (int i = 0; i < 10; i++) {

  Message<String> received1 = adaptor.receive();

  System.out.println("got message: " + received1.body());

}
----

== Using a `FiberHandler`

If you want to do use fibers in a normal handler, e.g. in the request handler of an Http Server then you must first
convert the normal handler to a fiber handler.

The fiber handler runs the normal handler on a fiber.

Here's an example:

[source,java]
----
EventBus eb = vertx.eventBus();

vertx.createHttpServer().requestHandler(fiberHandler(req -> {

  // Send a message to address and wait for a reply
  Message<String> reply = awaitResult(h -> eb.request("some-address", "blah", h));

  System.out.println("Got reply: " + reply.body());

  // Now end the response
  req.response().end("blah");

})).listen(8080, "localhost");
----

== Further examples

There are a set of working examples demonstrating vertx-sync in action in the
https://github.com/vert-x3/vertx-examples/tree/master/sync-examples[examples repository]

== What if you get exceptions?

Quasar and co-routines do not _"automagically"_ transform blocking code into non-blocking code.
Especially, blocking using `Thread.sleep` or using `synchronized` blocks and methods _is_ a problem.

There are 2 types of exceptions that you may observe when using `vertx-sync`.

=== Instrumentation warnings

You may encounter stack traces like the following in your logs:

----
(...)
[quasar] ERROR: while transforming io/vertx/core/impl/DeploymentManager$DeploymentImpl: Unable to instrument vertx/core/impl/DeploymentManager$DeploymentImpl#lambda$rollback$1(Ljava/lang/Throwable;Lio/vertx/core/impl/ContextInternal;Lio/vertx/core/Handler;/vertx/core/impl/ContextImpl;Lio/vertx/core/AsyncResult;)V because of synchronization
co.paralleluniverse.fibers.instrument.UnableToInstrumentException: Unable to instrument vertx/core/impl/DeploymentManager$DeploymentImpl#lambda$rollback$1(Ljava/lang/Throwable;Lio/vertx/core/impl/ContextInternal;Lio/vertx/core/Handler;/vertx/core/impl/ContextImpl;Lio/vertx/core/AsyncResult;)V because of synchronization
       at co.paralleluniverse.fibers.instrument.InstrumentMethod.dumpCodeBlock(InstrumentMethod.java:720)
       at co.paralleluniverse.fibers.instrument.InstrumentMethod.accept(InstrumentMethod.java:415)
       at co.paralleluniverse.fibers.instrument.InstrumentClass.visitEnd(InstrumentClass.java:265)
(...)
----

These errors are actually warnings from Quasar as it tries to instrument both your code and libraries (including Vert.x modules!).

Quasar may encounter blocking constructs such as thread blocking and `synchronized` blocks or methods.
There is sometimes little you can do, but this does not mean that your application will not be functional.

There are just some parts reported by Quasar where coroutines may block without being able to yield execution to another coroutine.

=== Calling fiber code from outside a fiber

You may encounter exceptions that prevent your application to function, such as:

----
(...)
io.vertx.core.VertxException: java.lang.IllegalThreadStateException: Method called not from within a fiber
       at co.paralleluniverse.fibers.FiberAsync.requestSync(FiberAsync.java:289)
       at co.paralleluniverse.fibers.FiberAsync.runSync(FiberAsync.java:255)
       at co.paralleluniverse.fibers.FiberAsync.run(FiberAsync.java:111)
(...)
----

This happens when you call fiber code (e.g., a method annotated with `@Suspendable`) from outside a fiber, such as from an event-loop thread.

In most of the cases the solution lies in wrapping the call to the first fiber code using one of the helper methods from `link:../../apidocs/io/vertx/ext/sync/Sync.html[Sync]`: `awaitResult`, `awaitEvent`, `fiberHandler` and `streamAdaptor`.

Suppose that we have a fiber method like the following:

[source,java]
----
@Suspendable
public String readData() {
 boolean exists = Sync.awaitResult(h -> vertx.fileSystem().exists("file.txt", h));
 if (exists) {
   Buffer buf = Sync.awaitResult(h -> vertx.fileSystem().readFile("file.txt", h));
		 return buf.toString();
 }
 return "";
}
----

Now suppose that we want to call this method in response to an event-bus method.
To ensure that the event-bus message processing is from a fiber and we can call the `readData` method, then we need adapting with `fiberHandler`:

[source,java]
----
vertx.eventBus().consumer("read", Sync.fiberHandler(m -> m.reply(readData())));
----

Conversely, if you do not use `fiberHandler` then you will get an exception as above:

[source,java]
----
// This crashes!
vertx.eventBus().consumer("read", m -> m.reply(readData()));
----

TIP: If you need more flexibility you can always use `link:../../apidocs/io/vertx/ext/sync/Sync.html#getContextScheduler--[Sync.getContextScheduler]` to access the verticle context scheduler and start Quasar fibers / strands.