GenServer及其状态

时间:2017-05-02 10:38:08

标签: elixir gen-server

我这个简单的genserver:

def handle_info(:tick, items) do
  items2 = do_job(items)
  tick()
  {:noreply, items2}
end

在" do_job"我需要a)迭代throug项目,b)发出一个http请求,这可能需要很长时间,c)取决于响应,更新数据库并通过从" items"中删除它来完成当前项目。或者只是更新数据库:

def do_job(items) do
  Enum.each(items, fn(a) -> # or Enum.map
    Task.start fn ->

      case external_request(a) do
        {:terminate, data} ->
          Repo.update(....)
          remove(a) # send a message to this GenServer to remove itself

        {:continue, data} ->
          Repo.update(....)
      end

    end
  end)
end

1)我是否必须返回新值 - 更新列表/状态 - 来自" do_job"允许我的GenServer正常工作?

2)如果是这样,怎么样?我无法从" do_job"中恢复更新状态。因为我需要为每个项目创建一个任务,因为它需要在数据库中发送http请求和CRUD操作。这就是为什么是异步任务的原因。

3)一般来说, GenServer自己管理状态变量,在这种情况下是"" items"。什么允许GenServer了解如何更新它?我们来考虑一下这段代码:

def add(a) do
  GenServer.cast(__MODULE__, {:add, a}) # what/who utilizes this return value?
end

def remove(....) do
  # ....



def handle_cast({:add, a}, items) do
  {:noreply, [a | items]}  # what/who utilizes this return value?
end

客户未使用来自&#34的返回值;添加"或"删除",因此它被扔掉了。尽管如此,当客户呼叫"添加" 3次,这个GenServer将在列表中有3个项目。但为什么? GenServer如何处理?

1 个答案:

答案 0 :(得分:2)

  

1)我是否必须从“do_job”返回一个新值 - 更新列表/状态 - 以使我的GenServer正常工作?

您没有 handle_info返回新的更新列表,但是如果您返回相同的列表,则下一条:tick消息可能会导致一组新的如果您通过稍后从{:terminate, _}向此GenServer发送消息来处理删除作业,则即使第一次运行最终会返回do_job,也会要求对相同项目发出请求。

  

2)如果是这样,怎么样?我无法从“do_job”返回更新状态,因为我为每个项创建了一个Task,因为它需要在数据库中发送http请求和CRUD操作。这就是异步任务的原因。

您可以在并行运行作业时返回新列表。这可以通过首先生成所有任务,然后等待所有任务来完成。我肯定会这样建议,因为它对于正在运行的重复作业来说简单有效。

以下是此方法的实现(未经测试):

def do_job(items) do
  items
  |> Enum.map(fn(a) ->
    Task.async(fn ->
      case external_request(a) do
        {:terminate, data} ->
          Repo.update(....)
          [] # remove this item from list
        {:continue, data} ->
          Repo.update(....)
          [a] # keep this item in list
      end
    end)
  end)
  |> Enum.flat_map(&Task.await/1)
end

do_job现在将获取一个项目列表,并将所有项目并行传递给external_request,然后等待所有项目都返回,并从列表中删除所有项目{:terminate, _}案例。

您可以将handle_info实施与以前保持一致。