ream88
I’m currently playing around with Flow and GenStage and wanted to know if something like this is possible:
def start_link(file) do
File.stream!(file)
|> Flow.from_enumerable()
|> Flow.partition()
|> Flow.into_stages([ProducerConsumer])
|> elem(1)
|> Flow.from_stage()
# more Flow stuff like |> Flow.filter
|> Flow.into_stages([Consumer])
end
This code does NOT work of course. My idea behind this was to have a clean and easy to understand flow and a bunch of GenStage modules which do the hard and complicated stuff.
Trending in Questions
Hello!
Suppose you are building workflow (order / task / payment) processing system with the following requirements:
Each workflow con...
New
I’m in search of an Elixir library that offers PDF generation capabilities similar to Ruby’s Prawn. While there have been discussions abo...
New
I’m looking to build a personal workflow to quickly deploy web applications written in elixir/phoenix, for local consumption (ie not on t...
New
Before I dive in myself, did anyone successfully sprinkle Hologram into their existing LiveView app?
Looking for hints regarding:
Addi...
New
Kia ora,
We have been using elixir-google-api to connect to Google Drive. However, with the updates to Tesla due to CVEs this is now bro...
New
Hi all, I wanted to ask how the community is dealing with post-release steps.
Today we have Ecto migrations, which make sure that the db...
New
Hello,
I have an Elixir backend that implements a custom protocol over TCP. I want to load test the backend and assess the performance o...
New
Other Trending Topics
Hey, I’m Jesse and I’m the main contributor behind Dexter, a full-featured, lightning-fast Elixir LSP optimized for large codebases. It s...
New
Beam Bots (or just BB for short) is a framework for building fault-tolerant robotics applications in Elixir using familiar OTP patterns. ...
New
Hello everyone. After busy few months I am happy to announce v0.1.0 of Emerge & Solve.
They are GUI (Emerge) and State management (S...
New
Corex is an accessible, unstyled UI component library for Phoenix that integrates Zag.js state machines using Vanilla JavaScript and Live...
New
Emily is an Elixir library that runs Nx computations on Apple’s MLX. Install it as the default Nx backend and Nx, defn, Axon, Nx.Serving,...
New
I just stumbled on a newly redesigned elixir-lang.org. :tada: It looks like @Software_Mansion did the work, and I think it is generally a...
New
Categories:
Sub Categories:
Forums
Popular Tags
- #ecto
- #liveview
- #troubleshooting
- #learning-elixir
- #deployment
- #library
- #erlang
- #testing
- #genserver
- #mix
- #absinthe
- #remote-other
- #otp
- #plug
- #how-to-question
- #macros
- #postgres
- #channels
- #elixirconf
- #exunit
- #discussion
- #code-sync
- #javascript
- #podcasts
- #onsite
- #dialyzer
- #docker
- #authentication
- #umbrella
- #full-time-contract
- #podcasts-by-brainlid
- #ecto-query
- #elixir-ls
- #blog-post
- #phoenix_html
- #iex
- #graphql
- #ai
- #genstage
- #elixirconf-us
- #websockets
- #supervisor
- #advent-of-code
- #distillery
- #processes
- #api
- #forms
- #metaprogramming
- #security
- #hex










First 10 of 18 Posts
lackac
Something like this could work, but the devil—as usually—is in the details.
First of all, there are some issues with the flow above, but I assume that’s because you didn’t want to include too much detail. For example, I don’t think calling
Flow.into_stages/2immediately afterFlow.partition/1makes sense.Also consider if using Flow is really necessary. You’re already using
GenStagefor other tasks. While Flow is a simpler, higher level way of coordinating multiple stages of consumers, you might find that it’s unnecessary overhead if you don’t need that kind of coordination.I assume you want to supervise this, so you’ll need to split it into separate modules too. So instead of
you would have a supervisor with the following children:
Then
MyFlow1andMyFlow2could be modules that satisfy a behaviour that implementschild_spec/1andstart_link/1so that their main job would be to implement the flow specific aspects.We have a similar kind of setup and so far it has worked out well. Let me know if you need more help with the specifics of the behaviour and the flow modules.
CptnKirk
I would also be interested in Flow getting better first class support for flows/graphs that incorporate external GenStages (or maybe just GenStage MFAs if control over materialization is necessary).
These days I end up manually composing the few custom GenStages that I need, plus a custom Enum GenStage that is a passthrough :producer_consumer + side effects.
The system works, but feels backwards. I’d much rather use a high level Flow/Graph DSL. And would welcome any enhancements to Flow that would make it easier to BYO GenStage in a complete execution graph (not just as flow source/sink).
Note: Some may argue that the need for custom GenStages ought to be rare. Maybe. But the need is still there. There are times you want/need an async boundary. There are times you want/need to deal with differences in flow rates. There are times you want/need to manage state and would rather do it in a GenServery way instead of a functional reducer way.
I’d love for Flow to incorporate more support for these types of data flows. The GenStage implementation of these things tends to then influence the DSL. More mature flow DSLs support the notion of explicit async boundaries, sub-flows, explicit buffers, timers and other rate control mechanisms, among other things. All of these can be implemented via a graph of GenStages. Optimizations can then be made to avoid extra stages and communication when unnecessary. For example, a series of Flow.map transformations could be made as a series of :producer_consumer GenStages, but usually it is more efficient to compose all those functions together. Flow makes that optimization already today.
ream88
I got the following to run, however @lackac could you be so kind to give me your opinion on it? (Still a GenStage/Flow novice here
)
josevalim
Yes, this should work. However, I am curious to know why you need to drop Flow in favor of GenStage?
CptnKirk
If your ProducerConsumer is wrapping a Port, you’d need a GenStage. Or you want to write a GenStage that emits other GenStages (stream of streams). I do this for TCP connection processing within GenStage graphs. Or you need to support differences in rate (extrapolate, expand, conflate). Or explicit buffers. Plenty of reasons to need GenStages as part of your Flow.
@ream88 Does it right by joining the flows via the GenStage, but this pattern isn’t obvious. When I was just starting I thought it would be a good idea to simply pipe everything together to form a larger composite flow.
In fact, I don’t think this even worked liked I hoped because I had to unpackage the pid from the Flow.into_stages return value.
While the pipe operator makes this look like a single flow with async components, it doesn’t behave that way. Demand doesn’t originate from the
Sinkand then propagate to theSource. Instead, multiple independent flows are materialized, activated, and then stitched together.The problem with this is that internal subscription switching isn’t immediate, so there’s a good chance that GenStages will process some messages that aren’t ever visible to the rest of the flow because it subscribed late. There may be other related gotchas wrt flow behavior in the face of crashes and recovery.
In short, attempting to mix GenStages into a Flow to make a larger Flow just didn’t work like I’d hoped. I’d like Flow to be more like the Akka Streams DSL. Both in behavior and richness.
ream88
My idea was to reuse one of my GenStage producer-consumer inside another flow.
CptnKirk
I think the Flow DSL could support GenStage chaining via a
viafunction that would help enable a single larger flow materialization.Hypothetically:
But since sources and sinks are just a matter per perspective and flows are just descriptions/blueprints until they’re materialized. You could construct flows, copy the blueprints around, and put them together or reuse them later.
Hopefully this is clear enough. Hard to explain without types the notion of a Flow definition, partial FlowGraphs, Source shapes, Sink shapes, etc.
josevalim
I agree. Can you please open up an issue? I would call it
Flow.into_producer_consumer/2or similar. Should they already be started or should we start them as part of the flow?CptnKirk
I think you’ll want
Flow.into_producer_consumer/2to support both flow starting and external started operations.I think the most common scenario will be flow started. You’d want the resources used by the flow to be managed by the flow.
But you’ll also want to support the case where this GenStage is shared across flows for whatever reason. In which case, you’ll need to accept an already started pid.
You need both.
CptnKirk
The Flow started case could also be used to abuse the GenStage behavior and allow Flow to simply compose callbacks in the calling process, instead of requiring an async boundary.
This would allow developers to treat this as a component model without necessarily inheriting the async overhead. To really flesh this out you’d need to add further async() demarcations to the Flow DSL. But more things are possible if you aren’t a process already.