From 9a6d68021310a75638a664c2f3716e32ed5980df Mon Sep 17 00:00:00 2001 From: Ben Busby Date: Fri, 22 Oct 2021 19:18:33 -0600 Subject: [PATCH] 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. --- lib/privacy_revolver.ex | 18 ------------------ lib/privacy_revolver/application.ex | 3 ++- lib/privacy_revolver/router.ex | 21 ++++++++++++++++++++- 3 files changed, 22 insertions(+), 20 deletions(-) delete mode 100644 lib/privacy_revolver.ex diff --git a/lib/privacy_revolver.ex b/lib/privacy_revolver.ex deleted file mode 100644 index 5de8e06..0000000 --- a/lib/privacy_revolver.ex +++ /dev/null @@ -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 diff --git a/lib/privacy_revolver/application.ex b/lib/privacy_revolver/application.ex index de38e6e..e303646 100644 --- a/lib/privacy_revolver/application.ex +++ b/lib/privacy_revolver/application.ex @@ -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] diff --git a/lib/privacy_revolver/router.ex b/lib/privacy_revolver/router.ex index cf702fe..c2c1c61 100644 --- a/lib/privacy_revolver/router.ex +++ b/lib/privacy_revolver/router.ex @@ -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