Problem: I am trying to make an HTTP request per second. I have written a gen server and starting it using DynamicSupervisor. But now I am self-invoking it and it’s not being invoked per second but wait for the methods to be completed in between the call. My only use case is to send each request per second and capture the time when it sent and also the response. I am not bothered by the time it will take to complete. my use is only to send a request per second and move on, to next second.
this is my genserver.
defmodule Recording.Worker do
use GenServer
require Logger
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(state.sleep)
{:ok, state}
end
def handle_info(:jpeg_fetch, state) do
{for_jpeg_bank, running} =
make_jpeg_request(state.camera)
|> running_map()
IO.inspect("request")
IO.inspect(DateTime.utc_now())
put_it_in_jpeg_bank(for_jpeg_bank, state.camera.name)
schedule_fetch_call(state.sleep)
{:noreply, Map.put(state, :running, running)}
end
def get_state(pid) do
GenServer.call(pid, :get)
end
def handle_call(:get, _from, state),
do: {:reply, state, state}
defp schedule_fetch_call(sleep),
do: Process.send_after(self(), :jpeg_fetch, sleep)
defp make_jpeg_request(camera) do
headers = get_request_headers(camera.auth, camera.username, camera.password)
requested_at = DateTime.utc_now()
Everjamer.request(:get, camera.url, headers)
|> get_body_size(requested_at)
end
defp get_body_size({:ok, %Finch.Response{body: body, headers: headers, status: 200}}, requested_at) do
IO.inspect(headers)
{body, "9", requested_at}
end
defp get_body_size(_error, requested_at), do: {:failed, requested_at}
defp running_map({body, file_size, requested_at}),
do:
{%{datetime: requested_at, image: body, file_size: file_size},
%{datetime: requested_at}}
defp running_map({:failed, requested_at}), do: {%{}, %{datetime: requested_at}}
defp get_request_headers("true", username, password),
do: [{"Authorization", "Basic #{Base.encode64("#{username}:#{password}")}"}]
defp get_request_headers(_, _username, _password), do: []
defp put_it_in_jpeg_bank(state, process) do
String.to_atom("storage_#{process}")
|> Process.whereis()
|> JpegBank.add(state)
end
end
GenServer with 1 HTTP request per second
This is related to the above question, So I have posted the link.
I have made such GenServer worker.
this my whole GenServer
defmodule Recording.Worker do
use GenServer
require Logger
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(state.sleep)
{:ok, state}
end
def handle_info(:jpeg_fetch, state) do
{for_jpeg_bank, running} =
make_jpeg_request(state.camera)
|> running_map()
IO.inspect("request")
IO.inspect(DateTime.utc_now())
put_it_in_jpeg_bank(for_jpeg_bank, state.camera.name)
schedule_fetch_call(state.sleep)
{:noreply, Map.put(state, :running, running)}
end
def get_state(pid) do
GenServer.call(pid, :get)
end
def handle_call(:get, _from, state),
do: {:reply, state, state}
defp schedule_fetch_call(sleep),
do: Process.send_after(self(), :jpeg_fetch, sleep)
defp make_jpeg_request(camera) do
headers = get_request_headers(camera.auth, camera.username, camera.password)
requested_at = DateTime.utc_now()
Everjamer.request(:get, camera.url, headers)
|> get_body_size(requested_at)
end
defp get_body_size({:ok, %Finch.Response{body: body, headers: headers, status: 200}}, requested_at) do
{body, "9", requested_at}
end
defp get_body_size(_error, requested_at), do: {:failed, requested_at}
defp running_map({body, file_size, requested_at}),
do:
{%{datetime: requested_at, image: body, file_size: file_size},
%{datetime: requested_at}}
defp running_map({:failed, requested_at}), do: {%{}, %{datetime: requested_at}}
defp get_request_headers("true", username, password),
do: [{"Authorization", "Basic #{Base.encode64("#{username}:#{password}")}"}]
defp get_request_headers(_, _username, _password), do: []
defp put_it_in_jpeg_bank(state, process) do
String.to_atom("storage_#{process}")
|> Process.whereis()
|> JpegBank.add(state)
end
end
I am trying to make an HTTP request per second. even while using GenSever and starting it with a DynamicSupervisor such as
General.Supervisor.start_child(Recording.Worker, %{id: String.to_atom(detailed_camera.name), camera: detailed_camera, sleep: detailed_camera.sleep})
this part
def handle_info(:jpeg_fetch, state) do
{for_jpeg_bank, running} =
make_jpeg_request(state.camera)
|> running_map()
IO.inspect("request")
IO.inspect(DateTime.utc_now())
put_it_in_jpeg_bank(for_jpeg_bank, state.camera.name)
schedule_fetch_call(state.sleep)
{:noreply, Map.put(state, :running, running)}
end
still waiting for the previous request to complete and it becomes (the time request took to get complete) / per request not request per second.
the results of IO.inspect are such as
"request"
~U[2020-12-30 05:27:21.466262Z]
"request"
~U[2020-12-30 05:27:24.184548Z]
"request"
~U[2020-12-30 05:27:26.967173Z]
"request"
~U[2020-12-30 05:27:29.831532Z]
is there any way possible in Elixir that without using spawn, handle_info
just keep running without waiting for the previous request or previous method to complete?
or is this not a GenServer use case? Should I use any other tool such as GenStage or Flow for this?
PS: I am not bothered about how much time the process will take to complete, I am only bothered the time when the request starts, it should start each second. I have tried putting schedule_fetch_call(state.sleep)
in the first line of handle_info
but it wont work either.
I have been juggling around with this problem but I am not getting any solution on this. Is there any way in Elixir to run a method each second?