dangets

dangets

How to have GenStage producer emit intermediate results?

This may just be my misunderstanding on appropriate design, but is there a way for a producer to yield intermediate results where the count is much lower than what is demanded? If it is an expensive operation to produce the results or you want to limit the actual number of items in flight at any given time, what is the best way to do this?

I saw in the docs that the consumer can set max_demand and min_demand, but is there a way for the producer to specify this? Or for the producer to give back intermediate results while still fullfilling up to the requested demand?

Some example code below.

alias Experimental.GenStage

defmodule GenStageEx do
  # ----------------------
  # Producer -------------
  # ----------------------
  defmodule Producer do
    use GenStage

    def init(_ok) do
      {:producer, []}
    end

    def handle_demand(demand, leftovers) do
      IO.puts("# producer was asked for #{demand}")
      items = case leftovers do
        [] -> request_more()
        _ -> leftovers
      end

      {to_return, next_leftovers} = Enum.split(items, demand)
      {:noreply, to_return, next_leftovers}
    end

    def request_more() do
      # some expensive operation that only returns 10 items at a time
      0..9
    end
  end

  # ----------------------
  # Consumer -------------
  # ----------------------
  defmodule Consumer do
    use GenStage

    def init(_ok) do
      {:consumer, %{}}
    end

    def handle_events(events, _from, state) do
      events
      |> Enum.map(&(IO.puts/1))

      {:noreply, [], state}
    end
  end

  def run_me do
    {:ok, p} = GenStage.start_link(GenStageEx.Producer, :ok)
    {:ok, c} = GenStage.start_link(GenStageEx.Consumer, :ok)

    GenStage.sync_subscribe(c, to: p)

    Process.sleep(2000)
  end
end

Most Liked

josevalim

josevalim

Creator of Elixir

The producer MUST yield intermediate results for higher demands. The idea is that, if you are asked more items than you have, then you just store that pending demand. The next time the items are available (because an external source pinged you, because someone sent them to you, because you reached a certain time, etc), you then emit the new items if pending_demand > 0.

Here is an example of a producer that handles both cases where it has more items to send than requested and it may have been asked for more items that it has to send: gen_stage/lib/gen_stage.ex at main · elixir-lang/gen_stage · GitHub. It uses a queue for the first case and a pending_demand integer for the second.

Where Next?

Popular in Questions Top

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
gshaw
What is the idiomatic way of matching for not nil in Elixir? E.g., First way: defp halt_if_not_signed_in(conn, signed_in_account) when...
New
electic
Hi, I am new to Elixir. I am trying to use the DateTime component to insert a date into MySQL however the there seems to be no way to fo...
New
tduccuong
Hi, is there any work on GUI with Elixir, that is similar to Electron/Javascript? My idea is to bundle Phoenix and BEAM into a single se...
New
myronmarston
The Elixir Typespec docs show the following syntax for keyword lists in typespecs: # ... | [key: type] # keyword lists...
New
vac
Hi, I’m quite new in Elixir and I’m trying to format a string to a PEM format. I have the certificate value like MIIDBTCCAe2...... and I...
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
itssasanka
Hi all, Trying to get some more clarity over utc_datetime and naive_datetime for Ecto: The documentation above suggests that while ...
New
JDanielMartinez
Hi! May someone helps me, please! I have two apps into an umbrella project: the first one is Database, which manages queries, and the se...
New
joaquinalcerro
Hi there, I am working with Ecto-Postgresql and I need to call all of the records from a specific table but the table has 40,000 records...
New

Other popular topics Top

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
malloryerik
Hi, this is for people who, like me, have had some friction using .html.heex templates in VSCode. The solution seems to be, in a hyphena...
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
gausby
I asked this very same question on twitter and got some interesting feedback, but I thought it would be a good question to ask here as we...
1207 39467 209
New
vonH
When I run the Plug and I recompile I wind up having to use Ctrl C to quit iex and start again. Witht the help of rlwrap I can use the cu...
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
dblack
I’ve got an issue with an app and I’ve no idea of how to troubleshoot it. I’m hoping someone here might have seen something similar. I p...
New
KronicDeth
Elixir plugin for JetBrain’s IntelliJ Platform (including Rubymine) This is a plugin that adds support for Elixir to JetBrains IntelliJ...
289 36352 110
New
openscript
Hello! Sorry for this astonishing simple question, but I’m really stuck. I try to set up the intellij-elixir plugin, but I don’t know ho...
New
sergio
Kind of like when jquery came out, it was super necessary. Existing drag and drop libraries have a bunch of baggage to support old browse...
New

Latest on Elixir Forum

Elixir Forum

We're in Beta

About us Mission Statement