每秒 1 个 HTTP 请求的 GenServer
GenServer with 1 HTTP request per second
我做了这个genserver
defmodule Recorder do
use GenServer
def start_link(args) do
id = Map.get(args, :id)
GenServer.start_link(__MODULE__, args, name: id)
end
def init(state) do
schedule_fetch_call()
{:ok, state}
end
def handle_info(:jpeg_fetch, state) do
spawn(fn ->
IO.inspect("I am being called")
IO.inspect(DateTime.utc_now())
Fincher.request(:get, state.url) |> IO.inspect()
end)
schedule_fetch_call()
{:noreply, Map.put(state, :run, true)}
end
defp schedule_fetch_call do
Process.send_after(self(), :jpeg_fetch, 1000)
end
end
我运行在这种状态下每秒 1 个请求。
defp get_children do
Enum.map([
%{
id: :hdipc,
url: "http://77.66.206.55/jpgmulreq/1/image.jpg?key=1516975535684&lq=1&COUNTER"
}
], fn(camera) ->
Supervisor.child_spec({Recorder, camera}, id: camera.id)
end)
end
在 application.ex
.
我在这里使用spawn但我不想使用spawn,请问解决这个问题最合乎逻辑和理想的方法是什么。
其中 GenServer 每秒都会发出一个请求。
也不要等待请求完成,因为请求可能需要一秒以上。
在 HTTP 请求-响应的情况下,我还想执行其他一些特定操作。
我不想让 genserver 耗尽并崩溃。但要处理每秒都会发生的请求的背压(不是 genstage,因为需求不确定)。
是否可以使用 GenServer
的方式 运行 而无需生成和处理请求?任何指导或帮助都会很棒。
它看起来像是 DynamicSupervisor
的完美用例。
将工人定义为 GenServer
来执行工作。
defmodule Recorder.Worker do
use GenServer
def start_link(opts) do
{id, opts} = Map.pop!(opts, :id)
GenServer.start_link(__MODULE__, opts, name: id)
end
def init(state) do
schedule_fetch_call()
{:ok, state}
end
def handle_info(:jpeg_fetch, state) do
result = Fincher.request(:get, state.url)
schedule_fetch_call()
{:noreply, Map.put(state, :run, {DateTime.utc_now(), result})}
end
defp schedule_fetch_call,
do: Process.send_after(self(), :jpeg_fetch, 1000)
end
然后定义一个DynamicSupervisor
为
defmodule Recorder.Supervisor do
use DynamicSupervisor
def start_link(opts),
do: DynamicSupervisor.start_link(__MODULE__, opts, name: __MODULE__)
def start_child(opts),
do: DynamicSupervisor.start_child(__MODULE__, {Recorder.Worker, opts})
@impl DynamicSupervisor
def init(opts),
do: DynamicSupervisor.init(strategy: :one_for_one, extra_arguments: [opts])
end
现在根据需要开始尽可能多的 DynamicSupervisor
s,也受到监督。
我相信我已经推荐了我的 Tarearbol
库,它(除其他外)将上面的 Dynamic Workers Management 简化为有点像
defmodule Recorder.Worker do
use Tarearbol.DynamicManager
def children_specs do
Enum.into([%{id: :hdipc, url: "..."}], %{}, &{&1.id, &1})
end
def perform(_id, state) do
result = Fincher.request(:get, state.url)
{:noreply, Map.put(state, :run, {DateTime.utc_now(), result})}
end
end
有了它,perform/2
将在 timeout
选项(默认为 1 秒)之后执行,并且还可以使用 handle_timeout/1
.
处理响应超时
示例 from tests 可能会受到启发。
我做了这个genserver
defmodule Recorder do
use GenServer
def start_link(args) do
id = Map.get(args, :id)
GenServer.start_link(__MODULE__, args, name: id)
end
def init(state) do
schedule_fetch_call()
{:ok, state}
end
def handle_info(:jpeg_fetch, state) do
spawn(fn ->
IO.inspect("I am being called")
IO.inspect(DateTime.utc_now())
Fincher.request(:get, state.url) |> IO.inspect()
end)
schedule_fetch_call()
{:noreply, Map.put(state, :run, true)}
end
defp schedule_fetch_call do
Process.send_after(self(), :jpeg_fetch, 1000)
end
end
我运行在这种状态下每秒 1 个请求。
defp get_children do
Enum.map([
%{
id: :hdipc,
url: "http://77.66.206.55/jpgmulreq/1/image.jpg?key=1516975535684&lq=1&COUNTER"
}
], fn(camera) ->
Supervisor.child_spec({Recorder, camera}, id: camera.id)
end)
end
在 application.ex
.
我在这里使用spawn但我不想使用spawn,请问解决这个问题最合乎逻辑和理想的方法是什么。
其中 GenServer 每秒都会发出一个请求。
也不要等待请求完成,因为请求可能需要一秒以上。
在 HTTP 请求-响应的情况下,我还想执行其他一些特定操作。
我不想让 genserver 耗尽并崩溃。但要处理每秒都会发生的请求的背压(不是 genstage,因为需求不确定)。
是否可以使用 GenServer
的方式 运行 而无需生成和处理请求?任何指导或帮助都会很棒。
它看起来像是 DynamicSupervisor
的完美用例。
将工人定义为 GenServer
来执行工作。
defmodule Recorder.Worker do
use GenServer
def start_link(opts) do
{id, opts} = Map.pop!(opts, :id)
GenServer.start_link(__MODULE__, opts, name: id)
end
def init(state) do
schedule_fetch_call()
{:ok, state}
end
def handle_info(:jpeg_fetch, state) do
result = Fincher.request(:get, state.url)
schedule_fetch_call()
{:noreply, Map.put(state, :run, {DateTime.utc_now(), result})}
end
defp schedule_fetch_call,
do: Process.send_after(self(), :jpeg_fetch, 1000)
end
然后定义一个DynamicSupervisor
为
defmodule Recorder.Supervisor do
use DynamicSupervisor
def start_link(opts),
do: DynamicSupervisor.start_link(__MODULE__, opts, name: __MODULE__)
def start_child(opts),
do: DynamicSupervisor.start_child(__MODULE__, {Recorder.Worker, opts})
@impl DynamicSupervisor
def init(opts),
do: DynamicSupervisor.init(strategy: :one_for_one, extra_arguments: [opts])
end
现在根据需要开始尽可能多的 DynamicSupervisor
s,也受到监督。
我相信我已经推荐了我的 Tarearbol
库,它(除其他外)将上面的 Dynamic Workers Management 简化为有点像
defmodule Recorder.Worker do
use Tarearbol.DynamicManager
def children_specs do
Enum.into([%{id: :hdipc, url: "..."}], %{}, &{&1.id, &1})
end
def perform(_id, state) do
result = Fincher.request(:get, state.url)
{:noreply, Map.put(state, :run, {DateTime.utc_now(), result})}
end
end
有了它,perform/2
将在 timeout
选项(默认为 1 秒)之后执行,并且还可以使用 handle_timeout/1
.
示例 from tests 可能会受到启发。