Rick

Rick
Rick

Wednesday, May 4, 2016

Reactive Java with Reakt

Reactive Java with Reakt

It might seem like Reakt is brand new. But it is not brand new. Most of what is in Reakt existed in QBit for years. But after working with Node.js and JavaScript promises, we realized we could write a lot cleaner interface. Instead of QBit's CallbackBuilder (QBits original Promise library) and Reactor we are moving towards Reakt promises, streams and the Reakt Reactor.
The trick for async and reactive programming is not the streams, it is the call coordination.

What is Reakt again?

If you are not familiar with Reakt. There was an informative interview about Reakt, and QBit has started to support Reakt as a first class citizen. You should start with the Reakt websiteand the Reakt documentation. You can use Reakt with any async lib including async NoSQL drivers.

Understanding managing callbacks

You want to async call serviceA, then serviceB, take the results of serviceA & serviceB, then call serviceC. Then based on the results of call C, call D or E and then return the results to the original caller. Calls to ABCD and E are all async calls and none should take longer than 10 seconds, if they do, then return a timeout to the original caller.
Let's say that the whole async call sequence should timeout in 20 seconds if it does not complete, and also check for circuit breakers, and provide back pressure feedback so the system does not have cascading failures. QBit is really good at this, but creating the Reactor (QBit's callback and task manager is called Reactor) was trial by fire. It was created while using it at scale, and was created while needing something like it and not finding anything. Which did great for the quick evolution of QBit's Reactor but its design could improve as well as its ease-of-use (although these were goals). QBit Reactor is quite good, but we could do better. QBit call coordination is goodReakt's will be better, and it is already useful.

Continous improvement

Reakt gives us a chance to work on QBit 2 call coordination and pull out async call coordinationinto a lib that can use be used with other projects that don't use QBit. This is the goal with Reakt.Reakt already has extention libraries for Guava/Cassandra and Vert.xReakt is also supported byQBit, a reactive microservice lib. The Reakt library can work with any JVM async framework. It is not tied to QBit microservices lib.

Next steps with Reakt

Reakt IO, which is in progress, will sit on top of Vertx or Conekt (a lightweight Netty IO lib that we are working on). Reakt IO provides a common interface for lightweight IO libs. Reakt provides promises and streams that are Java 8 lambda expression friendly (Groovy closure friendly, Kotlin closures friendly, Scala closure friendly, and Jython lambda friendly too).

When can I use Reakt

Now. QBit, which is a Java microservice lib, can handle call coordination like this at scale. It works. But this call coordination does not need to live in QBit. Thus Reakt was born. Reakt is already very useful and innovative and can be used with Vert.xGuavaCassandra and more.Reakt is laser focused on async call coordination on the JVM, and making that experience clean and enjoyable.

Reactive programming

Reactive programming is not a new paradigm. Reactive programming centers around data event flows and propagation of change. There are many example of reactive programming like spreadsheet updates, the Swing event loop, the Vert.x event bus, Node.js event loop and the JavaScript browser event loop.
Reactive programming often is at the core of interactive user interfacesModel-view-controller, simulations, real time animations, but can also be used to for reactive microservice development. It is a general technique with many applications.
You can even manage complex data flows and transformations using tools like Spark. You can do amazing near real time big data transformation using reactive streams, and tools like SparkFunctional reactive programming has its place, and is increasingly used to process large streams of data into useable information in near real time. However, there is a much more common and mundane use of reactive programming.

Object-oriented reactive programming

Object-oriented reactive programming (OORP) combines object oriented programming withreactive programming. This has become a very popular model with tools like AngularReact andjQueryjQuery and other libs also manage call coordination with Promises. Promises are a very common way to manage streams of event data into actionable responses. Promises have become so popular in the JavaScript/Node.js world that Promises are part of ES6.

Promise vs streams

Events and Streams are great for things that can happen multiple times — keyup, touchstart, or event a user action stream from Kafka, etc.
With those events you don't really care about what happened before when you attached the listener.
But often times when dealing with service calls and data repositories, you want to handle a response with a specific next action, and a different action if there was an error or timeout from the responses. You essentially want to call and handle a response asynchronously and that is what promises allow.
At their most basic level, promises are like event listeners except:
A promise can only succeed or fail once. A promise cannot succeed or fail twice, neither can it switch from success to failure. Once it enters its completed state, then it is done.

Reakt Promises

Reakt promises are very similar in concept to ES6 promises, which have become standardized in the JavaScript/TypeScript/ES5/ES6/ES7 pantheon on languages.
A promise can be:
  • fulfilled The callback relating to the promise succeeded
  • rejected The callback/action relating to the promise failed
  • pending The callback has not been fulfilled or rejected yet
  • completed The callback/action has been fulfilled/resolved or rejected
Java is not single threaded, meaning that two bits of code can run at the same time, so the design of this promise and streaming library takes that into account. We came out with many tools that adapt the Promise constructs (single threaded event loop in JavaScript) to the Java world (multi-threaded, race condition possibilities, thread visibility, etc.).
There are three types of promises:
  • Callback promises (async)
  • Blocking promises (for testing and legacy integration)
  • Replay promises (allow promises to be handled on the same thread as caller, managed by aReactor)
Unlike their JavaScript cousins that do not have to worry about thread safety. Promises in Reakt can be invokable.
Promises can be very fluent.

Passing a promise as a callback handler

        employeeService.lookupEmployee(33, result -> {
            result.then(e -> saveEmployee(e))
                  .catchError(error -> {
                    logger.error("Unable to lookup", error);
            });
        });
Promises in Java become even more fluent when you use invokable promises.

Using an invokable promise

        employeeService.lookupEmployee("123")
               .then((employee)-> {...}).catchError(...).invoke();
Replay promises are the most like their JS cousins. Replay promises are usually managed by theReakt Reactor and supports environments like Vert.xAkkaReactorNetty, async noSQL drivers and QBit.
It is common to make async calls to store data in a NoSQL store or to call a remote REST interface or deal with a distributed cache or queue. Also Java is strongly typed so the library that mimics JS promises is going to look a bit different. Reakt uses similar terminology to ES6 promises where it makes sense.
We have been on projects where we wrote libs in JS and Java that did very similar things and the promise code for ES6 and Java looks close to the point where we have to take a double look to decide which language we are working with.

Conclusion

QBit has had Promises for a few years now, but they were called them CallbackBuilders instead and were not as easy-to-work with. Reakt focuses using standard terminology and ease-of-use. With Reakt you can use the same terminology and modeling on projects that do not use QBit, reactive microservices lib like Conekt, Vert.xRxJavaProject ReactorLightbend, and reactive streams.

No comments:

Post a Comment

Kafka and Cassandra support, training for AWS EC2 Cassandra 3.0 Training