Monix and doobie

Tapan Vaishnav
3 min readDec 15, 2019

--

Recently, I started playing with Monix as a part of my scala study and I got quite intrigued by it. Hence, I would like to share some of its important aspects and a simple example of using Monix to access databases in a Functional and Asynchronous manner.

What is Monix?

As per the official document, Monix is a high-performance Scala / Scala.js library for composing asynchronous, event-based programs, which mostly covers the definition along with Monix being an inspiration of ReactiveX but in a functional way.

Monix introduces various data-types among which Task, Observable, and Coeval being the highlights. Monix has been modularized( which most of the recent projects are, like ZIO) to make it easier for users to only use what they need. Let’s dig into its Data-types:

Task Vs Future

Monix Task is a lazy alternative of Future. Future ‘s are designed for ongoing computation which is possibly finished, whereas Task is a description of the computation and we need to explicitly trigger it to start the computation, providing control over side-effects:

To trigger the above Task , we can call the runAsync method as following:

Here, we also defined an implicit scheduler, which is basically an ExecutionContext but provides leverage for scheduling of single or periodical execution of Runnables.
We also introduced CancelableFuture which is an extension of Future, allowing the programmer to attempt the cancellation of the async computations, or to release resources that active data-sources are holding.
Monix provides a high-level control over Task executions like, we can whether choose to execute aTaskon each invocation of runAsync (Task.eval) or we can memoize the result (Task.evalOnce) or even execute it in a separate thread (Task.fork).

Monix Taskprovides a rich set of combinator(which makes it hard to explain each of them in one article) but I would introduce some of those which I personally like:

Coeval

It is a synchronous version of Task, being meant for computations that are guaranteed to execute immediately (synchronously) and similarily doesn’t trigger the execution or any effects until value or run .

Observable vs Iterable

Observables are the lazy, non-blocking and asynchronous alternative of scala Iterables. It provides multiple producer-consumer relationships, including having a single producer pushing data into one or multiple consumers.

Similarily, Observable also provided rich set of combinators and constructors including, fromIterable which creates an Observable from an Iterable and the likes of mapParallelOrdered and mapParallelUnordered , which are useful for processing multiple elements at once.
Monix Observable also provides various strategies to process elements in batches:
bufferSliding : it skip some elements with each batch containing count items.
bufferTumbling : this one combines the buffer elements to a specific count.
bufferTimes : it buffers elements respect to a timespan.
(There are many more but I’m limiting myself to these three for the sake of this article, you can find a detailed description here.

Connecting to a Database

I’m using doobie as a JDBC layer for scala but there are other good options like Slick or scalikeJDBC.
doobie provides a pure functional way to connect to a database, doobie supports various RDBs but I’m using progress for this article:

Monix makes, otherwise tedious operations, easier to write in a purely functional, non-blocking manner while not compromising on the performance. Another plus point is that it provides a broad set of combinators for its data types. Monix provides ways to have a scalable model for reactive systems.

--

--