feat: Respect Retry-After header on 429 response code (#3943)

* Respect 429 response code instructions

* format

* up

* up

---------

Co-authored-by: Julien <julien@citio.digital>
This commit is contained in:
jlestel
2024-06-07 10:10:35 +02:00
committed by GitHub
parent f34c0876e8
commit b900a98d08
5 changed files with 46 additions and 0 deletions
+1
View File
@@ -55,6 +55,7 @@ config/*.env
.eclipse/ .eclipse/
.elixir_ls/ .elixir_ls/
/.project /.project
.vscode/
# Mac files # Mac files
.DS_Store .DS_Store
+12
View File
@@ -113,6 +113,18 @@ defmodule TeslaApi.Vehicle do
%Tesla.Env{status: 408, body: %{"error" => "vehicle unavailable:" <> _}} = env -> %Tesla.Env{status: 408, body: %{"error" => "vehicle unavailable:" <> _}} = env ->
{:error, %Error{reason: :vehicle_unavailable, env: env}} {:error, %Error{reason: :vehicle_unavailable, env: env}}
%Tesla.Env{status: 429, headers: headers} ->
retry_after =
case Enum.find(headers, fn {key, _value} -> key == "retry-after" end) do
nil ->
"300"
{"retry-after", value} ->
value
end
{:error, %Error{reason: :too_many_request, message: String.to_integer(retry_after)}}
%Tesla.Env{status: 504} = env -> %Tesla.Env{status: 504} = env ->
{:error, %Error{reason: :timeout, env: env}} {:error, %Error{reason: :timeout, env: env}}
+4
View File
@@ -278,6 +278,10 @@ defmodule TeslaMate.Api do
Logger.error("TeslaApi.Error / #{status} #{inspect(body, pretty: true)}") Logger.error("TeslaApi.Error / #{status} #{inspect(body, pretty: true)}")
{:error, reason} {:error, reason}
{:error, %TeslaApi.Error{reason: :too_many_request, message: retry_after}} ->
Logger.warning("TeslaApi.Error / :too_many_request #{retry_after}")
{:error, :too_many_request, retry_after}
{:error, %TeslaApi.Error{reason: reason, message: msg}} -> {:error, %TeslaApi.Error{reason: reason, message: msg}} ->
if is_binary(msg) and msg != "", do: Logger.warning("TeslaApi.Error / #{msg}") if is_binary(msg) and msg != "", do: Logger.warning("TeslaApi.Error / #{msg}")
{:error, reason} {:error, reason}
+6
View File
@@ -386,6 +386,12 @@ defmodule TeslaMate.Vehicles.Vehicle do
{:keep_state, data, {:keep_state, data,
[broadcast_fetch(false), broadcast_summary(), schedule_fetch(30, data)]} [broadcast_fetch(false), broadcast_summary(), schedule_fetch(30, data)]}
{:error, :too_many_request, retry_after} ->
Logger.error("Too many request / Retry after #{retry_after} seconds", car_id: data.car.id)
{:keep_state, data,
[broadcast_fetch(false), broadcast_summary(), schedule_fetch(retry_after, data)]}
{:error, reason} -> {:error, reason} ->
Logger.error("Error / #{inspect(reason)}", car_id: data.car.id) Logger.error("Error / #{inspect(reason)}", car_id: data.car.id)
+23
View File
@@ -343,6 +343,29 @@ defmodule TeslaMate.ApiTest do
end end
end end
@tag :capture_log
test ":too_many_requests", %{test: name} do
api_error = %TeslaApi.Error{
reason: :too_many_requests,
message: 300
}
vehicle_mock =
{TeslaApi.Vehicle, [],
[
get: fn _auth, _id -> {:error, api_error} end,
get_with_state: fn _auth, _id -> {:error, api_error} end
]}
with_mocks [auth_mock(self()), vehicle_mock] do
:ok = start_api(name, start_auth: false)
assert :ok = Api.sign_in(name, @valid_tokens)
assert {:error, :too_many_requests} = Api.get_vehicle(name, 0)
assert {:error, :too_many_requests} = Api.get_vehicle_with_state(name, 0)
end
end
@tag :capture_log @tag :capture_log
test "other error with Env", %{test: name} do test "other error with Env", %{test: name} do
api_error = %TeslaApi.Error{ api_error = %TeslaApi.Error{