Handling async tasks with Elixir
As web developers we often experience the need to do something asynchronously — like processing large data sets, communicating with external API’s or waiting for a blocking operation to finish. In this article I’m going to show you how you can handle async tasks with the help of Elixir.
What I like the most in Elixir is that it’s concurrent by nature. It comes with number of abstraction that makes writing asynchronous code pretty easy.
Elixir is built on top of Erlang and brings all the power of the Erlang virtual machine (BEAM).
Erlang is designed for massive concurrency. Erlang processes are lightweight (grow and shrink dynamically) with small memory footprint, fast to create and terminate, and the scheduling overhead is low.
Lets get straight to an example — as we live in rise of the cryptocurrency one might consider useful building a bot that tracks down cryptocurrency rates. Later it can be used as a service providing information to subscribers.
First we create a simple mix application:
mix new cryptoex && cd cryptoex
Then lets create our worker that will query the rates for us
Lets add our only config for the API url:
Now we can start our mix app and see if our worker does his job:
iex -S mix and in the console call the worker
The output should give us bitcoin to USD exchange rate which at the time of this writing is exactly
9926.3388 USD for 1 BTC.
Now what if we want to get rates for a list of currencies? We would need to execute our worker for each and every currency in our list and wait for every request/response from our external API to be finished so we can display results. This is where concurrency comes in handy. We can do each call to our worker in a separate process — this way we will be able to benefit from the concurrent processing without the need to wait:
Lets try this out:
Cryptoex.rates_for(["USD", "AUD", "GBP", "CHF", "EUR"])
the output should look like the following:
10089.02 USD for 1BTC
8241.105 EUR for 1BTC
7292.6463 GBP for 1BTC
12648.5136 AUD for 1BTC
9694.5898 CHF for 1BTC
Each call to our worker now start separate process using
spawn/3 — the worker does it's job, puts a response and quits.
Of course this is just a very basic example of how concurrency can be handled in Elixir. If you need more flexibility there are plenty of other approaches including GenServerbehaviour or coordinators if you want to keep state. You could also use the
Taskmodule to rewrite this example as it is higher level abstraction over the basic
spawnfunctions. The tools that Elixir provides are great and enables you to implement very sophisticated concurrent systems.
Feel interested in the matter? There are some really nice books and blog posts about GenServer, process messages, handling state and all other cool things that the language brings. I really enjoy playing with Elixir and I hope you found this simple example helpful. You can find the source code on GitHub.