Current section

Files

Jump to
electric_client lib electric client fetch http.ex
Raw

lib/electric/client/fetch/http.ex

defmodule Electric.Client.Fetch.HTTP do
@moduledoc false
alias Electric.Client.Fetch
alias Electric.Client.ShapeDefinition
@behaviour Electric.Client.Fetch
def fetch(%Fetch.Request{} = request, opts) do
request_opts = Keyword.get(opts, :request, [])
{connect_options, request_opts} = Keyword.pop(request_opts, :connect_options, [])
%{
method: method,
base_url: base_url,
shape: %ShapeDefinition{} = shape
} = request
params = Electric.Client.params(request)
[
method: method,
base_url: base_url,
url: "/v1/shape/#{ShapeDefinition.url_table_name(shape)}",
params: params,
retry_delay: &retry_delay/1,
max_retries: 6,
# finch: Electric.Client.Finch,
# we use long polling with a timeout of 20s so we don't want Req to error before
# Electric has returned something
receive_timeout: 60_000,
connect_options:
Keyword.merge(
[protocols: [:http2]],
connect_options
)
]
|> Keyword.merge(request_opts)
|> Req.new()
|> request()
end
defp request(request) do
request |> Req.request() |> wrap_resp()
end
defp wrap_resp({:ok, %Req.Response{} = resp}) do
%{status: status, headers: headers, body: body} = resp
{:ok, Fetch.Response.decode!(status, headers, body)}
end
defp wrap_resp({:error, _} = error) do
error
end
defp retry_delay(n) do
(Integer.pow(2, n) * 1000 * jitter())
|> min(30_000 * (1 - 0.1 * :rand.uniform()))
|> trunc()
end
defp jitter() do
1 - 0.1 * :rand.uniform()
end
end