(EXIT) no process: the process is not alive or there's no process currently associated with the given name, possibly because its application isn't started

I have an umbrella app.

Some of the apps inside depend on other apps in the umbrella, unsurprisingly.

I’m writing a test for one of the apps which currently relies on starting a process using one of the other apps.

Almost all such processes across these apps use an app-specific or purpose-specific Registry.

This is the error I get:

23:04:13.529 [error] GenServer {Registry.Mobs, 1} terminating
** (stop) exited in: GenServer.call({:via, Registry, {World.LocationRegistry, "2"}}, {:mobs, #Function<1.42779424/1 in Mobs.Bird.handle_cast/2>}, 5000)
    ** (EXIT) no process: the process is not alive or there's no process currently associated with the given name, possibly because its application isn't started
    (elixir) lib/gen_server.ex:729: GenServer.call/3
    (mobs) lib/mobs/bird.ex:79: Mobs.Bird.handle_cast/2
    (stdlib) gen_server.erl:601: :gen_server.try_dispatch/4
    (stdlib) gen_server.erl:667: :gen_server.handle_msg/5
    (stdlib) proc_lib.erl:247: :proc_lib.init_p_do_apply/3
Last message: {:"$gen_cast", :try_to_mate}
State: %Mobs.Bird{controller: #PID<0.395.0>, gender: :female, id: 1, lifespan: 39, location_id: "2", name: "a bird", pregnant: nil}

My test_helper.exs is trying to provide support to the mix.exs file which requires the apps by doing this:

Application.ensure_all_started(:world)
Application.ensure_all_started(:mobs)
Application.ensure_all_started(:controllers)
Application.ensure_all_started(:life)
ExUnit.start()

The World.Application module looks like this:

defmodule World.Application do
  # See http://elixir-lang.org/docs/stable/elixir/Application.html
  # for more information on OTP Applications
  @moduledoc false

  use Application

  def start(_type, _args) do
    import Supervisor.Spec, warn: false

    # Define workers and child supervisors to be supervised
    children = [
      supervisor(Registry, [:unique, World.LocationRegistry], id: :location_registry),
      supervisor(Registry, [:unique, World.PathwayRegistry], id: :pathway_registry),
      supervisor(World, [%{spawn_locations: Application.get_env(:world, :spawn_locations)}])
    ]

    # See http://elixir-lang.org/docs/stable/elixir/Supervisor.html
    # for other strategies and supported options
    opts = [strategy: :one_for_one, name: World.Supervisor]
    Supervisor.start_link(children, opts)
  end
end

This is the test as it stands:

defmodule Mobs.BirdTest do
  use ExUnit.Case
  doctest Mobs.Bird

  test "only mates with birds" do
    import IEx
    {:ok, foo} = World.Location.start_link(
      %World.Location{
        id: "2",
        name: "center of the universe",
        description: "what's on the tin",
        pathways: []}
    )
    female_bird = Mobs.Spawn.birth(
      %{module: Mobs.Bird, location_id: "2", gender: :female})
    male_dwarf = Mobs.Spawn.birth(
      %{module: Mobs.Dwarf, location_id: "2", gender: :male})
    :ok = Mobs.Bird.try_to_mate(female_bird)
  end
end

The obviously relevant code from Mobs.Bird is :

defmodule Mobs.Bird do
  def try_to_mate(id) do
    GenServer.cast(via_mob(id), :try_to_mate)
  end

  def handle_cast(:try_to_mate, state) do
    looking_for = case state.gender do
                    :male -> :female
                    :female -> :male
                  end

    possible_partners =
      World.Location.mobs(
              state.location_id,
              fn({{module, id}, info}) -> module == __MODULE__ && info.gender == looking_for end)

    if Enum.any? possible_partners do
      partner = Enum.random possible_partners

      case [state.gender, elem(partner, 1).gender] do
        [:male, :female] -> __MODULE__.pregnantize(elem(partner, 0))
        [:female, :male] ->  __MODULE__.pregnantize(state.id)
      end
    end
    {:noreply, state}
  end
end 

Similarly, the obviously relevant code from World.Location is :

defmodule World.Location do
  def mobs(loc_id)do
    mobs(loc_id, fn(_x) -> true end)
  end

  def mobs(loc_id, filter) do
    GenServer.call(via_tuple(loc_id), {:mobs, filter})
  end

  def handle_call({:mobs, filter}, _from, state) do
    mobs = Enum.filter(state.entities, filter)
    {:reply, mobs, state}
  end
end
2 Likes

I had this problem before Elixir 1.4 when I forgot to add the umbrella dependency to my list of applications in my mix.exs, but I’m not sure that would be a problem with the new extra_applications.

1 Like

The other thing that comes to mind is that the registry via tuple reference

isn’t actually made available by

{:ok, foo} = World.Location.start_link(
  %World.Location{
    id: "2",
    name: "center of the universe",
    description: "what's on the tin",
    pathways: []
  }
)

I’d check your World.Location.start_link/1 code again.

1 Like

The mix.exs for the Mobs app includes this:

  def application do
    [extra_applications: [:logger],
     mod: {Mobs, []}]
  end

  defp deps do
    [
      {:faker, "~> 0.7.0"},
      {:world, in_umbrella: true},
      {:controllers, in_umbrella: true},
      {:dialyxir, "~> 0.4", only: [:dev], runtime: false},
      {:credo, "~> 0.6.1"}
    ]
  end
1 Like

The start_link/1 code for World.Location is as follows:

defmodule World.Location do
  def start_link(args) do
    GenServer.start_link(__MODULE__, args, name: via_tuple(args.id))
  end

  defp via_tuple(id) do
    {:via, Registry, {LocationRegistry, id}}
  end
end
1 Like

In order to debug this, I would try replicating the situation in a regular shell (no need to deal with timeouts, that get nasty trying to use visual tools, like observer). Some things you can then try (some are possible when running through tests as well):

  • turn on sasl reports to get supervisor progress reports as described in: https://github.com/elixir-lang/elixir/blob/master/lib/logger/lib/logger.ex#L147
  • Check the result of GenServer.whereis/1 just before calling the process
  • Check the state of the registry ets table in observer - you should see what processes are exactly registered
  • Subscribe to the events of the problematic process with :sys.trace/2
  • bring out the big guns and start tracing what is happening using recon or redbug.
8 Likes

I will try what you mentioned.

I tried it with an IEx.pry and couldn’t replicate it.

1 Like

@michalmuskala @christhekeele

I found the root cause.

It turns out the way the test is written, the test ends too quickly, and since it’s an async call, the location IS ALREADY DEAD by the time I am trying to send it a message.

Fun times.

Thank you both for your time and effort here, and @michalmuskala thanks for showing me all those really cool tools, they’ve really taught me a lot.

4 Likes

FWIW, I ended up on this page because I had converted my app that I generated with mix new to have a supervisor and I had forgot to add

mod: {MyApp.Application, []}

into the mixfile’s application function. So… if you are new and you see this error. Maybe check that!

4 Likes

@Trevoke I’m experiencing this same issue (process is not alive) in my test suite randomly. I see you found the root cause, but wondering how did you fix/work around this issue?

I, naively, attempted to work around the issue by mocking the process to kick off async calls. That seemed to fix some of the tests but then other new tests that started failing randomly.

Thanks.

Welcome to the forum!

Without any code there really can’t be a specific answer.

In general it comes down to synchronizing actions between processes with messages, signals (via links) and monitors.

For some ideas have a look at this example.

1 Like

Oof, this is old! (well, old-ish).

So, what was happening in my test was, it turns out, very simple: I had async behavior that existed independently of the tests. As a consequence, the test could end before the behavior could be resolved.

I think I solved this by a combination of two techniques:

  1. I decided that I did not need to do async testing and I just tested the behavior inline
  2. I decided that I could pass the test process in with self() and use assert_receive to cause a synchronous wait for a message

HTH!

2 Likes