smanza

smanza

Hello !

I’m wondering of the best approach to use regarding data coming from worker processes under supervision tree.

Is it better to use state per worker (ie. GenServer, :gen_statem) and restart over when they fail (with maybe mechanism to save data when they are down: ie ETS) or use a cache process which is filled by worker process (ie. Task) ?

The last approach is more centralized instead of the first one which is more distributed/decentralized

Thanks

Showing Posts 13 to 4

ityonemo

ityonemo

I would say when to use gen_statem:

  1. you’re modeling an external “real thing” that you have limited control over, or stateful communications protocol.
  2. there are recurrent events that must be asynchronous (eg you have to check on your external thing and you don’t know when the response will come back)
  3. your model is not transient (if your process crashes you want to recover, and you can’t just throw it away and start from scratch)

If all do not apply, do not use gen_statem.

smanza

smanza OP

Thank you very much @gregvaughn .
Nice way to do it :slight_smile:

But I my use case, I don’t known if async_stream is the right thing to do, because I need to retrieve the result asynchronously later not after the job completion but when I will receive to check and compare the jobs results.

gregvaughn

gregvaughn

I’m sorry I don’t have some example to share, but I view it as some basics of functional programming. Here’s some pseudo code (caution: I have not executed it) to think about

Enum.reduce(data_list, (:initial_state, nil), &transition/2)

def transition(data_element, {:initial_state, accumulated_data}) do
  #do something and return {new_state, new_accumulated_data}
end

def transition(data_element, {:state2, accumulated_data}) do
  #do something else and return {new_state, new_accumulated_data}
end

# ... plus as many more transition/2 function clauses you need

Now the result of the Enum.reduce is {final_state, final_accumulated_data} and if you use the async_stream approach I suggested, it will be sent to the calling process automatically. There is no need to store this (in process state or ETS) and later retrieve with some :get_job_result message. That is the whole advantage of the async_stream approach.

smanza

smanza OP

Thanks @gregvaughn.

Do you have any example about your idea using state machine with simple Enum.reduce ?
because at the end , I need also to keep state of the data, even if the only received message will be “get_job_result” . So wondering if a simple tasks + ETS will be sufficient.

gregvaughn

gregvaughn

No, please, a thousand times no. Do not use :sys.get_state in production code. It is intended only for debugging purposes. You speak a lot about managing state carefully, but then you want to do this brutal approach. :frowning:

My suggestion wasn’t so much about Task.Supervisor as it was about async_stream in which case the results come to you when they complete. No need to reach into another process’ state (which would be akin to me to grabbing money out of your wallet because you owe me).

And gen_statem seems to be overkill for your purposes too. The point of a “gen” style server is to be able to receive messages from other processes. You can use a basic state machine approach with Enum.reduce and an appropriate accumulator map/struct.

smanza

smanza OP

Thanks @dimitarvp, I was thinking the same, just I didn’t know if it’s impact more the memory to keep multiple process with state vs only process with more big state.

smanza

smanza OP

Good point @gregvaughn, I didn’t think about Task.Supervisor because I didn’t want to use Task because I need to keep state somewhere and I do not want to retrieve the data when they are finished but when I will receive another request to check this state.

And for the :gen_statem approach, jobs will not received really messages only a way simplify the state identification and transitions. Only at the end I will request process state and date for example using :sys.get_state. But maybe there is a better way to do.

dimitarvp

dimitarvp

IMO you should have many processes with smaller data. Copying from ETS will be easier on the GC (after the process dies) and will also be faster.

The calculation results that are hard to recompute should go into a database. Everything else is fine in ETS.

gregvaughn

gregvaughn

This sounds like a job for TaskSupervisor.async_stream to me. I use that a lot to “fan out” jobs into concurrent pieces, but still collect their responses. Do review all the options for that function though. I use ordered: false quite often.

However, if you really need :gen_statem to manage incoming messages to each of your jobs, then this approach is too simple.

wolfiton

wolfiton

Thanks @shanesveller, for explaining why you wouldn’t use Elixir Agents in this situation.

Where Next? Top

Trending in Discussions Top

AstonJ
As the title says, please share what you’ve been up to with Elixir. Whether that’s been learning it, looking into it, making stuff with i...
2977 94592 917
New
cblavier
Hey there, It’s been more than a year since we started using LiveView as our main UI library and building a whole library of UI componen...
New
mudasobwa
I am happy to introduce the very α version of the new programming language compiled to BEAM. Welcome Cure. It has literally three kille...
New
heathen
Quite interesting article Google brought me. Didn’t find any mentions about it here. What do you think in general? Would you use togethe...
New
mhanberg
Hi everyone! The first release candidate for the Expert language server project is now available! We’ve published a press release detai...
New
axelson
Hi there! :wave: @frigidcode and I (but mostly him) have been running an Elixir Book club, we’re almost done with Designing Elixir Syste...
New
AstonJ
Since we have deprecated our Erlang sections (as we have dedicated Erlang Forums now) let’s add this thread for those who’d like to post ...
New

Other Trending Topics Top

GenericJam
Edit: 2026 May 15 - This post is archived. Mob is alive!! Main docs: mob v0.7.11 — Documentation A bit of explanation for the slightly c...
New
JesseHerrick
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
marciok
Hi there! We created Gust: A task orchestrator inspired by Airflow. For those who have never heard about Aiflow, it’s a Python-based wor...
New
jimsynz
Beam Bots (or just BB for short) is a framework for building fault-tolerant robotics applications in Elixir using familiar OTP patterns. ...
New
georgeguimaraes
Just published claude-code-elixir, a plugin marketplace for Claude Code with Elixir support. These are the plugins I’ve been using for my...
New
Dmk
Xamal is a deployment tool for Elixir apps that deploys native releases to bare metal servers over SSH. It’s a port of GitHub - basecamp/...
New

We're in Beta

About us Mission Statement

Options

Thread Display Mode




Thread Preview

Skip Thread Previews