sntran / google_maps

Google Maps API written in Elixir
https://hex.pm/packages/google_maps/
MIT License
92 stars 39 forks source link

Exponential Backoff #14

Open sntran opened 6 years ago

sntran commented 6 years ago

Implement Exponential Backoff to conform with Google's best practice:

https://developers.google.com/maps/documentation/directions/web-service-best-practices#exponential-backoff

jowi-dev commented 4 years ago

Is this still open? I could probably tackle it if need be

sntran commented 4 years ago

@jowi-dev I'd love your help on this!

lovebes commented 3 months ago

I asked Perplexiity.ai to code up a sample Elixir using the example Python script in that referenced website:

defmodule Timezone do
  @api_key "YOUR_KEY_HERE"
  @timezone_base_url "https://maps.googleapis.com/maps/api/timezone/json"

  def get_timezone(lat, lng, timestamp) do
    params = URI.encode_query(%{
      "location" => "#{lat},#{lng}",
      "timestamp" => timestamp,
      "key" => @api_key
    })
    url = "#{@timezone_base_url}?#{params}"

    fetch_timezone(url, 0.1, 5)
  end

  defp fetch_timezone(url, current_delay, max_delay) do
    case Req.get(url) do
      {:ok, %Req.Response{status: 200, body: body}} ->
        result = Jason.decode!(body)
        handle_response(result)

      {:ok, %Req.Response{status: status}} when status != 200 ->
        IO.puts("Received non-200 response: #{status}")
        retry_or_fail(url, current_delay, max_delay)

      {:error, %Req.Error{reason: reason}} ->
        IO.puts("HTTP request failed: #{inspect(reason)}")
        retry_or_fail(url, current_delay, max_delay)
    end
  end

  defp handle_response(%{"status" => "OK", "timeZoneId" => time_zone_id}), do: {:ok, time_zone_id}
  defp handle_response(%{"status" => status, "errorMessage" => error_message}) when status != "OK" do
    IO.puts("API error: #{error_message}")
    {:error, error_message}
  end

  defp retry_or_fail(url, current_delay, max_delay) when current_delay > max_delay do
    raise "Too many retry attempts."
  end

  defp retry_or_fail(url, current_delay, max_delay) do
    IO.puts("Waiting #{current_delay} seconds before retrying.")
    :timer.sleep(round(current_delay * 1000))
    fetch_timezone(url, current_delay * 2, max_delay)
  end
end

I'll try to get to use this as a reference to create the PR