Thanks for spelling it out. Yes it works. smilie

defmodule A do
  use GenServer


  def start_link() do
    GenServer.start_link(__MODULE__, nil, name: :a)
  end

  def apple() do
    GenServer.call(:a, :apple)
  end

  def handle_call(:apple, _from, state) do
    IO.puts "In apple handle_call, going to call banana"

    try do
      B.banana(5)
    catch :exit, reason ->
        IO.puts "caught :exit, reason is #{inspect reason}"
    end
    
    {:reply, :ok, state}
  end

  def handle_info(msg, state) do
    IO.puts "Handle_info, msg received #{inspect msg}"

    {:noreply, state}
  end

end


defmodule B do
  use GenServer


  def start() do
    GenServer.start(__MODULE__, nil, name: :b)
  end

  def banana(value) do
    GenServer.call(:b, {:banana, value})
  end

  def handle_call({:banana, value}, _from, state) do
    IO.puts "In banana handle_call, about to explode"

    case value do
      5 -> raise "Pigs are flying, crashing now"
      _ -> ""
    end

    {:reply, :ok, state}
  end

end




Interactive Elixir (1.3.2) - press Ctrl+C to exit (type h() ENTER for help)
iex(1)> B.start
{:ok, #PID<0.109.0>}
iex(2)> A.start_link
{:ok, #PID<0.111.0>}
iex(3)> A.apple
In apple handle_call, going to call banana
In banana handle_call, about to explode
caught :exit, reason is {{%RuntimeError{message: "Pigs are flying, crashing now"}, [{B, :handle_call, 3, [file: 'lib/propagate.ex', line: 50]}, {:gen_server, :try_handle_call, 4, [file: 'gen_server.erl', line: 615]}, {:gen_server, :handle_msg, 5, [file: 'gen_server.erl', line: 647]}, {:proc_lib, :init_p_do_apply, 3, [file: 'proc_lib.erl', line: 247]}]}, {GenServer, :call, [:b, {:banana, 5}, 5000]}}
:ok
iex(4)> 
12:03:47.149 [error] GenServer :b terminating
** (RuntimeError) Pigs are flying, crashing now
    (propagate) lib/propagate.ex:50: B.handle_call/3
    (stdlib) gen_server.erl:615: :gen_server.try_handle_call/4
    (stdlib) gen_server.erl:647: :gen_server.handle_msg/5
    (stdlib) proc_lib.erl:247: :proc_lib.init_p_do_apply/3
Last message: {:banana, 5}
State: nil

nil
iex(5)> Process.whereis(:a)
#PID<0.111.0>
iex(6)> Process.whereis(:b)
nil


In Section 8.23 where Monitors are discussed, there is a small grey box that mentions that exits are propagated through gen_server calls. How do you trap these?

Let's say you have a module A which is a GenServer

You also have a module B, which also is a GenServer


in one of A's handle_call method's you issue a GenServer.call(B_pid, :foo)

if The Server Process B crashes during this call, the error will be propagated to Server Process A.

What needs to be done in either modules A or B to trap exits here? I've experimented with trapping exits in module A's init function and supplying the relevant handle_info function but to no success. The Process A dies. I'm assuming the Server Process A is also monitoring Process B.

Is there some different technique to trap exits that are propagated through gen server calls?

Thank you very much!
Awesome! Thanks so much -- Have a good weekend
Hello again Sasa,

I'm trying to run my application on an iMac, my dev version was on Xubuntu

I did the standard steps to compile a release for this new target architecture but I am getting a strange error. (I'm using the instructions to include exrm as a compile time dependency to be able to use the mix release task)

$ mix deps.get
$ mix local.hex
$ MIX_ENV=prod mix compile --no-debug-info
$ MIX_ENV=prod mix release
$ rel/game/bin/game console

readlink: illegal option -- f
usage: readlink [-n] [file ...]
usage: dirname path
cat: //releases/start_erl.data: No such file or directory
cat: //releases/start_erl.data: No such file or directory
Using //releases//game.sh
rel/game/bin/game: line 11: //releases//game.sh: No such file or directory
rel/game/bin/game: line 11: exec: //releases//game.sh: cannot execute: No such file or directory

I'm not sure what's happening here? Could this be related to the versions of my dep packages no quite working on Mac as they did before?

Cheers ~ Bibek
Makes sense. I see a lot of references to using ETS in elixir code but not soo much mnesia, maybe for the reason you describe. Well, if you ever do a 2nd version, I wouldn't mind a section on Postgres then smilie

I have another question for you.

I tried using the runtime_tools -- specifically the observer. I was salivating to the idea of being able to drill into the ETS data for my application. However, I got an error

$ iex --hidden --name observer@127.0.0.1 --cookie game
Erlang/OTP 18 [erts-7.2] [source] [async-threads:10] [kernel-poll:false]

Interactive Elixir (1.2.3) - press Ctrl+C to exit (type h() ENTER for help)
iex(observer@127.0.0.1)1> :observer.start

16:37:41.654 [error] WX ERROR: SMP emulator required (start with erl -smp)
{:error,
{:not_smp,
[{:wxe_server, :start, 1, [file: 'wxe_server.erl', line: 65]},
{:wx, :new, 1, [file: 'wx.erl', line: 115]},
{:observer_wx, :init, 1, [file: 'observer_wx.erl', line: 96]},
{:wx_object, :init_it, 6, [file: 'wx_object.erl', line: 337]},
{:proc_lib, :init_p_do_apply, 3, [file: 'proc_lib.erl', line: 240]}]}}
iex(observer@127.0.0.1)2>

Where do I specify erl -smp? Were you doing this implicitly in your setup?

Thanks again!

Cheers,
Bibek
Awesome Sasa - thanks. I got the wrk tool to run. Thank you.

With your 'optimized' updates to database_worker and database involving mnesia, it seems fitting for the next book edition to perhaps have a section on mnesia. Pretty neat to see some readable elixir code using mnesia!

Bibek
First off, I just want to say how amazing this book was for me to understand elixir/erlang/otp. It is very well-written and practical. I really was able to develop an intuitive feel of things. So thank you Sasa immensely for writing this book.

I had a question on Chapter 11, after you setup the web module which uses plug and the cowboy adapter, how exactly did you load test the module?

Were you using standard tools like curl or did you have a more elaborate load testing setup? How exactly did you achieve the 2 min load test of 20,000 / s. Cheers Bibek