sschuldenzucker

sschuldenzucker

Supervision design for static but interdependent processes, startup order

Hey all, I’m pulling my hair out over how to properly design my supervision structure. It works right now but only because processes are restarted often enough to eventually fall in the right order.

I’m sure there’s an obvious right solution here that I just don’t see (pretty new to elixir). Anyone got an idea? :folded_hands:

I’m building a single-user interactive app. There are four GenServers:

  • The ModelManager serves as a central point to store the underlying data. (makes it easier to implement sync later) Processes can subscribe to the ModelManager and be notified in the event of changes.
  • The Frontend (a TUI using the Ratatouille library) presents the UI and pushes changes to the ModelManager. It also listens to change events emitted from the ModelManager (e.g., because of sync).
  • The frontend actually needs a little MsgTransformer process between itself and the ModelManager to transform the messages into a shape that Ratatouille can deal with.
  • The FileSaver implements autosave by listening to change events from the ModelManager and writing them to disk.

I even made a little diagram:

The problem I’m facing is startup: in principle it’s clear what should happen:

  • The ModelManager should start first.
  • Then we can start FileServer and MsgTransformer (the MsgTransformer actually belonging to the Frontend; nobody else has to know about this)
  • Finally we can start the Frontend.

This order is necessary so everyone can subscribe / reference the other processes when they need to. But I have no idea how to make this happen.

Right now I’m just putting all four processes as directly supervised children under my main app tree. Some process (the frontend specifically) crash upon init because the ModelManager isn’t live yet, so it can’t subscribe. But the supervisor restarts it, so it’ll eventually be fine. — But this is definitely not a clean design right?

Most Liked

axelson

axelson

Scenic Core Team

It sounds like you’re pretty well sorted on the questions you had, but reading your post I think that I’d recommend not having a separate process for the MsgTransformer, and instead convert that into a plain module that is used by the frontend process. My reasoning is that it sounds like the MsgTransformer process is being used for code organization rather than isolation/resilience (plus adding a process always adds performance overhead). If you haven’t already, I highly recommend reading Saša Jurić excellent blog post on this topic: The Erlangelist - To spawn, or not to spawn?

cmo

cmo

Children are started in the order you list them. Once one returns from init, the next one starts.

w0rd-driven

w0rd-driven

If Frontend depends on it then it should start first. Your second point kind of illustrates that. You could try to detect if the named process is started but you might as well use supervisors to guarantee it.

You are basically pulling the childspec calls from your app into each supervisor with a bit more boilerplate. A supervisor is a behavior of a GenServer, which I map to something like traits in PHP. Since you want to manage dependent processes, it makes sense to group them as a supervisor tree and when your dependency crashes you likely want to re-initialize some state for it.

I think you understand quite a bit but it helps to put theory to practice. You could spike on a throwaway branch and try different strategies or groupings until it “feels right”. You could also look at all the other children your app handles. The docs for supervisors Supervisor — Elixir v1.17.2 has examples and is pretty comprehensive. The DockYard Academy section on supervisors and the drills are a great as well curriculum/reading/supervisors.livemd at main · DockYard-Academy/curriculum · GitHub.

Where Next?

Popular in Questions Top

marius95
Hello everyone, I try to use an Javascript Event Handler in my root.html.leex file. Therefore I created a function in the app.js file: ...
New
fireproofsocks
I’m working on defining a simple Ecto schema for a table (in PostGres), but I don’t see where I can define a column as NOT NULL. Conside...
New
shahryarjb
Hello, I have map which I want to convert it to string like this: the map: %{last_name: "tavakkoli", name: "shahryar"} the string I ne...
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
nobody
How to bind a phoenix app to a specific ip address? could not find anything about that, nowhere, unfortunately, but for me this is quite...
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
JulienCorb
I am trying to implement my new.html.eex file to create new posts on my website. new.html.eex: <h1>Create Post</h1> <%= ...
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
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

Other popular topics Top

sorentwo
Hello! tl;dr Announcing Oban, an Ecto based job processing library with a focus on reliability and historical observability. After spen...
985 42920 311
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
Patoshizzle
After calling mix ecto.create I get this error: 17:00:32.162 [error] GenServer #PID<0.412.0> terminating ** (Postgrex.Error) FATAL...
New
JorisKok
I have a server on AWS, and was running a load test using artillery. When looking at the Phoenix dashboard I see the Ports going to 100% ...
New
pmjoe
I have a relationship of love and hate with Elixir. Lots of things are just absolutely right, but there are some things that are kind of ...
New
aalberti333
As the title describes, I’m trying to run Enum.map() over a list of key/value pairs, where the value is a map. My data looks like this: ...
New
KronicDeth
Elixir plugin for JetBrain’s IntelliJ Platform (including Rubymine) This is a plugin that adds support for Elixir to JetBrains IntelliJ...
289 36128 110
New
rms.mrcs
Hi, I need to transform a list of numbers into a map where the keys are the indexes and the values are the original values of the list. ...
New
AstonJ
We’ve put together this wiki for Phoenix LiveView - please feel free to add any info you feel is worth including. What is Phoenix LiveV...
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