mononym

mononym

GenStage: Bounded buffering and serialization

The general problem I face is that I have N producers emitting events which must be processed in order with respect to each producer, but can be interleaved with the events emitted from other producers in the final consumer step. In addition, the number of events emitted from each producer must be able to be buffered up to a configurable limit, again on a per producer basis. This upper limit must be enforced in such a way that code pushing events into this pipeline can detect when the buffer is full and take appropriate action. I’m also writing this code to be consumed by another application.

In the general approach I’m considering, the application using mine as a dependency will start up a Producer per connected user and in my application I will start up a Buffer (:consumer_producer) per Producer for the purposes of buffering the input. These buffering stages will then forward the input to the final Consumer stage, which will have a number of consumers equal to some multiple of the number of cores on the machine and will process the input from all user specific stages.

It seems like my requirement of being able to buffer the input is an easy one to achieve. As long as I set the max_demand in my Buffer correctly and as long as the Producer only acknowledges events when they are emitted to the Buffer, code submitting events into the pipeline should be able to correctly handle the case that the buffer is full.

One assumption I’m working on is that given a pipeline with a chain of single producers/consumers that any series of events will be processed in the order that they are produced. Working on this assumption, the only thing I then have left to do is wire the stages up in such a way that no further events can be emitted past the buffer until the last emitted event is processed. The only thing is I can’t figure out how to do this without having the pipeline end with the Buffer, having it as a consumer, and then having the Buffer submit work one-by-one to a worker pool for processing. So rather than having N producers piping into a single set of consumers in one large pipeline, I’d have N separate pipelines and a separate worker pool.

Is there a way to fulfill my requirements using GenStage for the entire process, or does my need to serialize the processing of each event on a per-producer basis throw too big of a wrench in the works?

Most Liked

josevalim

josevalim

Creator of Elixir

Consider each stage as a unit of concurrency / fault tolerance / back-pressure rather than of code organization. As as extreme, imagine you need to perform three operations, a, b and c on every event in the system. Putting each operation in a separate GenStage that are connected together is not the way to go. If your goal is code isolation, then Elixir modules and functions are the proper tool.

The reason I am saying this is that I am not sure I would have the buffer as separate stage. It could simply be part of the producer. I also wouldn’t necessarily mix all producers and consumers together, especially because items from the same producer needs to be processed in order.

From your description, the simplest solution seems to be N GenServers, one for each kind of producer that keeps the buffer and processes the events as they come. The processing can happen on Task. Alternatively, you can keep N pairs of GenStage, with a single producer and a single consumer, connected directly, each pair isolated from each other.

mononym

mononym

Splitting the final Consumer stage and having a Buffer/Consumer pair as a pipeline for each connected user would absolutely work, but at that point I feel like I am not really gaining anything over taking the N GenServer approach. It was something I’d considered doing, but was hoping to find a way to pipe everything into a single bounded set of consumers while still meeting my requirements.

I’m very excited at all of the fantastic software being build up with/around Elixir, and I’m looking forward to finding a use case that makes sense with and can leverage GenStage, but this doesn’t seem to be it. Just feels like it would be a case of using something because it is flashy and new rather than because it provides a concrete benefit for the specific use case. I have some thoughts around doing some log processing though…

Where Next?

Popular in Questions Top

Harrisonl
We have an ECS cluster with 4 services, where each task joins a single cluster, via discovery ECS discovery service. Currently when I de...
New
sen
Hi All, I set a environment variables in dev.exs , like below code. when i start server, how can i set the ${enable} value? thanks. d...
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
pmjoe
I have a relationship of love and hate with Elixir. Lots of things are just absolutely right, but there are some things that are kind of ...
New
fireproofsocks
Forgive me if this is obvious, but how does one delete a database record WITHOUT selecting it first? Ecto.Repo — Ecto v3.14.0 has exampl...
New
itssasanka
Hi all, Trying to get some more clarity over utc_datetime and naive_datetime for Ecto: The documentation above suggests that while ...
New
joeerl
Hello again - after a longish gap I’ve decided I really must dig into Elixir and see what’s been happening here - so I have a few questio...
New
vrod
I am using the Starship cross-shell prompt – it seems pretty nice, but I get some errors: [WARN] - (starship::utils): Executing command ...
New
hariharasudhan94
I would like to know what is the best IDE for elixir development?
New
JorisKok
I have a server on AWS, and was running a load test using artillery. When looking at the Phoenix dashboard I see the Ports going to 100% ...
New

Other popular topics Top

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
Fl4m3Ph03n1x
About me? ( if you have nothing better to do than reading about some random guy in the internet :stuck_out_tongue: ) Hello all, this is ...
New
grych
Hi folks, Few months ago I have announced the proof-of-concept of the library to manipulate the browsers DOM objects directly from Elixi...
639 52774 488
New
nobody
Hi! In PHP: $_SERVER[‘SERVER_ADDR’] - in Elixir? Searched the docs for ip address and the web, no good results. Thanks!
New
jason.o
In the code below, if the create action is not set to accept “extra_key” as an input, it errors out with a message shown above. Is there ...
New
shijith.k
I am trying to start a new phoenix project with elixir 1.9, but mix phx.new does not work. It says that ** (Mix) The task "phx.new" could...
New
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
AstonJ
Seen any cool LiveView demos, sample apps or examples? Please post them here! :003:
New
dogweather
I wrote this comment on r/haskell, and it’s not popular there. :wink: But I think I’m on to something… Haskell reminds me of Java, and e...
New
vonH
In asking this question I am more interested about the expressiveness of the language itself and less concerned about the availability of...
New

We're in Beta

About us Mission Statement