Route service requests to an available instance

Router has been updated with a basic /:service/*glob endpoint, which
retrieves a list of instances for the requested service and picks a
random one to forward the user to (or falls back to a default instance
if none are found).

Should probably add a check to make sure the requested service exists
first.
This commit is contained in:
Ben Busby 2021-10-22 19:18:33 -06:00
parent 8f762d47fa
commit 9a6d680213
No known key found for this signature in database
GPG key ID: 339B7B7EB5333D14
3 changed files with 22 additions and 20 deletions

View file

@ -1,18 +0,0 @@
defmodule PrivacyRevolver do
@moduledoc """
Documentation for `PrivacyRevolver`.
"""
@doc """
Hello world.
## Examples
iex> PrivacyRevolver.hello()
:world
"""
def hello do
:world
end
end

View file

@ -6,7 +6,8 @@ defmodule PrivacyRevolver.Application do
@impl true
def start(_type, _args) do
children = [
Plug.Cowboy.child_spec(scheme: :http, plug: PrivacyRevolver.Router, options: [port: 4001])
Plug.Cowboy.child_spec(scheme: :http, plug: PrivacyRevolver.Router, options: [port: 4001]),
{Redix, {"redis://localhost:6379", [name: :redix]}}
]
opts = [strategy: :one_for_one, name: PrivacyRevolver.Supervisor]

View file

@ -5,6 +5,25 @@ defmodule PrivacyRevolver.Router do
plug :dispatch
get "/ping" do
send_resp(conn, 200, "pong")
# Useful for app healthcheck
{:ok, resp} = Redix.command(:redix, ["PING"])
send_resp(conn, 200, resp)
end
get "/:service/*glob" do
full_path = "/" <> Enum.join(glob, "/")
{:ok, instances} = Redix.command(:redix, ["LRANGE", service, "0", "-1"])
# Either pick a random available instance, or fall back to the default one
instance = if Enum.count(instances) > 0 do
Enum.random(instances)
else
Redix.command(:redix, ["GET", service <> "-fallback"])
end
# Redirect to the available instance
conn |>
Plug.Conn.resp(:found, "") |>
Plug.Conn.put_resp_header("location", instance <> full_path)
end
end