shahryarjb

shahryarjb

Help to understand PartitionSupervisor in elixir 1.14

Hi, I have read the PartitionSupervisor documents and I think I need help to understand it.

For example:

defmodule MishkaInstaller.Application do
    use Application
    @impl true
    def start(_type, _args) do
      plugin_runner_config = [
        strategy: :one_for_one,
        name: PluginStateOtpRunner
      ]
      children = [
        {DynamicSupervisor, plugin_runner_config},
      ]
      opts = [strategy: :one_for_one, name: MishkaInstaller.Supervisor]
      Supervisor.start_link(children, opts)
    end
  end

So I started it in a file named like plugin_state_dynamic_supervisor.ex this:

def start_job(args) do
    DynamicSupervisor.start_child(PluginStateOtpRunner, {MishkaInstaller.PluginState, args})
end

and finally, in my Genserver module:

  def start_link(args) do
    GenServer.start_link(__MODULE__, [], name: via(id, type))
  end
  
  defp via(id, value) do
    {:via, Registry, {PluginStateRegistry, id, value}}
  end

So every time I want to select a Genserver I am using a registry like this:

  def get_plugin_pid(module_name) do
    case Registry.lookup(PluginStateRegistry, module_name) do
      [] -> {:error, :get_plugin_pid}
      [{pid, _type}] -> {:ok, :get_plugin_pid, pid}
    end
  end

Now where I can use PartitionSupervisor to improve it? And the second question is with this ways If 1000 user call get_plugin_pid function and load a data from a specific state in a same time, I am going to have a bottleneck?

Thank you in advance


Genserver, and the Supervisor

  1. https://github.com/mishka-group/mishka_installer/blob/master/lib/plugin_manager/state/plugin_state.ex
  2. https://github.com/mishka-group/mishka_installer/blob/master/lib/plugin_manager/state/plugin_state_dynamic_supervisor.ex

Marked As Solved

msimonborg

msimonborg

No problem!

If you have many users concurrently starting dynamic processes then the PartitionSupervisor may help reduce bottlenecks in that process. At least it won’t hurt : )

Registry is the right tool for this, it uses ETS tables which provide good read concurrency when being accessed my many processes. Consider partitioning your registry for better concurrency.

You may experience bottlenecking with this, you can run some basic load tests on your own to find out. If you have many processes concurrently accessing the same state then this could be a good use case for an ETS table with the read_concurrency: true option.

Also a good use case for wanting this state in an ETS table. I personally find it helpful to think of genserver state as something that the genserver uses to do its work, maybe a few processes will access it. If you plan to have many concurrent processes accessing shared state then it’s better to store it in ETS rather than a single process

If the state is only read and never updated, then it could be a good use case for persistent_term, which is optimized for reads at the expense of writes. Just be sure to read the performance tradeoffs in the module documentation very carefully.

It doesn’t seem like you’d have many issues with this if the state is only being read by 5 processes that all belong to the same user.

Also consider whether all or any of this state should be persisted into a Postgres database instead of in memory : ) Some of the complexity may disappear

Ultimately the PartitionSupervisor will probably only help you by reducing bottlenecks at your DynamicSupervisor, which seems like it could be a good fit for your app and it’s a very simple migration so it can’t hurt. I don’t think it will help with your other needs.

Also Liked

msimonborg

msimonborg

In this case you would use PartitionSupervisor to partition your DynamicSupervisor and spread out the work load from one supervisor to many, with the default number of partitions being equal to the number of cores i.e. System.schedulers_online/0. This would reduce bottlenecks at your DynamicSupervisor for the work it’s doing, like starting, stopping, and restarting your plug-in processes. If you have a lot of concurrency with starting and stopping these processes then this may help you. The PartitionSupervisor would not prevent your get_plugin_id function from bottlenecking, since that is going through a Registry, not your DynamicSupervisor. To maximize concurrency and reduce bottlenecks with your Registry you can manually increase the number of partitions with the :partitions option, e.g. {Registry, keys: :unique, name: PluginStateRegistry, partitions: System.schedulers_online()}.

In my app there are many processes that may be started concurrently by many users. Each process does some clean up in the terminate/2 callback at shutdown. During deployments and scale-downs I need nodes to shutdown gracefully, and these processes must store their state to perform an eventual handoff to a new process that might start on another node and continue its work. I noticed in load testing that when the number of these processes under a single DynamicSupervisor reached a certain level, shutdowns took a really long time. When I tested out replacing the dynamic supervisor with PartitionSupervisor on my 8-core machine the shutdown time decreased dramatically, far more than 8x. This was so helpful for my use case that I copied the PartitionSupervisor module directly into my app so I can start using it without depending on pre-release 1.14.

If you have any particular questions about migrating to PartitionSupervisor I’d be happy to try and help.

msimonborg

msimonborg

This was my try at answering your second question. If your get_plugin_pid function is using Registry then no part of the call is hitting your DynamicSupervisor, so optimizing with a PartitionSupervisor will not help. Optimizing Registry with more partitions might be helpful. Or, are you more concerned with this piece of code GenServer.call(pid, {:pop, :module})? Sorry if I’m misunderstanding your question.

shahryarjb

shahryarjb

I am very grateful to you, and thank you for your time, I try to change my code to PartitionSupervisor after releasing elixir 1.14 Official

Where Next?

Popular in Questions Top

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
vonH
In asking this question I am more interested about the expressiveness of the language itself and less concerned about the availability of...
New
yawaramin
In the Dialyzer docs ( http://erlang.org/doc/man/dialyzer.html#requesting-or-suppressing-warnings-in-source-files ), there is a way to tu...
New
lastday4you
I wanted to check elixir version in phoenix because i found that my elixir is 1.5 but when i use Enum.chunk_by it said the function is un...
New
makeitrein
Hey all, just started picking up Elixir last week and am writing a scraper as a learning project. Baby step #1 is extracting the number ...
New
electic
Hi, I am new to Elixir. I am trying to use the DateTime component to insert a date into MySQL however the there seems to be no way to fo...
New
kostonstyle
Hi all I want to have a unix time, from the current time plus 1 hour. DateTime.now + 1 hour How to get it in elixir? Thanks
New
Codball
Mix format works fine if run from the cmd. I’ve followed this to facilitate the implementation into VSC which involves downloading an ext...
New
wernerlaude
In AR this is so simple @articles = current_user.articles How to do in Ecto? def index(conn, _params) do current_user = conn.assig...
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

Other popular topics Top

Tee
can someone please explain to me how Enum.reduce works with maps
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
axelson
This post is a wiki (feel free to hit the edit button near the bottom right of this post to add your own changes!) This post collects co...
239 45766 226
New
_russellb
I want to try my hand at web scraping. What tools/libraries do I need to use. I’m hoping to turn this into something professional so don’...
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
fayddelight
I tried installing elixir 1.11.2 erlang 23.3.4 via asdf in my zsh shell. Enabled the versions locally and globally. When I list them ...
New
electic
Hi, I am new to Elixir. I am trying to use the DateTime component to insert a date into MySQL however the there seems to be no way to fo...
New
chrisalley
ExUnit now has describe blocks which is a welcome addition coming from RSpec. In the docs, it states that nested hierarchies of describe ...
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
Nvim
Elixir appears to be a superior language to Python. I don’t see any advantage of Python over Elixir. Are there any?
New

We're in Beta

About us Mission Statement