artem

artem

What is the Elixir/OTP way for long queues that in JVM world would live on RabbitMQ or Kafka?

Hi All

I am still learning Elixir in semi-hobby mode, so sorry if the question is stupid. Imagine an API that processes survey responses, possibly in computationally expensive way (maybe fashionable AI is being trained from them or something like this). When survey gets published to some popular facebook group or twitter nearly simultaneous submissions can easily overload a small server.

I come from JVM world and one of the usual ways there for surviving against connection overload is whenever possible to accept a request, put it to the queuing service such as RabbitMQ and then slowly (e.g. in 1-3 threads) pull them to process. Or if we are in a less serious service, then maybe a homemade queue in just the heap memory and/or persisted to database.

My understanding is that Elixir/OTP are so great regarding number of connections, that it is not really a concern. However, processing tons of feedback still needs CPU, RAM (especially is machine learning is involved), saving to database, etc.

What is the Elixir way for handling such situations?

  • Do we just post messages from every API call and some genserver slowly processes then one by one?
  • Do you use database persistence in such situation somehow (it wouldn’t be nice to drop queued survey results if service dies)? With some standard libraries?

P.S.
I realize that you can perfectly use RabbitMQ or Kafka from Elixir as well. Still certainly if I can have just one elixir box to do it for a small business SaaS, then it would be great not to add more nodes to the system.

Most Liked

cjbottaro

cjbottaro

For persistent queues, I’m becoming a big fan of NATS Jetstream. It has nothing to do with Elixir btw. Before that, I was using Faktory a lot (which is based on Redis).

Jetstream is distributed and highly available. You can create both queues and streams.

The protocol to talk to Jetstream is extremely simple. Most Jetstream concepts are simple, but the feature set is huge, despite its simplicity.

Jetstream also comes with an amazingly robust pub/sub system.

Jetstream is much more simple than Kafka, but the feature set is greater.

lucaong

lucaong

Hi @artem ,
I am mostly just repeating things that were already mentioned by other people in this thread, but I hope to offer some points on which to decide what to choose based on your specific needs.

As you mentioned, you can definitely use Kafka and/or RabbitMQ from Elixir. RabbitMQ is actually written in Erlang, and runs on the same VM as Elixir. That said, it very much depends on whether you only need scalable and concurrent execution of tasks, or if you need to persist your jobs on disk to recover from a restart of a worker instance without loosing messages.

If you do not need to persist tasks on disk, Elixir/OTP has already very good facilities for managing concurrent tasks, and to scale to a large number of concurrent requests, without reaching outside of the language ecosystem. That’s because OTP relies on exchanging messages asynchronously across lightweight processes. This is really one of the use cases that Erlang is built for. One thing to be aware is that GenServer will not automatically provide a back pressure mechanism: it’s possible to do that, but does not come by default. There are some libraries, such as the already mentioned gen_stage, that facilitate the implementation of pipelines to process tasks in parallel, with back pressure, throttling, and more.

If you instead want to persist those jobs to disk, to recover from a restart without loosing them, I’d consider something like RabbitMQ (with durable queues enabled) or like Oban (based on Postgres), depending on your specific needs.

derpycoder

derpycoder

I have the following book in my backlog, and a general idea of how things can be done in Elixir:


I would tackle it by using GenStage. It has concept of Producer and Consumers, which helps with consumption of data in batched fashion. If the machine learning Consumer gets overwhelmed, it can ask for less work from Producer… (i.e. Backpressure)

If requirements get more complicated, then we can go for Broadway.

For persistence across restarts, I guess Oban will do the trick.

yolo007wizard

yolo007wizard

I’ve been looking at some Postgres Queues myself:

Queues then feed Genstage pipeline. I’m also hobby-learing so interested to see other ideas.

kokolegorille

kokolegorille

In that case, GenStage or Broadway as mentionned by @derpycoder are good fit.

In the BEAM, processes are (almost) free. If You need to do some work, You can throw some processes to do it. But it’s more complicate to control them.

GenStage and Broadway have back pressure mecanism.

You can use ETS table (in memory) and Stream to optimize the pipeline.

Where Next?

Popular in Questions Top

senggen
Erlang/OTP 25 [erts-13.2.2] [source] [64-bit] [smp:8:8] [ds:8:8:10] [async-threads:1] 15:22:35.803 [error] gen_event {lager_file_backend...
New
jerry
Good day to you all. I have been struggling to get a query involving like and ilike to work. Can anyone assist me on this, please? pro...
New
fireproofsocks
I’m working on defining a simple Ecto schema for a table (in PostGres), but I don’t see where I can define a column as NOT NULL. Conside...
New
polypush135
As many of you may have realized by now (sorry for all the posts here) I’ve been working on a db problem where I’m trying to aggregate a ...
New
vertexbuffer
Hello, can anybody help here..? I have a list of players and I what to delete an element, but every for loop the list is reverting to ori...
New
lastday4you
I wanted to check elixir version in phoenix because i found that my elixir is 1.5 but when i use Enum.chunk_by it said the function is un...
New
makeitrein
Hey all, just started picking up Elixir last week and am writing a scraper as a learning project. Baby step #1 is extracting the number ...
New
johnnyicon
Hi all, I've just started learning Elixir and Phoenix Framework, so please pardon my n00bness at this stage. I'm trying to use Postg...
New
9mm
I am constructing a JSON object (map) and I need to conditionally set a field. I’m trying to write proper elixir-way code… and I’m at a l...
New
skosch
To my knowledge, put_in, Map.update etc. all have the one limitation of not automatically creating intermediate keys when needed (for exa...
New

Other popular topics Top

Brian
What is the proper way to load a module from a file in to IEX? In the python world, doing something like this pretty standard: from ....
New
senggen
Erlang/OTP 25 [erts-13.2.2] [source] [64-bit] [smp:8:8] [ds:8:8:10] [async-threads:1] 15:22:35.803 [error] gen_event {lager_file_backend...
New
sergio
In Ruby, I can go: User.find_by(email: "foobar@email.com").update(email: "hello@email.com") How can I do something similar in Elixir? ...
New
yawaramin
In the Dialyzer docs ( http://erlang.org/doc/man/dialyzer.html#requesting-or-suppressing-warnings-in-source-files ), there is a way to tu...
New
vertexbuffer
Hello, can anybody help here..? I have a list of players and I what to delete an element, but every for loop the list is reverting to ori...
New
freewebwithme
Using vs code and installed ElixirLS: support and debugger. And I got an error popped up on start up says Failed to run ‘elixir’ comma...
New
danschultzer
None of the current solutions worked well for me, so I went ahead and built a user management system from scratch. This project took far...
548 27727 240
New
shahryarjb
Hello, I have map which I want to convert it to string like this: the map: %{last_name: "tavakkoli", name: "shahryar"} the string I ne...
New
Qqwy
Original source of discussion: This topic on the Pragmatic Programmers' Functional Web Development with Elixir, OTP, and Phoenix forum. ...
New
Nvim
Elixir appears to be a superior language to Python. I don’t see any advantage of Python over Elixir. Are there any?
New

We're in Beta

About us Mission Statement