如何从Elixir GenServer处理程序中调用其他函数?

时间:2016-10-24 15:17:15

标签: function erlang elixir otp gen-server

我有一个实现单个项目功能的GenServer,例如:

def handle_call({:sync, id}, _from, state) do
    ## update data
    {:reply, data, sync}
end

现在我想为多个ID处理此功能,例如:

def handle_call({:sync_all, ids}, _from, state) do
    ## call sync for each id
    data = Enum.map(ids, fn(id) ->
        GenServer.call(self(), {:sync, id})
    end)
    ## Further reduce down data to stats
    {:reply, data, sync}
end

然而,这并不能告诉我该过程试图调用自己。

我认为这必须归因于call的阻止性质。如果我在cast版本中使用sync_all,则会发生同样的情况。

所以我的问题是:如何在GenServerhandle_call函数中调用其他handle_cast个任务?

2 个答案:

答案 0 :(得分:7)

在这种情况下,您通常会将共同逻辑提取到单独的函数中:

def handle_call({:sync, id}, _from, state) do
  {data, state} = do_sync(id, state)
  {:reply, data, state}
end

def handle_call({:sync_all, ids}, _from, state) do
  {data, state} = Enum.map_reduce(ids, state, &do_sync/2)
  {:reply, data, state}
end

defp do_sync(id, state) do
  # do something
  {data, new_state}
end

答案 1 :(得分:1)

对同一进程进行GenServer调用没有多大意义。一个进程一次处理一条消息。通话将等待回答。但是,在完成当前消息之前,该过程无法应答。您拥有的代码将等待答案超时,因为进程永远不会完成处理当前消息,因此永远不会处理随呼叫发送的消息。

通常,您使用强制转换和调用来定义其他进程的接口,以将消息发送到进程。您可以将实际数据转换建模为纯函数,然后根据需要从两个处理函数中调用这些函数。