在elixir GenServer
中,有同步和异步方法,handle_cast
和handle_call
。在异步情况下,如果方法失败,我该如何获得通知?
方法失败意味着在handle_call
方法中,我需要定义一些逻辑来查询/写入数据库。如果数据库操作失败,我需要通知调用者有关此失败的信息。在异步方法中,我该怎么做?
答案 0 :(得分:1)
所以评论鼓励你让它死去'一般都是正确的。惯用的Erlang和Elixir要求“快速失败”,并让主管重新启动任何组件崩溃。
尽管如此,有时候崩溃并不合适;通常当你知道可能会出现负面结果时。标准库中的许多API通过返回结果元组(即{:ok, result}
或{:error, reason}
来处理此问题,并使调用代码负责崩溃或尝试其他内容。
在您的用例中,我认为您应该只使用数据从进程中调用数据库写入/查询代码,而不使用异步方法,首先修复数据库性能。如果这确实是一个长期运行的查询,并且优化数据库并不是正确的答案,那么您的下一个最佳选择是Task
模块(documentation here),Elixir的一部分&#39; s标准库 - 它为异步任务执行提供了内置功能。</ p>
我知道人们不回答你的问题是多么令人沮丧,所以我会回答它;但请注意,这几乎肯定不是解决原始问题的正确方法。
关键的洞察力是将调用进程的pid传递给Worker,以便以后可以发送结果消息:
defmodule CastBackExampleWorker do
use GenServer
# ...
def do_operation(args) do
caller = self()
ref = make_ref()
# Pass the caller's pid to the GenServer so that it can message back later
GenServer.cast(__MODULE__, {:do_operation, caller, ref, args})
# hand back a unique ref for this request
ref
end
# ...
def handle_cast({:do_operation, caller, ref, args}, state) do
case execute_operation(args) do
{:ok, result} -> send(caller, {__MODULE__, ref, {:ok, result}})
{:error, reason} -> send(caller, {__MODULE__, ref, {:error, reason}})
end
{:noreply, state}
end
end
defmodule CastBackExampleClient do
use GenServer
# ...
def handle_call(:my_real_work, _from, state) do
# ignoring the ref, but we could stick it into our state for later...
_ref = CastBackExampleWorker.do_operation([])
{:reply, :ok, state}
end
def handle_info({CastBackExampleWorker, _ref, outcome}, state) do
# Do something with the outcome here
{:noreply, state}
end
end