Last active
September 23, 2016 17:35
-
-
Save myronmarston/6fd65606246c842c9420460637debf88 to your computer and use it in GitHub Desktop.
Example of handling errors when using `GenServer.reply/2`
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
defmodule Registry do | |
# ... | |
def handle_call({:execute_against_shard, campaign_id, fun}, from, state) do | |
{shard_process, state} = find_or_create_shard(campaign_id, state) | |
ShardProcess.execute_and_reply(shard_process, fun, from) | |
{:noreply, state} | |
end | |
# ... | |
end |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
defmodule ShardProcess do | |
# ... | |
def handle_cast({:execute, fun, {client_pid, monitor_ref} = reply_to}, state) do | |
{result, state} = try do | |
execute_fun(fun, state) | |
rescue error -> | |
# This is a bit weird, but is necessary to ensure that the client that | |
# made the `GenServer.call` is properly notified of the failure and aborts | |
# immediately (instead of waiting on the timeout). `GenServer.call` sets | |
# a monitor and, after sending the message, waits for either a response | |
# or a `:DOWN` message matching the monitor ref. To cause its `receive` | |
# to match a message (and not just wait for the timeout), we have to send | |
# a `:DOWN` message matching what it is looking for. | |
# | |
# Normally this kind of thing is unnecessary because GenServers typically | |
# reply from `handle_call` (that is, the process which the client is monitoring) | |
# but in this case, the client is monitoring the registry but we are replying | |
# from a ShardProcess. So we have to do a non-standard thing here. | |
stacktrace = System.stacktrace() | |
send(client_pid, {:DOWN, monitor_ref, :process, self(), error}) | |
reraise(error, stacktrace) | |
end | |
GenServer.reply(reply_to, result) | |
{:noreply, state} | |
end | |
end |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment