How to stop a GenServer and delete it's Registry under DynamicSupervisor

Hi, I have a normal Genserver which has a normal Supervisor and it’s Supervisor has a DynamicSupervisor and Registry like this:

Genserver1 -> Supervisor -> DynamicSupervisor

I have a problem, when I want to stop a PID and delete it’s Registry. when I call Genserver1.stop like this.

 @impl true
  def handle_cast(:stop, stats) do
    Logger.info("OTP ACL server was stoped and clean State")
    {:stop, :normal, stats}
  end

it is just restrated and DynamicSupervisor.start_child is loaded again, and the default data and this PID’s Registry still exists.

please help me , thanks

Try setting the restart option to :transient or :temporary when starting a child. See DynamicSupervisor.start_child/2

EDIT: I see now that you use a normal Supervisor to start the GenServer. The same still applies that you shoud add restart to the child spec when starting the GenServer

Otherwise the process will get restarted

From iex> h Supervisor

Restart values (:restart)

The :restart option controls what the supervisor should consider to be a
successful termination or not. If the termination is successful, the supervisor
won’t restart the child. If the child process crashed, the supervisor will
start a new one.

The following restart values are supported in the :restart option:

• :permanent - the child process is always restarted.
• :temporary - the child process is never restarted, regardless of the
supervision strategy: any termination (even abnormal) is considered
successful.
• :transient - the child process is restarted only if it terminates
abnormally, i.e., with an exit reason other than :normal, :shutdown, or
{:shutdown, term}.

2 Likes

hi, I did this before use Supervisor, restart: :temporary or transient in my Supervisor not DynamicSupervisor

I think my DynamicSupervisor can let me stop it and delete it’s Registry

this line

 def start_job(args) do
    DynamicSupervisor.start_child(MishkaUser.Acl.AclOtpRunner, {MishkaUser.Acl.AclSupervisor, args})
end

I don’t understand what to do !!

Are you able to share the relevant code? I.e where you start your DynamicSupervisor, your Supervisor and your GenServer?

Also, I am not sure about the strategy you are using with: DynamicSupervisor → Supervisor → GenServer?

Are you starting up dynamic supervision trees? But you register GenServers under the Supervisor?

Yes it is a elixir open source CMS project

at first I add 2 lines in my application file:

https://github.com/shahryarjb/mishka-cms/blob/master/apps/mishka_user/lib/mishka_user/application.ex#L24-L25

after than I crate a normal Genserver:

https://github.com/shahryarjb/mishka-cms/blob/master/apps/mishka_user/lib/acl/acl_management.ex

after than I create a supervisor for it:

https://github.com/shahryarjb/mishka-cms/blob/master/apps/mishka_user/lib/acl/acl_supervisor.ex

after all of them I create DynamicSupervisor:

https://github.com/shahryarjb/mishka-cms/blob/master/apps/mishka_user/lib/acl/acl_dynamic_supervisor.ex


I delete some code like when it has errors, reload Genserver or sth to see code clearly

when I want to save something:

https://github.com/shahryarjb/mishka-cms/blob/master/apps/mishka_user/lib/acl/acl_management.ex#L33-L41

Yes I think, I implemented Genserver under supervisor and implemented supervisor under dynamic supervisor

Thanks, I will have a look at the code.

A first thought is that I am not sure you need the Supervisor in the middle? Why not start the GenServers directly through the DynamicSupervisor?

2 Likes

before this post, I thought I can handle direct Supervisors with their code and strategy, and handle it on DynamicSupervisor (like 2 or 3 supervisor), I think it is wrong and I don’t know why I decided to do this

and I changed this now

  def start_job(args) do
    DynamicSupervisor.start_child(MishkaUser.Acl.AclOtpRunner, {MishkaUser.Acl.AclManagement, args})
  end

I load Genserver direct in my DynamicSupervisor, but still after stop Genserver PID it restart me again and import default value

I think now I can use

DynamicSupervisor.terminate_child(DynamicSupervisor_module_name, pid)

after use this, I cant find the process was killed .

Either you need to add the restart option in start_child or your GenServer should have use GenServer, restart: :temporary

child_spec = Supervisor.child_spec({MishkaUser.Acl.AclManagement, args}, restart: :temporary)
DynamicSupervisor.start_child(MishkaUser.Acl.AclOtpRunner, child_spec)
1 Like

what about this way ?

Should work.

[{pid, _}] = Registry.lookup(YourRegistryName, user_id)
DynamicSupervisor.terminate_child(MishaUser.Acl.AclOtpRunner, pid)
2 Likes