sure
this is on my config file
config :testespay, :blockchain_apis,
instantnodes: %{
url: "https://api1.example.com",
default_tokens: 10,
refresh_time: 50000,
circuit_breaker_threshold: 5
},
quicknode: %{
url: "https://api2.example.com",
default_tokens: 10,
refresh_time: 50000,
circuit_breaker_threshold: 5
},
ankr: %{
url: "https://api2.example.com",
default_tokens: 20,
refresh_time: 50000,
circuit_breaker_threshold: 5
}
and i’m loading into my code
defmodule Testespay.Genservers.ApiLoadBalancerBlockchain do
use GenServer
@my_apis Application.compile_env(:testespay, :blockchain_apis) # Configurado em config.exs
def start_link(opts \\ []) do
GenServer.start_link(__MODULE__, %{}, opts)
end
def init(_) do
:ets.new(:api_states, [:set, :named_table, :public])
registry_apis();
print_all_apis()
pick_api()
{:ok, %{}}
end
# defp schedule_token_refresh, do: Process.send_after(self(), {:refill_tokens, 1000})
defp registry_apis() do
for {api_name, config} <- @my_apis do
:ets.insert(:api_states, {
api_name,
%{
tokens: config[:default_tokens],
refresh_time: config[:refresh_time],
oks: 0,
errors: 0,
last_refresh: System.os_time(:second),
circuit_status: :closed
}
})
end
end
def handle_call(:pick_api, _from, current_state) do
api = pick_api()
{:reply, api, current_state}
end
defp pick_api() do
IO.puts("picking")
api =
:api_states
|> :ets.tab2list()
|> Enum.filter(fn {_name, data} -> available?(data) end)
|> select_api_with_most_tokens()
|> case do
nil -> {:error, :no_apis_available}
{name, _data} -> {:ok, name}
end
IO.puts("final api choose list")
IO.inspect(api)
api
end
defp available?(%{tokens: t, circuit_status: status, errors: e}) do
t > 0 and status == :closed and e < 10
end
def select_api_with_most_tokens(list) do
Enum.reduce(list, nil, fn {name, data}, acc ->
case acc do
nil -> {name, data}
{_, %{tokens: max_tokens}} when data.tokens > max_tokens -> {name, data} ##retorna nome e data
_ -> acc
end
end)
end
def handle_info({:perform_task, api_name, state}, current_state) do
[{^api_name, current_state_map}] = :ets.lookup(:api_states, api_name)
IO.inspect(current_state_map, label: "Current map for #{api_name}")
updated_state = Map.put(current_state_map, :tokens, state.tokens)
:ets.insert(:api_states, {api_name, updated_state})
IO.puts("new tokens for #{api_name} reset to #{state.tokens}")
Process.send_after(self(), {:perform_task, api_name, %{tokens: state.tokens, refresh_time: state.refresh_time}}, state.refresh_time)
{:noreply, current_state}
end
defp print_all_apis() do
:ets.tab2list(:api_states)
|> Enum.each(fn {api_name, state} ->
reduced_state = %{
tokens: state.tokens,
refresh_time: state.refresh_time
}
Process.send_after(self(), {:perform_task, api_name, reduced_state}, 0)
IO.inspect({api_name, state}, label: "API State")
end)
end
end