Vertigo

Vertigo

Design pattern GenServer tree

So I’ve been exploring Elixir/Erlang/OTP and totally love the syntaxes, concepts and theory models involving the actor model (thank you community, Carl Hewitt, Joe, Jose, et cetera). At this point I’m messing with GenServers and am seeking some guidance on a design pattern (this is pure hobby fun).

Say I have a ‘main’ GenServer which receives a call to find some word in multiple files, it distributes this silly task to a few workers (e.g. one per cpu, and they are also GenServers) that on their turn invoke a cast on a GenServer that does the actual searching.

Now imagine this crazy algorithm is in a competition with its fellow workers and as soon as one worker has found the word the other workers should stop(restart?) and start looking for the next word. How would I implement this as the mailbox of each process wont be read until the running task is finished. So the worker won’t cancel its, now, redundant search (poor worker :frowning:).

I thought of calling Process.exit on the actual worker once the parent receives a new instruction from the main GenServer, is this the way to go? Does ‘killing’ and starting a new GenServer include a lot of overhead or is this still considered ‘lightweight’ ?

Thanks for your insights!

Perhaps the snippet I describe is above considered an anti pattern and I should delve into supervisors more.. anyway this already has been an interesting learning experience :slight_smile:

Most Liked

aenglisc

aenglisc

If I’m getting your idea correctly, you can start your workers via a supervisor with a one_for_all strategy and terminate as soon as the required task is finished, thus killing off the rest.

Last Post!

ityonemo

ityonemo

you know, I thought this would work, but it doesn’t:

test_pid = self()

children = Enum.map(1..10, &(%{
  id: "#{&1}",
  start: {Task, :start_link, [fn ->
    idx = &1

    # pick a random amount of time.
    duration = Enum.random(1000..10000) + 1000
    
    # report existence.
    IO.puts("starting #{idx} with #{duration} ms")

    # cache the pid of this task in the process mailbox of the test
    send(test_pid, {:pid_of, idx, self()})

    # sleep

    Process.sleep(duration)

    # return the result of our task.

    send(test_pid, {:finished, idx})

    IO.puts("#{idx} finished.")

    #Process.exit(self(), :kill)
  end]},
  restart: :temporary,
  #shutdown: :brutal_kill
}))

{:ok, sup} = Supervisor.start_link(children, strategy: :one_for_all)

#wait for the first to finish.
receive do {:finished, _} -> :ok end

# wait a hot moment for the task supervisor to do its thing
Process.sleep(100)

Enum.each(1..10, fn idx ->
  #check on the cached messages
  receive do {:pid_of, ^idx, pid} ->
    IO.puts("is #{idx} alive? #{Process.alive?(pid)}")
  end
end)

I tried (uncommenting the Process.kill), or (uncommenting the shutdown: :brutal_kill)
If you remove restart: :temporary it does correctly do the :one_for_all thing, so I either I’m setting something wrong in my code or there’s an undocumented interaction (or bug?) in the handling code:

seems to imply that you can do this, as it says “A temporary child process is never restarted (not even when the supervisor restart strategy is rest_for_one or one_for_all and a sibling death causes the temporary process to be terminated).” which doesn’t make sense if one_for_all interacts with temporary…

Where Next?

Popular in Questions Top

Qqwy
Original source of discussion: This topic on the Pragmatic Programmers’ Functional Web Development with Elixir, OTP, and Phoenix forum. ...
New
mcarvalho
What is the difference between System.get_env and Application.get_env? For example, what are best practices to use one versus another.
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
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
sergio_101
I am VERY much an elixir newbie. I have taken one elixir course and one phoenix course on Udemy. During that course, I saw the instructor...
New
SoCreat
i’m a new one to elixir which editor can i use vs code? or atom? Thanks! :smiley:
New
svb
Hi! Currently I want to submit a form by pressing the Enter key. However, since my input field is of type “textarea” this is just adds a...
New

Other popular topics Top

baxterw3b
Hi guys, i’m new in the Elixir world, and i have to say, that i love it! i’m having some problem to understand anonymous functions with ...
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
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
saif
Hello everyone, Long time lurker first time poster here. I’ve recently begun working on Elixir full-time again! :raised_hands: It’s been...
New
TunkShif
This post is an instruction guide to help you setup your Neovim for Elixir development from scratch. It includes general information on h...
274 42576 114
New
senggen
Erlang/OTP 25 [erts-13.2.2] [source] [64-bit] [smp:8:8] [ds:8:8:10] [async-threads:1] 15:22:35.803 [error] gen_event {lager_file_backend...
New

We're in Beta

About us Mission Statement