Rick

Rick
Rick

Thursday, May 5, 2016

Reactive Java code examples using Reakt (with links to docs for further info)

This is a presentation of different Reakt features in the context of a real application. I have renamed the classnames and such, but this is from an in-progress microservice. It demonstrates where you would use the Reakt pieces to build a reactive Java application.
This covers usage of Reakt:
  • blocking promises
  • Promises.all
  • invokable promise
  • Expected values
  • Circuit breakers
  • Working with the Reactor
  • Working with streams
  • Using AsyncSuppliers to create downstream services
  • Reakt Guava integration
  • Using promise.thenMap

Blocking promise example

Let's say you have an async microservices application, and you want to write some unit and integration tests. You want the tests to wait until the system starts up. Rather you want the system to notify the test when it is done loading.
NOTE: The examples below are written in Kotlin which is a JVM language from Idea. I use Kotlin because the example are easier to read and take up less space. If you know Java 8, you should follow no problem. Think of it like pseudo code. Kotlin works well with Java classes and such.

Loading a system for testing.

import io.advantageous.qbit.util.PortUtils
import io.advantageous.reakt.AsyncSupplier
import io.advantageous.reakt.promise.Promises

object DFTestUtils {

    val adminPort : AtomicInteger = AtomicInteger(9090)
    val eventBusPort : AtomicInteger = AtomicInteger(8080)

    fun loadSystem(): ServicePlatform {
        /** Load System. */
        val loadPromise = Promises.blockingPromiseNotify(Duration.ofSeconds(4))
        val servicePlatform = servicePlatform().withNamespace(Constants.TODO_SERVICE)
                .setWaitForStartup(true).setAdminPort(PortUtils.findOpenPortStartAt(adminPort.andIncrement))
                .setEventBusPort(PortUtils.findOpenPortStartAt(eventBusPort.andIncrement))
        Main.run(servicePlatform).invokeWithPromise(loadPromise)

        loadPromise.get() //Wait for the system to load before we start.
        Assert.assertFalse("system loaded", loadPromise.failure())
        return servicePlatform
    }
Notice that we create a promising using Promises.blockingPromiseNotify(Duration.ofSeconds(4)). We call loadPromise.get() to wait until the system loads. Blocking promises are good for testing.
Now we can use the loadSystem in our tests. Here is a test that does a health check against a running server.

Using loadSystem / blocking promise in our test

    @Test
    @Throws(Exception::class)
    fun mainHealthCheckTest() {

        val servicePlatform = loadSystem()
        val httpTextResponse = HttpClientBuilder.httpClientBuilder().setPort(servicePlatform.adminPort)
                .buildAndStart().get("/__admin/ok")

        assertNotNull(httpTextResponse)
        assertEquals("true", httpTextResponse.body())
        assertEquals(200, httpTextResponse.code().toLong())

        shutdownSystem(servicePlatform)
    }

Using invokable promises to notify when the entire system is done loading

The actual code that loads our system uses an invokable promise.

Load system calls Main.run which returns an invokable promise

import io.advantageous.reakt.AsyncSupplier
import io.advantageous.reakt.Callback
import io.advantageous.reakt.Stream
import io.advantageous.reakt.promise.Promise
import io.advantageous.reakt.promise.Promises.*
object Main {

...
    var repoServiceQueue: ServiceQueue? = null
    private val logger = LoggerFactory.getLogger(Main::class.java)
...
    fun main(args: Array<String>) {
        run(servicePlatform().withNamespace(TODO_SERVICE)).invoke()
    }

...
    fun run(servicePlatform: ServicePlatform): Promise<Void> {
        return invokablePromise { donePromise ->

            val loadCollectionServicePromise = promiseBoolean()
            val loadTodoServicePromise = promiseBoolean()

            val loadPromise = all(loadCollectionServicePromise,
                    loadTodoServicePromise)
                    .thenPromise(donePromise)

            createCollectionService(servicePlatform, loadPromise)
            createTodoServiceService(servicePlatform, loadPromise)
            servicePlatform.start()
        }
    }

Working with Promises.all

There is a lot going on here. The run method is using Promises.invokablePromise. Then the run method uses Promises.all to chain the promise loadCollectionServicePromise and loadTodoServicePromise together. The method Promises.all is used when you want all of the promises to trigger then the all promise triggers. This way you are being notified when both the createCollectionService and the createTodoServiceService async reply. You don't want to start testing before the system is initialized.

Working with Reakt Streams

The project that I am working on uses leader election from elekt. Elekt, leadership API lib, uses Reakt streams. For testing, we just simulate the Elekt consul support.
The LeaderElector looks like this:

LeaderElector uses Reakt streams support

public interface LeaderElector {

