问题描述
我做了这个genserver
I have made this 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个请求.
I am running it 1 request per second with such a state.
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,这是解决此问题的最合乎逻辑和最理想的方法.
I am using spawn here but I don't want to use spawn, what is the most logical and ideal way to solve this problem.
-
GenServer将在其中每秒发出一个请求.
where GenServer will make a request each second.
也不要等待请求完成,因为请求可能需要一秒钟以上的时间.
Also don't wait for the request to complete, as the request can take more than a second.
在HTTP请求响应的情况下,我还需要执行其他一些操作.
There are a few other certain operations I want to do in case of HTTP request-response.
我不想让genserver精疲力尽并崩溃.但要处理每秒将要发生的请求的背压(由于需求不确定,因此不会进入阶段).
I don't want to make genserver exhausted and crash. but to handle the back pressure of requests, which will be going each second (Not genstage as demand is not certain).
是否可以以这样的方式使用 GenServer
来使其不产生和处理请求就可以运行?任何指导或帮助都会很棒.
Is it possible to use GenServer
in such a way that it can run without spawn and handle requests? any guidance or help would be wonderful.
推荐答案
对于 DynamicSupervisor
.
将工作程序定义为 GenServer
以执行工作.
Define the worker as a GenServer
to perform a work.
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
,也可以对其进行监督.
Now start as many DynamicSupervisor
s, also supervised, as you need.
我相信我已经推荐了我的 Tarearbol
库,该库(除其他所有功能外)使用动态工人管理有点像
I believe I have already recommended my Tarearbol
library that (besides everything else,) simplifies the above with Dynamic Workers Management to somewhat like
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
.
With it, perform/2
will be executed after timeout
option (defaulted to 1 second,) and one might also handle response timeouts with handle_timeout/1
.
示例来自测试可能是寻求灵感.
这篇关于每秒具有1个HTTP请求的GenServer的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持!