1
0
Fork 0
mirror of https://github.com/benbusby/farside.git synced 2025-04-20 10:58:42 +00:00

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 defmodule PrivacyRevolver.Application do
@redis_conn Application.fetch_env!(:privacy_revolver, :redis_conn)
@moduledoc false @moduledoc false
use Application use Application
@ -7,7 +8,7 @@ defmodule PrivacyRevolver.Application do
def start(_type, _args) do def start(_type, _args) do
children = [ 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]}} {Redix, {@redis_conn, [name: :redix]}}
] ]
opts = [strategy: :one_for_one, name: PrivacyRevolver.Supervisor] opts = [strategy: :one_for_one, name: PrivacyRevolver.Supervisor]

View file

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

View file

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