Move constants to config, update string formatting

Not sure if this is the Elixir-y way to do this, but seems more logical
than hardcoding values such as redis connection.

Also went through and improved how string formatting was performed
throughout the app. Rather than "combining" <> "strings" this way, I'm
now just doing "#${variable}#{formatting}", which looks a lot cleaner.
This commit is contained in:
Ben Busby 2021-10-22 20:07:07 -06:00
parent 9a6d680213
commit 76faebd234
No known key found for this signature in database
GPG Key ID: 339B7B7EB5333D14
4 changed files with 51 additions and 22 deletions

7
config/config.exs Normal file
View File

@ -0,0 +1,7 @@
import Config
config :privacy_revolver,
redis_conn: "redis://localhost:6379",
fallback_str: "-fallback",
update_file: ".update-results",
services_json: "services.json"

View File

@ -1,4 +1,5 @@
defmodule PrivacyRevolver.Application do
@redis_conn Application.fetch_env!(:privacy_revolver, :redis_conn)
@moduledoc false
use Application
@ -7,7 +8,7 @@ defmodule PrivacyRevolver.Application do
def start(_type, _args) do
children = [
Plug.Cowboy.child_spec(scheme: :http, plug: PrivacyRevolver.Router, options: [port: 4001]),
{Redix, {"redis://localhost:6379", [name: :redix]}}
{Redix, {@redis_conn, [name: :redix]}}
]
opts = [strategy: :one_for_one, name: PrivacyRevolver.Supervisor]

View File

@ -1,9 +1,15 @@
defmodule PrivacyRevolver.Router do
@fallback_str Application.fetch_env!(:privacy_revolver, :fallback_str)
use Plug.Router
plug :match
plug :dispatch
get "/" do
send_resp(conn, 200, "")
end
get "/ping" do
# Useful for app healthcheck
{:ok, resp} = Redix.command(:redix, ["PING"])
@ -11,19 +17,30 @@ defmodule PrivacyRevolver.Router do
end
get "/:service/*glob" do
full_path = "/" <> Enum.join(glob, "/")
{:ok, instances} = Redix.command(:redix, ["LRANGE", service, "0", "-1"])
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
# 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"])
{:ok, result} = Redix.command(
:redix,
["GET", "#{service}#{@fallback_str}"]
)
result
end
# Redirect to the available instance
conn |>
Plug.Conn.resp(:found, "") |>
Plug.Conn.put_resp_header("location", instance <> full_path)
Plug.Conn.put_resp_header(
"location",
"#{instance}/#{path}"
)
end
end

View File

@ -8,6 +8,15 @@ defmodule Service do
end
defmodule Instances do
@fallback_str Application.fetch_env!(:privacy_revolver, :fallback_str)
@update_file Application.fetch_env!(:privacy_revolver, :update_file)
@services_json Application.fetch_env!(:privacy_revolver, :services_json)
def init() do
File.rename(@update_file, "#{@update_file}-prev")
update(@services_json)
end
def request(url) do
case HTTPoison.get(url) do
{:ok, %HTTPoison.Response{status_code: 200}} ->
@ -19,10 +28,6 @@ defmodule Instances do
end
def update(filename) do
{:ok, conn} = Redix.start_link(
"redis://localhost:6379",
name: :redix
)
{:ok, file} = File.read(filename)
{:ok, json} = Poison.decode(file, as: [%Service{}])
@ -32,20 +37,20 @@ defmodule Instances do
request(instance_url <> service.test_url) == :good
end)
add_to_redis(conn, service, result)
add_to_redis(service, result)
log_results(service.type, result)
end
end
def add_to_redis(conn, service, instances) do
def add_to_redis(service, instances) do
# Remove previous list of instances
Redix.command(conn, [
Redix.command(:redix, [
"DEL",
service.type
])
# Update with new list of available instances
Redix.command(conn, [
Redix.command(:redix, [
"LPUSH",
service.type
] ++ instances)
@ -53,26 +58,25 @@ defmodule Instances do
# Set fallback to one of the available instances,
# or the default instance if all are "down"
if Enum.count(instances) > 0 do
Redix.command(conn, [
Redix.command(:redix, [
"SET",
service.type <> "-fallback",
"#{service.type}#{@fallback_str}",
Enum.random(instances)
])
else
Redix.command(conn, [
Redix.command(:redix, [
"SET",
service.type <> "-fallback",
"#{service.type}#{@fallback_str}",
service.fallback
])
end
end
def log_results(service_name, results) do
{:ok, file} = File.open(".update-results", [:append, {:delayed_write, 100, 20}])
IO.write(file, service_name <> ": " <> inspect(results) <> "\n")
{:ok, file} = File.open(@update_file, [:append, {:delayed_write, 100, 20}])
IO.write(file, "#{service_name}: #{inspect(results)}\n")
File.close(file)
end
end
File.rename(".update-results", ".update-results-prev")
Instances.update("services.json")
Instances.init()