我这个简单的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如何处理?
答案 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
实施与以前保持一致。