Suggestion to bind dynamic supervisor form starting server

Hello, I have a Genserver under a dynamic supervisor, but from starting a server, I need to check my database and move all the data to each Genserver.

DynamicSupervisorA Genserver → each data in my database has its own PID and Genserver state.

So I always create another Genserver without a dynamic supervisor (B) and define it on my application. Every time the server is started, it loads all data from the database, and in a loop, it sends to my main A Genserver.

So I thought about Oban for my strategies, but do you have any suggestions for this purpose? Just for first binding data, not the time a state is dropped.

gen

Thank you.

Your solution seems to work just fine. Unless I’m missing something, I’m not sure what problem Oban would solve here?

1 Like

Nothing about Oban, I just wanted to create many background jobs, and it is very useless for me, and it doesn’t work for this requirement I need

What does GenServer A do? Can’t you just call start_child with your dynamic supervisor from GenServer B? (Maybe this is already what you do, but I am not sure from the diagram).

As stefanchrobot said this is a classic pattern and it should work fine.

1 Like

I did, but I call start_child in my supervisor not in Genserver B.

Genserver A

@spec add(plugin()) :: :ok | {:error, :add, any} | {:error, :add, :already_started, any}
  def add(%PluginState{} = element) do
    case PSupervisor.start_job(%{id: element.name, type: element.event}) do
      {:ok, pid} ->
        GenServer.cast(pid, {:push, element})
        {:ok, :add, element}
      {:ok, pid, _any} ->
        GenServer.cast(pid, {:push, element})
      {:error, {:already_started, pid}} ->  {:error, :add, :already_started, pid}
      {:error, result} ->  {:error, :add, result}
    end
  end

DynamicSupervisor.

@spec start_job(%{id: atom(), type: atom()}) :: :ignore | {:error, any} | {:ok, pid} | {:ok, pid, any}
  def start_job(args) do
    DynamicSupervisor.start_child(MishkaInstaller.Cache.PluginStateOtpRunner, {MishkaInstaller.PluginState, args})
  end

In my ‍Genserver A, we have some functions to do much stuff, like we let system add some new state update and re check use of these functions. Hence, it is very important each data has own state, because if a state is dropped the other should work

But the problem I have is when I down and start my server, I need to bind it just for once

Is it necessary to have all your data running in its own genservers from the beginning?

I’m curious about your memory requirements as your data grows more and more, because if only a small subset of data would be accessed over some period of time, it may be easier for A to fetch specific data and spawn a process if it doesn’t exist already.

Then the process keeps itself alive while it’s being used and spins down if there’s no activity over the time needed for your use case, e.g. 5 minutes or an hour.

2 Likes

Yes, because it is about all plugins installed in my CMS and at the runtime we should check and every page too.
So it is limited, and I do not think it takes a big space in a Ram, but it is always necessary to be stable and exist in my ram then I created many checkers and strategies if they are terminated or something else.

Yes sorry I should have been more precise, you call start_child from server B process. So it’s fine.

Now I see that you use server B as a registry. Instead of registering the pid you may use an actual Registry so the processes are registered by name. And use a :rest_for_one strategy so if your dynamic supervisor restarts, server B is restarted too and will spawn your servers As again. And at this point server B could just be a Task.

Does that make sense?

1 Like

Oh I see, that makes sense. Thanks :+1:

1 Like

Hi @lud, no, I just use Genserver B to bind Genserver A from the beginning of the server (just for once). And I have my own registry in my supervisor, and I introduced it on my Application.