Oliver

Oliver

Supervisor dies with its child?

I have an application with the following setup:

  • There is a central supervisor which is initialized with a child spec at startup encompassing three permanent children. It is started with start_link/2 in the application’s start/2.
  • During the run of the application I start a child supervisor by calleing the central supervisor with start_child/2 and Supervisor.Spec.supervisor/3. This one is started as transient.
  • The child supervisor starts a set of children with transient and one_for_all.

The intent behind that is that each group of workers is tied together and is dismissed after its common task is done. The child supervisor is supposed to restart children on errors only but to let them go gracefully when their job is done. (A “normal” exit.)

The central supervisor has a name (alias MyMod.Supervisor) it was started with. When I query it with Supervisor.which_children(MyMod.Supervisor) it shows me the child supervisor is there.

Now:

  • Whenever I try to use Process.exit/2 to end the child supervisor nothing happens.
  • When I use Supervisor.terminate_child/2 with the assigned child ID in the central supervisor, it returns ok but the next call to Supervisor.which_children(MyMod.Supervisor) tells me there is no process (the central supervisor died)
  • When I use Supervisor.stop/2 in the child with its registered name and :normal I also can afterwards not query the central supervisor (again, it died).

It seems like no matter what I do, if the child exits, the central supervisor exits. I’ve played around with the Supervisor.Spec I created it with. Made no difference.

Any ideas?

Marked As Solved

josevalim

josevalim

Creator of Elixir

Quick tip: you should investigate if this is related to the controlling process: http://erlang.org/doc/man/gen_tcp.html#controlling_process-2

Also Liked

NobbZ

NobbZ

Can you provide a minimal example project which does show your problem? Only from your wording, I can roughly understand the problem you have, but without seeing what you are really doing, one can’t tell what you are doing wrong…

Oliver

Oliver

Hmmm… tried to do that, but my sample project seems to work:

[code]defmodule Test do

import Supervisor.Spec

def start do
# static children
children = [
worker(Worker, [0], restart: :permanent, id: :static1),
worker(Worker, [1], restart: :permanent, id: :static2),
worker(Worker, [2], restart: :permanent, id: :static3)
]

Supervisor.start_link(children, strategy: :one_for_one, name: Central.Supervisor)
    Supervisor.start_child(Central.Supervisor,
                           supervisor(Worker.Supervisor, [3], restart: :transient, id: :super))
    test

end

def test do
IO.puts “Central: #{inspect Supervisor.which_children(Central.Supervisor)}”
IO.puts “Worker: #{inspect Supervisor.which_children(Worker.Supervisor)}”

# Supervisor.terminate_child(Central.Supervisor, :super)
    Worker.Supervisor.stop
    IO.puts "Central: #{inspect Supervisor.which_children(Central.Supervisor)}"

end

end

defmodule Worker.Supervisor do

use Supervisor

def start_link(id) do
Supervisor.start_link(MODULE, [id], name: Worker.Supervisor)
end

def init([id]) do
children = [
worker(Worker, [id], restart: :transient, id: 0),
worker(Worker, [id+1], restart: :transient, id: 1),
worker(Worker, [id+2], restart: :transient, id: 2)
]

supervise(children, strategy: :one_for_all)

end

def stop do
Supervisor.stop(Worker.Supervisor)
end

end

defmodule Worker do

use GenServer

def start_link id do
GenServer.start_link(MODULE, [], name: {:global, {:worker, id}})
end

end[/code]

Oliver

Oliver

Now I have SASL reports for my app and the following transpires:

2016-04-3011:59:51.496[ERR/connector.ex:43] Received error when listening on TCP port, reason was :closed 2016-04-3011:59:51.496[ERR/SASL] GenServer {:connector, 1} terminating | ** (stop) :error 2016-04-3011:59:51.498[ERR/SASL] Process #PID<0.235.0> terminating ** (exit) :error (stdlib) gen_server.erl:826: :gen_server.terminate/7 (stdlib) proc_lib.erl:240: :proc_lib.init_p_do_apply/3 Initial Call: Connector.init/1 Ancestors: [#PID<0.233.0>, MyMod.Supervisor, #PID<0.181.0>] 2016-04-3011:59:51.498[ERR/SASL] Child {:connection, 1} of Supervisor {:supervisor, 1} shutdown abnormally | ** (exit) :error | Pid: #PID<0.235.0> | Start Call: Connector.start_link(1, #Port<0.7095>) 2016-04-3011:59:51.498[INF/SASL] Application myapp exited: normal

In my application startup I create a TCP listener port:

{ :ok, listenSocket } = :gen_tcp.listen(readUeTcpPort(), [:binary, active: true, packet: :raw, reuseaddr: true])

I then give the listenSocket to each worker child I start:

def addWorker(workerId, listenSocket) do Supervisor.start_child(MyMod.Supervisor, supervisor(Worker.Supervisor, [workerId, listenSocket], restart: :transient, id: {:worker, workerId}, shutdown: :infinity)) end

These workers run their init/1 and send themselves a GenServer.call that makes them wait on :gen_tcp.accept. The first worker is dynamically created during the run of my application’s start/2.

Whenever a new client is accepted, the worker immediately calls MyMod.addWorker to start the next process waiting on the listen port.

Now, when I stop the supervisor of the first group of workers, something odd happens. The 2nd worker suddenly drops out of its :gen_tcp.accept call it is sleeping on with an error. Apparently the listenSocket is somehow closed. And somehow this leads to my whole application to quietly shut down with exit :normal.

Any ideas?

Oliver

Oliver

Hello, José.

After rearranging everything under another supervisor I played around with :gen_tcp.controlling_process, and after reading its docs another time and also checking its return value I managed to properly transfer control to the children and also not have this weird exit behavior anymore.

Thank you. :smile:

Aetherus

Aetherus

I have a similar problem.

I have a top level dynamic supervisor, say, TopDynSup, whose children are in turn supervisors. The sub supervisors each supervises a fixed number of temporary workers (they should never be restarted even if they died abnormally).

My problem is, I want to let the sub supervisor terminates normally when all of its children terminates. As I played around Supervisor in iex, I saw that a supervisor never ends even when there is no child. How can I make it die?

Where Next?

Popular in Questions Top

lessless
I believe there are people here who are dealing with CSV files import on the daily basis, and since Excel is a really popular tool there ...
New
openscript
Hello! Sorry for this astonishing simple question, but I’m really stuck. I try to set up the intellij-elixir plugin, but I don’t know ho...
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
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
polypush135
As many of you may have realized by now (sorry for all the posts here) I’ve been working on a db problem where I’m trying to aggregate a ...
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
hpopp
To simplify some tasks at work, I wrote and published this package yesterday. It’s a simple macro that enables Access behaviour on struct...
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
lucidguppy
I have a super simple question about elixir - how would I take a file like this foo bar baz and output a new file that enumerates th...
New
lanycrost
Hi everyone! I need implement if…else if…else condition from my elixir code, and anymore of this control flow structures not work proper...
New

Other popular topics Top

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
dotdotdotPaul
Okay, I'm having a heck of a time trying to figure out how to best handle the validation of belongs_to associations in Ecto. I'm sure I'...
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
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
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
vac
Hi, I'm quite new in Elixir and I'm trying to format a string to a PEM format. I have the certificate value like MIIDBTCCAe2...... and ...
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
beno
I will often find my self writing things similar to: case some_value do nil -&gt; something() "" -&gt; something() _ -&gt; someth...
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

We're in Beta

About us Mission Statement