defmodule Klaviyo do
alias Klaviyo.HTTP
alias Klaviyo.Opts
alias Klaviyo.Request
alias Klaviyo.RequestOperation
alias Klaviyo.Response
@type headers_t ::
[{String.t(), String.t()}]
@type method_t ::
:delete | :get | :head | :patch | :post | :put
@type response_t ::
{:ok, Response.t()} | {:error, Response.t() | any}
@type status_code_t ::
pos_integer
@doc """
Send an HTTP request.
"""
@spec send(
RequestOperation.t(),
keyword
) :: response_t
def send(operation, opts) do
opts = Opts.new(opts)
request = Request.new(operation, opts)
do_send(request, opts)
end
defp do_send(request, opts) do
case opts.client.send(request, opts) do
{:ok, %HTTP.Response{status_code: status_code} = response}
when status_code >= 500 ->
maybe_retry(Response.new(response, opts), request, opts)
{:ok, %HTTP.Response{status_code: status_code} = response}
when status_code >= 400 ->
{:error, Response.new(response, opts)}
{:ok, %HTTP.Response{status_code: status_code} = response}
when status_code >= 200 ->
{:ok, Response.new(response, opts)}
result ->
maybe_retry(result, request, opts)
end
end
defp maybe_retry(result, request, opts) do
if opts.retry do
do_retry(result, request, opts)
else
{:error, result}
end
end
defp do_retry(result, request, opts) do
attempt = Map.get(request.private, :attempt, 1)
max_attempts = Keyword.get(opts.retry_opts, :max_attempts, 3)
if max_attempts >= attempt do
seconds_to_wait = opts.retry.wait_for(request, opts)
:timer.sleep(seconds_to_wait)
request
|> Map.put(:private, Map.put(request.private, :attempt, attempt + 1))
|> do_send(opts)
else
{:error, result}
end
end
end