venomnert

venomnert

Creating process from GenServer and passing state

Context:

I am pretty new to OTP. In trying to learn it I’m creating an application that does the following (high level overview):

  1. users submit X number tasks to a GenServer.
  2. The GenServer iterates over the queue of tasks and creates a process for each task.
  3. Once the process is completed it will notify the GenServer it’s done and return its value.
  4. Once the GenServer get’s notified it will update the state with the process’s return value, and notify the client with the updated state.

The diagram demonstrates what I’m trying to achieve.

I am able to spawn a process from the GenServer; however, I’m struggling to connect between the GenServer and process, so the process can call the GenServer; in return, the GenServer can handle_call/3.

Questions:

  1. Am I taking the right approach of calling a process from a GenServer? Is there better way to create process from GenServer and notify the process about the state?
  2. How do I call GenServer from a process and passing the state to server?

Marked As Solved

al2o3cr

al2o3cr

This sounds a lot like the Task functionality in the Elixir standard library. Here’s some relevant discussion from 2018, complete with a code example:

The tricky part with spawning additional processes is making sure everything works sensibly when things go wrong - what happens when those processes shut down, when the parent shuts down, etc. The Task library wraps the relevant parts (linking, supervising and so on).

Also Liked

joaquinalcerro

joaquinalcerro

@venomnert,

Even though this code might work for your current use case you have to consider what happens if one of the tasks crashes.

With this code, if one task crashes, your GenServer will also crash with your state because the Task is still sending the GenServer a message that is currently not handled. You can handle them as follows:

   def handle_info({:EXIT, _task, _reason}, state) do
     IO.puts("Crashed!!!!!")
     {:noreply, state}
   end

  def handle_info({:DOWN, _ref, :process, _pid, reason}, state) do
    IO.inspect(reason)
    {:noreply, state}
  end

The first message will have the tuple {:EXIT, task, reason}. The other one is {:DOWN, _ref, :process, _pid, reason}. You already have a tuple similar to this one but handles the happy path when the task exits normally like this {:DOWN, _ref, :process, _pid, :normal}… note the :normal atom at the end will be pattern matched.

With this in place, your GenServer will not crash and will be available to handle other tasks.

So this might work but: I just wanted to share with you some recommendations @whatyouhide gave us during this weeks ElixirConfLA in Medellin.

He recommended us:

  1. Limit the amount of tasks that can be spawned to avoid exhausting the resources

  2. Use the proper strategy for your use case:
    a. one_to_one
    b. one_for_all
    c. rest_for_one

    So what happens if one of the task fails? is it worth continue processing the other tasks? how will your state be affected if one task fails?

    Check this link for details of each one: Supervisor — Elixir v1.20.2

  3. Nest you supervision tree with other supervisors with the proper strategy. For example, under your main application supervisor, create a worker supervisor with a one_for_one strategy.

  4. All processes should be supervised

  5. Name your supervisors to access them by name which is easier.

  6. Test you supervision tree

I will be monitoring when the talks are published to link it to this thread.

Best regards,

Where Next?

Popular in Questions Top

Darmani72
If I have a post route which an argument: post /my_post_route/:my_param1, MyController.my_post_handler How would get the post params ...
New
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
qwerescape
Is there a way to get the call stack or stack trace at any point in the code? Not from exceptions, but an expression that returns how the...
New
jononomo
I am trying to figure out how Mix knows whether the environment is test, dev, or prod – where is this set? Thanks.
New
stefanchrobot
What’s the safe way to decode a JSON string into a struct? I want to avoid calling String.to_atom. Jason.decode can give me a map with st...
New
ycv005
I have followed this StackOverflow post to install the specific version of Erlang. And When I am running mix ecto.setup then getting fol...
New
dokuzbir
I want to highlight html closing tags when i click a html tag. That works in .html files but doesnt work for html.eex templates. How can...
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
Qqwy
Original source of discussion: This topic on the Pragmatic Programmers’ Functional Web Development with Elixir, OTP, and Phoenix forum. ...
New
chensan
I have a User schema with a :from_id field set to type :string: defmodule TweetBot.Repo.Migrations.CreateUsers do use Ecto.Migration ...
New

Other popular topics Top

albydarned
Hello all! I am typing this post from my new MacBook Pro with the M1 chip. I’m loving it so far, and will probably use it as my daily dr...
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
chrismccord
As promised, the first release candidate of Phoenix 1.3.0 is out! This release focuses on code generators with improved project structure...
New
stefanchrobot
What’s the safe way to decode a JSON string into a struct? I want to avoid calling String.to_atom. Jason.decode can give me a map with st...
New
AngeloChecked
What learn first? Rust or Elixir Hi Elixir community! I’m here because i want learn a new language. I’m a junior developer and mainly i ...
New
nsuchy
Hi. I’ve noticed that Windows Powershell has it’s own IEX command and you cannot access Elixir’s IEX due to the conflict. This isn’t a cr...
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
marick
I had some trouble figuring out how to make many-to-many associations work. Once I got it working, I wrote a blog post. Because I’m a nov...
New
PeterCarter
There are pre-rolled solutions for other frameworks that do work. However, Phoenix does not seem to have these. Have people had good expe...
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