    /**
     * Attempt to elect this service as leader.
     * Returns true if successful, and false if not successful.
     * @param endpoint endpoint describes the host and port of the leader.
     * @param callback callback
     */
    void selfElect(final Endpoint endpoint, final Callback<Boolean> callback);

    /**
     *
     * This will send leadership changes as the occur over the stream.
     *
     * @param callback callback returns new leader.
     */
    void leadershipChangeNotice(final Stream<Endpoint> callback);

    /**
     *
     * This will come back quickly with a new Leader.
     * If no Endpoint is returned in the callback then there is no leader.
     *
     * @param callback callback returns new leader.
     */
    void getLeader(final Callback<Endpoint> callback);


}
To simulate that for integration testing, we use this mock LeaderElector.

Using a test LeaderElector stream for integration testing

    private fun createLeaderElector(): Supplier<LeaderElector> {
        return Supplier {
            object : LeaderElector {
                override fun leadershipChangeNotice(stream: Stream<Endpoint>?) {
                    logger.info("Leader notice registered")
                    val idOfServer = Identity()
                    stream?.reply(Endpoint(idOfServer.host, idOfServer.servicePort))
                    Thread({
                        Thread.currentThread().isDaemon = true
                        while (true) {
                            Thread.sleep(1000 * 10)
                            stream?.reply(Endpoint(idOfServer.host, idOfServer.servicePort))
                        }
                    })
                }

                override fun selfElect(endpoint: Endpoint?, callback: Callback<Boolean>?) {
                    logger.info("Self elect was called")
                    callback?.resolve(true);
                }

                override fun getLeader(callback: Callback<Endpoint>?) {
                    logger.info("Self elect was called")
                    val idOfServer = Identity()
                    callback?.resolve(Endpoint(idOfServer.host, idOfServer.servicePort))
                }
            }
        }
    }
Notice the call to stream.reply to send a stream of leader elect notifications that this server has been elected the leader.

Reakt Expected and Circuit breakers

It is important to monitor the health of your system, and sometimes it is good not to beat a dead horse. If downstream services are broken there is no point in using them until the are fixed. In Reakt we use Circuit Breakers and Expected to handle when some service is support to be there or some value is expected.
Let's demonstrate this with MetricsCollectionServiceImpl.

MetricsCollectionServiceImpl

import io.advantageous.reakt.Breaker
import io.advantageous.reakt.Breaker.*
import io.advantageous.reakt.Expected
import java.util.function.Function
import java.util.function.Supplier

/**
 * Metrics Collection Service.
 * Manages finding leader with LeaderElector.
 */
class MetricsCollectionServiceImpl
/**
 * @param mgmt                            ServiceManagementBundle (from QBit)
 * *
 * @param leaderElectorSupplier           leaderElectorSupplier for connecting to the leader elector.
 * *
 * @param todoListServiceSupplier todoListServiceSupplier for connecting
 * *                                        to the todo service.
 * *
 * @param metricRepository                metric repo for storing metrics
 */
(
        /**
         * Service management bundle which includes stats collection, Reakt reactor, QBit health management, and more.
         */
        private val mgmt: ServiceManagementBundle,
        /**
         * Supplies a leader elector interface. LeaderElector is from Elekt.
         */
        private val leaderElectorSupplier: Supplier<LeaderElector>,
        /**
         * This is used to create a supplier.
         */
        private val todoListServiceSupplier: Function<Endpoint, TodoServiceClient>,
        /**
         * Metric repository for saving repositories.
         */
        private val metricRepository: MetricRepositoryClient)
: MetricsCollectionService {


    /**
     * The current leaderEndpoint which starts out empty.
     */
    private var leaderEndpoint = Expected.empty<Endpoint>()
    /**
     * The actual todoService wrapped in a Reakt Circuit breaker.
     */
    private var todoService = Breaker.opened<TodoServiceClient>()
    /**
     * The leader elector we are using, wrapped in Reakt Circuit breaker
     */
    private var leaderElectorBreaker: Breaker<LeaderElector> = Breaker.opened()
    /**
     * Call count per second.
     */
    private var callCount: Long = 0

    init {
        /*
         * Check circuit breaker health every 10 seconds.
         */
        mgmt.reactor().addRepeatingTask(seconds(10)) {
            healthCheck()
        }
        createLeaderElector()
        mgmt.reactor().addRepeatingTask(seconds(1)) { throughPut() }
        mgmt.reactor().addRepeatingTask(millis(100), { flushService(metricRepository) })
    }
Notice that we are using Reakt circuit breakers. Notice we are using Reakt reactor's Reactor.addRepeatingTask to periodically check the health of our repo. Reakt's Reactor is used to manage callbacks so they execute on this thread, callback timeouts, and repeating tasks.
Let's look at the healthCheck that runs every 10 seconds to see how circuit breakers work.

healthCheck that runs every 10 seconds via a Reakt Reactor task

    private fun healthCheck() {
        if (mgmt.isFailing) {
            logger.warn("CollectionService Health is suspect")
        } else {
            logger.debug("CollectionService is Healthy")
        }

        leaderElectorBreaker.ifBroken {
            createLeaderElector()
        }

         /* If the TODO service is broken, i.e. the circuit is open then do... */
        todoService.ifBroken {
            /* Check to see if we have a leaderEndpoint. */
            leaderEndpoint
                    .ifPresent { leaderEndpoint ->
                        this.handleNewLeader(leaderEndpoint)
                    }
                    /* If we don't have a leaderEndpoint, then look it up. */
                    .ifEmpty {
                        /* Look up the endpoint if the elector is not broken. */  
                        leaderElectorBreaker
                                .ifOk { elector ->
                                    this.lookupLeader(elector)
                                }
                                .ifBroken {
                                    logger.warn("We have no leader and the leader elector is down")
                                }
                    }
        }
    }
The leaderEndpoint is an expected value that might not exist. The methods ifOk and ifBroken are from circuit breaker. The ifOk means the fuse it not burned out. The ifBroken means the fuse blew. As you can see combining Expected values and services wrapped in Breakers allows us to simplify and reasoning on what to do if things go down.
When a fuse opens or breaks, then we can work around it. Here is how we mark a broken breaker.

Marking a service Breaker as broken (the fuse is open)

        try {
            leaderElectorBreaker = Breaker.operational(leaderElectorSupplier.get())
            leaderElectorBreaker
                    .ifOk { this.lookupLeader(it) }
                    .ifBroken {
                        logger.error("Unable to connect to leader supplier")
                    }

            if (leaderElectorBreaker.isOk)
                mgmt.increment("leader.elector.create.success")
            else
                mgmt.increment("leader.elector.create.fail")

            leaderElectorBreaker.ifOk {
                this.handleElectionStream(it)
            }
        } catch (ex: Exception) {
            mgmt.increment("leader.elector.create.fail.exception")
            logger.error("Unable to connect to leader supplier", ex)
            leaderElectorBreaker = Breaker.broken<LeaderElector>()
        }
Notice the use of Breaker.operational to denote that we have a new service to work with that should work. Then if the service fails, we mark it has broken with Breaker.broken.

Working with Reakt Streams

Here is us handling the election stream that we showed a mock-up of earlier.

Working with Reakt Streams

    private fun handleElectionStream(leaderElector: LeaderElector) {
        leaderElector.leadershipChangeNotice { result ->
            result
                    .catchError { error -> // Run on this service thread
                        mgmt.reactor()
                                .deferRun {
                                    logger.error("Error handling election stream")
                                    mgmt.increment("leader.stream.elect.error")
                                    this.leaderElectorBreaker = broken<LeaderElector>()
                                    createLeaderElector()
                                }
                    }
                    .then { endpoint -> // Run on this service thread
                        mgmt.reactor().deferRun {
                            mgmt.increment("leader.stream.elect.notify")
                            logger.info("New Leader Notify {} {}", endpoint.host, endpoint.port)
                            handleSuccessfulLeaderLookupOrStream(endpoint)
                        }
                    }
        }
    }
Notice that we use reactor.deferRun so we can handle this stream on this services thread.
Now let's show another example of Promises.all. We have a Cassandra service that wants to write a heap of records to the DB. It wants to write the records in parallel.
/**
 * Stores Metric data and results into Cassandra.
 */
internal class CassandraMetricRepository
/**
 * @param sessionAsyncSupplier supplier to supply Cassandra session.
 * @param serviceMgmt              serviceMgmt to manage callbacks and repeating tasks.
 * @param promise              returns when cassandra initializes.
 *
 */
(
        /**
         * Cassandra Session supplier.
         */
        private val sessionAsyncSupplier: AsyncSupplier<Session>,
        /**
         * QBit serviceMgmt for repeating tasks, stats, time and callbacks that execute on the caller's thread.
         */
        private val serviceMgmt: ServiceManagementBundle,
        promise: Promise<Boolean>) : MetricRepositoryService {
    /**
     * generate the sequence for backup.
     */
    private val sequenceGen = AtomicLong(2)
    /**
     * Reference to the cassandra session which get connected to async.
     */
    private var sessionBreaker = Breaker.opened<Session>()
    /**
     * Error counts from Cassandra driver for the last time period.
     */
    private val errorCount = AtomicLong()
...
Notice that we create our sessionBreaker, which is our reference to Cassandra as an opened Circuit. We define a sessionAsyncSupplier An AsyncSupplier is also from Reakt. It is like a regular Supplier except it is async.
We use the reactor to define a repeating task to check the health of the Cassandra connection.

Using the reactor

    init {

        /* Connect the Cassandra session. */
        connectSession(promise)

        /*
             This makes sure we are connected.
             It provides circuit breaker if sessionBreaker is down to auto reconnect.
         */
        serviceMgmt.reactor().addRepeatingTask(Duration.ofSeconds(5)) 
                          { this.cassandraCircuitBreaker() }
    }
There we check for the health of our Cassandra session and if it goes down, we try to reconnect just like before.
We use the circuit breaker to do alternative logic if our connection goes down.

using alternative Breaker logic

    override fun recordMetrics(callback: Callback<Boolean>, metrics: List<Metric>) {
        sessionBreaker()
                /* if we are not connected, fail fast. */
                .ifBroken { callback.reject("Not connected to Cassandra") }
                /* If we are connected then call cassandra. */
                .ifOk { session -> doStoreMetrics(session, callback, metrics) }
    }
Note the use of ifBroken and ifOk. This way we can control the reconnect.
The method doStoreMetrics stores many records to Cassandra asynchronously, and even though it saves records in parallel it does not let its caller know via a callback, unless all of the records were stored.

Using reactor.all to coordinate many async calls

    /**
     * Does the low level cassandra storage.
     */
    private fun doStoreMetrics(session: Session,
                                  callback: Callback<Boolean>,
                                  metrics: List<Metric>) {

        logger.debug("Storing metrics {}", metricss.size)
        /* Make many calls to cassandra using its async lib to recordMetrics
        each imprint. */
        val promises = metrics.map({ metric -> doStoreMetric(session, metric) }).toList()
        /*
         * Create a parent promise to contain all of the promises we
         * just created for each imprint.
         */
        serviceMgmt.reactor().all(promises)
                .then {
                    serviceMgmt.increment("bulk.store.success);
                    logger.info("metrics were stored {}", metrics.size)
                    callback.resolve(true)
                }
                .catchError { error ->
                    serviceMgmt.increment("bulk.store.error);
                    logger.error("Problem storing metrics ${metrics.size}", error)
                    callback.reject(error)
                }
    }
It does this call coordination by using reactor.all to create a promise that only replies if all of the other promise reply. The method doStoreMetric returns a single promise. We use Kotlin streams (just like Java streams but more concise) to turn the list of metrics into a list of calls to doStoreMetric into a list of Promises which we then pass to reactor.all to make all of those promises into a single promise.
The doStoreMetric uses Reakt Guava/Cassandra integration to turn a ListableFuture into a Reakt promise.

Working with Reakt Cassandra / Guava support, and using thenMap

import io.advantageous.reakt.guava.Guava.registerCallback

    private fun doStoreMetric(session: Session,
                                metric : Metric): Promise<Boolean> {
        val resultSetFuture = session.executeAsync(QueryBuilder.insertInto(METRICS_TABLE)
                .value("employeeId", metric.employeeId)
                .value("metricType", metric.metricType.name.toLowerCase())
                .value("metricName", metric.metricName)
                .value("provider", metric.provider)
                .value("externalId", metric.externalId)
                .value("value", metric.value)
                .value("surrogateKey", metric.surrogateKey)
                .value("created_at", metric.timestamp))
        return createPromiseFromResultSetFutureForStore(resultSetFuture, "Storing Metric")
    }


    private fun createPromiseFromResultSetFutureForStore(resultSetFuture: ResultSetFuture,
                                                         message: String): Promise<Boolean> {

        val resultSetPromise = serviceMgmt.reactor().promise<ResultSet>()

        val promise = resultSetPromise.thenMap({ it.wasApplied() }).catchError { error ->
            if (error is DriverException) {
                callback.ifPresent { callback1 -> callback1.reject(error.message, error) }
                logger.error("Error " + message, error)
                errorCount.incrementAndGet()
            }
        }
        registerCallback<ResultSet>(resultSetFuture, resultSetPromise)
        return promise
    }

Using thenMap to convert a promise into another type of Promise

Notice we use registerCallback from the Reakt Guava integration to convert the future into a promise. We also use promise.thenMap to convert a Promise into a Promise.

Using invokable Promises inside of an Actor or Managed event loop

Using invokeWithReactor

override fun collectTodo(callback: Callback<Boolean>,
                                todoList: List<Todo>) {
        callCount++
        todoRepo.recordTodoList(todoList)
                .then { ok ->
                    todoService
                            .ifOk { todoService1 ->
                                doCollectWithCallback(callback, todoList, todoService1)
                            }
                            .ifBroken {
                                mgmt.increment("collect.call.df.service.broken")
                                logger.error("Connection to todoService is down.")
                                mgmt.increment("collect.broken")
                            }
                }
                .catchError { error ->
                    mgmt.setFailing()
                    logger.error("Connection to cassandra is down.", error)
                    callback.reject("Connection to cassandra is down. " + error.message, error)
                }
                .invokeWithReactor(mgmt.reactor())
    }
You can invoke invokable promises in the context of a Reactor by using invokeWithReactor(mgmt.reactor()). This allows the callback handlers from the promises to run in the same thread as the service actor or event loop.

Conclusion

I hope you enjoyed this article. It links back to areas of the Reakt documentation where you can find more details. If you are new to Reakt and what to understand the question Why Reakt and What is Reakt I suggest reading this. Also this interview about Reakt might help.

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 A, B, C, D 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 good. Reakt'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.x. Reakt 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.x, Guava, Cassandra 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 interfaces, Model-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 Spark. Functional 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 Angular, React andjQuery. jQuery 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.x, Akka, Reactor, Netty, 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.x, RxJava, Project Reactor, Lightbend, and reactive streams.

Monday, May 2, 2016

Integrating TypeSafe Config and Konf.

Konf - Typed Java Config Integration

This allows you to combine TypeSafe config and Konf. You can have TypeSafe config be a fallback for Konf or the other way around.
You can load TypeSafe config as a Konf Config instance as follows:

Loading Typesafe config as a Konf Config object

        Config config = TypeSafeConfig.typeSafeConfig();
        final String abc = config.getString("abc");
        assertEquals("abc", abc);
You can also chain TypeSafe config as fallback or Konfig as a fallback for TypeSafe config as follows:

Konf as a fallback for TypeSafe config.

import static io.advantageous.config.ConfigLoader.config;
import static io.advantageous.config.ConfigLoader.configs;
import static io.advantageous.config.ConfigLoader.load;

...

    Config config;
    ...
        config = configs(TypeSafeConfig.typeSafeConfig(), config("test-config.js"));
Kafka and Cassandra support, training for AWS EC2 Cassandra 3.0 Training