mirror of
https://github.com/benbusby/farside.git
synced 2025-06-08 10:26:36 +00:00
refactor, remove unnecessary dependencies
This commit is contained in:
parent
8fbe016cdb
commit
a70cb19051
12 changed files with 394 additions and 301 deletions
135
lib/farside.ex
135
lib/farside.ex
|
@ -1,7 +1,5 @@
|
|||
defmodule Farside do
|
||||
@service_prefix Application.fetch_env!(:farside, :service_prefix)
|
||||
@fallback_suffix Application.fetch_env!(:farside, :fallback_suffix)
|
||||
@previous_suffix Application.fetch_env!(:farside, :previous_suffix)
|
||||
|
||||
# Define relation between available services and their parent service.
|
||||
# This enables Farside to redirect with links such as:
|
||||
|
@ -34,16 +32,14 @@ defmodule Farside do
|
|||
@quora_regex => ["querte"]
|
||||
}
|
||||
|
||||
def get_services_map do
|
||||
{:ok, service_list} = Redix.command(:redix, ["KEYS", "#{@service_prefix}*"])
|
||||
alias Farside.LastUpdated
|
||||
|
||||
# Match service name to list of available instances
|
||||
Enum.reduce(service_list, %{}, fn service, acc ->
|
||||
{:ok, instance_list} =
|
||||
Redix.command(
|
||||
:redix,
|
||||
["LRANGE", service, "0", "-1"]
|
||||
)
|
||||
def get_services_map do
|
||||
Farside.Server.Supervisor.list()
|
||||
|> Enum.reduce(%{}, fn service, acc ->
|
||||
data = :ets.lookup(String.to_atom(service), :data)
|
||||
|
||||
{_, data} = List.first(data)
|
||||
|
||||
Map.put(
|
||||
acc,
|
||||
|
@ -52,125 +48,20 @@ defmodule Farside do
|
|||
@service_prefix,
|
||||
""
|
||||
),
|
||||
instance_list
|
||||
data.instances
|
||||
)
|
||||
end)
|
||||
end
|
||||
|
||||
def get_service(service) do
|
||||
# Check if service has an entry in Redis, otherwise try to
|
||||
# match against available parent services
|
||||
service_name = cond do
|
||||
!check_service(service) ->
|
||||
Enum.find_value(
|
||||
@parent_services,
|
||||
fn {k, v} ->
|
||||
String.match?(service, k) && Enum.random(v)
|
||||
end)
|
||||
true ->
|
||||
service
|
||||
end
|
||||
def get_service(service \\ "libreddit") do
|
||||
data = :ets.lookup(String.to_atom(service), :data)
|
||||
|
||||
service_name
|
||||
end
|
||||
{_, service} = List.first(data)
|
||||
|
||||
def check_service(service) do
|
||||
# Checks to see if a specific service has instances available
|
||||
# in redis
|
||||
{:ok, instances} =
|
||||
Redix.command(
|
||||
:redix,
|
||||
[
|
||||
"LRANGE",
|
||||
"#{@service_prefix}#{service}",
|
||||
"0",
|
||||
"-1"
|
||||
]
|
||||
)
|
||||
|
||||
Enum.count(instances) > 0
|
||||
end
|
||||
|
||||
def last_instance(service) do
|
||||
# Fetches the last selected instance for a particular service
|
||||
{:ok, previous} =
|
||||
Redix.command(
|
||||
:redix,
|
||||
["GET", "#{service}#{@previous_suffix}"]
|
||||
)
|
||||
previous
|
||||
end
|
||||
|
||||
def pick_instance(service) do
|
||||
{:ok, instances} =
|
||||
Redix.command(
|
||||
:redix,
|
||||
[
|
||||
"LRANGE",
|
||||
"#{@service_prefix}#{service}",
|
||||
"0",
|
||||
"-1"
|
||||
]
|
||||
)
|
||||
|
||||
# Either pick a random available instance,
|
||||
# or fall back to the default one
|
||||
instance =
|
||||
if Enum.count(instances) > 0 do
|
||||
if Enum.count(instances) == 1 do
|
||||
# If there's only one instance, just return that one...
|
||||
List.first(instances)
|
||||
else
|
||||
# ...otherwise pick a random one from the list, ensuring
|
||||
# that the same instance is never picked twice in a row.
|
||||
instance =
|
||||
Enum.filter(instances, &(&1 != last_instance(service)))
|
||||
|> Enum.random()
|
||||
|
||||
Redix.command(
|
||||
:redix,
|
||||
["SET", "#{service}#{@previous_suffix}", instance]
|
||||
)
|
||||
|
||||
instance
|
||||
end
|
||||
else
|
||||
{:ok, result} =
|
||||
Redix.command(
|
||||
:redix,
|
||||
["GET", "#{service}#{@fallback_suffix}"]
|
||||
)
|
||||
|
||||
result
|
||||
end
|
||||
instance
|
||||
end
|
||||
|
||||
def amend_instance(instance, service, path) do
|
||||
cond do
|
||||
String.match?(service, @instagram_regex) ->
|
||||
# Bibliogram doesn't have a 1:1 matching to Instagram URLs for users,
|
||||
# so a "/u" is appended if the requested path doesn't explicitly include
|
||||
# "/p" for a post or an empty path for the home page.
|
||||
if String.length(path) > 0 and
|
||||
!String.starts_with?(path, "p/") and
|
||||
!String.starts_with?(path, "u/") do
|
||||
"#{instance}/u"
|
||||
else
|
||||
instance
|
||||
end
|
||||
true ->
|
||||
instance
|
||||
end
|
||||
Enum.random(service.instances)
|
||||
end
|
||||
|
||||
def get_last_updated do
|
||||
{:ok, last_updated} =
|
||||
Redix.command(
|
||||
:redix,
|
||||
["GET", "last_updated"]
|
||||
)
|
||||
|
||||
last_updated
|
||||
LastUpdated.value()
|
||||
end
|
||||
end
|
||||
|
|
|
@ -1,32 +1,89 @@
|
|||
defmodule Farside.Application do
|
||||
#@farside_port Application.fetch_env!(:farside, :port)
|
||||
#@redis_conn Application.fetch_env!(:farside, :redis_conn)
|
||||
# @farside_port Application.fetch_env!(:farside, :port)
|
||||
# @redis_conn Application.fetch_env!(:farside, :redis_conn)
|
||||
@moduledoc false
|
||||
|
||||
use Application
|
||||
|
||||
require Logger
|
||||
|
||||
alias Farside.LastUpdated
|
||||
|
||||
@impl true
|
||||
def start(_type, _args) do
|
||||
redis_conn = Application.fetch_env!(:farside, :redis_conn)
|
||||
farside_port = Application.fetch_env!(:farside, :port)
|
||||
IO.puts "Runing on http://localhost:#{farside_port}"
|
||||
IO.puts "Redis conn: #{redis_conn}"
|
||||
port = Application.fetch_env!(:farside, :port)
|
||||
|
||||
children = [
|
||||
Plug.Cowboy.child_spec(
|
||||
scheme: :http,
|
||||
plug: Farside.Router,
|
||||
options: [
|
||||
port: String.to_integer(farside_port)
|
||||
]
|
||||
),
|
||||
{PlugAttack.Storage.Ets, name: Farside.Throttle.Storage, clean_period: 60_000},
|
||||
{Redix, {redis_conn, [name: :redix]}},
|
||||
Farside.Scheduler,
|
||||
Farside.Server
|
||||
]
|
||||
Logger.info("Running on http://localhost:#{port}")
|
||||
|
||||
sync =
|
||||
case is_nil(System.get_env("FARSIDE_TEST")) do
|
||||
true ->
|
||||
Logger.info("Skipping sync job setup...")
|
||||
[]
|
||||
|
||||
false ->
|
||||
{Farside.Sync, []}
|
||||
end
|
||||
|
||||
children =
|
||||
[
|
||||
Plug.Cowboy.child_spec(
|
||||
scheme: :http,
|
||||
plug: Farside.Router,
|
||||
options: [
|
||||
port: String.to_integer(port)
|
||||
]
|
||||
),
|
||||
{LastUpdated, DateTime.utc_now()},
|
||||
{PlugAttack.Storage.Ets, name: Farside.Throttle.Storage, clean_period: 60_000},
|
||||
{DynamicSupervisor, strategy: :one_for_one, name: :server_supervisor},
|
||||
{Registry, keys: :unique, name: :servers}
|
||||
] ++ sync
|
||||
|
||||
opts = [strategy: :one_for_one, name: Farside.Supervisor]
|
||||
|
||||
Supervisor.start_link(children, opts)
|
||||
|> load()
|
||||
end
|
||||
|
||||
def load(response) do
|
||||
services_json = Application.fetch_env!(:farside, :services_json)
|
||||
queries = Application.fetch_env!(:farside, :queries)
|
||||
|
||||
{:ok, file} = File.read(services_json)
|
||||
{:ok, json} = Jason.decode(file)
|
||||
|
||||
for service_json <- json do
|
||||
service_atom =
|
||||
for {key, val} <- service_json, into: %{} do
|
||||
{String.to_existing_atom(key), val}
|
||||
end
|
||||
|
||||
service = struct(%Service{}, service_atom)
|
||||
|
||||
Logger.info("Service: #{service.type}")
|
||||
|
||||
instances =
|
||||
Enum.filter(service.instances, fn instance_url ->
|
||||
request_url =
|
||||
instance_url <>
|
||||
EEx.eval_string(
|
||||
service.test_url,
|
||||
query: Enum.random(queries)
|
||||
)
|
||||
|
||||
Logger.info("Testing: #{request_url}")
|
||||
|
||||
Farside.Http.request(request_url) == :good
|
||||
end)
|
||||
|
||||
service = %{service | instances: instances}
|
||||
|
||||
Farside.Server.Supervisor.start(service)
|
||||
end
|
||||
|
||||
LastUpdated.value(DateTime.utc_now())
|
||||
|
||||
response
|
||||
end
|
||||
end
|
||||
|
|
26
lib/farside/http.ex
Normal file
26
lib/farside/http.ex
Normal file
|
@ -0,0 +1,26 @@
|
|||
defmodule Farside.Http do
|
||||
require Logger
|
||||
|
||||
@headers Application.fetch_env!(:farside, :headers)
|
||||
|
||||
def request(url) do
|
||||
cond do
|
||||
System.get_env("FARSIDE_TEST") ->
|
||||
:good
|
||||
|
||||
true ->
|
||||
HTTPoison.get(url, @headers)
|
||||
|> then(&elem(&1, 1))
|
||||
|> Map.get(:status_code)
|
||||
|> case do
|
||||
n when n < 400 ->
|
||||
Logger.info("Response: [#{n}]")
|
||||
:good
|
||||
|
||||
n ->
|
||||
Logger.error("Response: [#{n}]")
|
||||
:bad
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
|
@ -1,115 +1,18 @@
|
|||
defmodule Farside.Instances do
|
||||
@fallback_suffix Application.fetch_env!(:farside, :fallback_suffix)
|
||||
@update_file Application.fetch_env!(:farside, :update_file)
|
||||
@service_prefix Application.fetch_env!(:farside, :service_prefix)
|
||||
@headers Application.fetch_env!(:farside, :headers)
|
||||
@queries Application.fetch_env!(:farside, :queries)
|
||||
@debug_header "======== "
|
||||
@debug_spacer " "
|
||||
alias Farside.LastUpdated
|
||||
|
||||
def sync() do
|
||||
File.rename(@update_file, "#{@update_file}-prev")
|
||||
update()
|
||||
|
||||
# Add UTC time of last update
|
||||
Redix.command(:redix, [
|
||||
"SET",
|
||||
"last_updated",
|
||||
Calendar.strftime(DateTime.utc_now(), "%c")
|
||||
])
|
||||
end
|
||||
update_file = Application.fetch_env!(:farside, :update_file)
|
||||
|
||||
def request(url) do
|
||||
cond do
|
||||
System.get_env("FARSIDE_TEST") ->
|
||||
:good
|
||||
File.rm("#{update_file}-prev")
|
||||
|
||||
true ->
|
||||
HTTPoison.get(url, @headers)
|
||||
|> then(&elem(&1, 1))
|
||||
|> Map.get(:status_code)
|
||||
|> case do
|
||||
n when n < 400 ->
|
||||
IO.puts("#{@debug_spacer}✓ [#{n}]")
|
||||
:good
|
||||
File.rename(update_file, "#{update_file}-prev")
|
||||
|
||||
n ->
|
||||
IO.puts("#{@debug_spacer}x [#{(n && n) || "error"}]")
|
||||
:bad
|
||||
end
|
||||
end
|
||||
end
|
||||
File.write(update_file, "")
|
||||
|
||||
def update() do
|
||||
services_json = Application.fetch_env!(:farside, :services_json)
|
||||
{:ok, file} = File.read(services_json)
|
||||
{:ok, json} = Jason.decode(file)
|
||||
LastUpdated.value(DateTime.utc_now())
|
||||
|
||||
# Loop through all instances and check each for availability
|
||||
for service_json <- json do
|
||||
service_atom = for {key, val} <- service_json, into: %{} do
|
||||
{String.to_existing_atom(key), val}
|
||||
end
|
||||
|
||||
service = struct(%Service{}, service_atom)
|
||||
|
||||
IO.puts("#{@debug_header}#{service.type}")
|
||||
|
||||
result =
|
||||
Enum.filter(service.instances, fn instance_url ->
|
||||
request_url =
|
||||
instance_url <>
|
||||
EEx.eval_string(
|
||||
service.test_url,
|
||||
query: Enum.random(@queries)
|
||||
)
|
||||
|
||||
IO.puts("#{@debug_spacer}#{request_url}")
|
||||
|
||||
request(request_url) == :good
|
||||
end)
|
||||
|
||||
add_to_redis(service, result)
|
||||
log_results(service.type, result)
|
||||
end
|
||||
end
|
||||
|
||||
def add_to_redis(service, instances) do
|
||||
# Remove previous list of instances
|
||||
Redix.command(:redix, [
|
||||
"DEL",
|
||||
"#{@service_prefix}#{service.type}"
|
||||
])
|
||||
|
||||
# Update with new list of available instances
|
||||
Redix.command(
|
||||
:redix,
|
||||
[
|
||||
"LPUSH",
|
||||
"#{@service_prefix}#{service.type}"
|
||||
] ++ instances
|
||||
)
|
||||
|
||||
# Set fallback to one of the available instances,
|
||||
# or the default instance if all are "down"
|
||||
if Enum.count(instances) > 0 do
|
||||
Redix.command(:redix, [
|
||||
"SET",
|
||||
"#{service.type}#{@fallback_suffix}",
|
||||
Enum.random(instances)
|
||||
])
|
||||
else
|
||||
Redix.command(:redix, [
|
||||
"SET",
|
||||
"#{service.type}#{@fallback_suffix}",
|
||||
service.fallback
|
||||
])
|
||||
end
|
||||
end
|
||||
|
||||
def log_results(service_name, results) do
|
||||
{:ok, file} = File.open(@update_file, [:append, {:delayed_write, 100, 20}])
|
||||
IO.write(file, "#{service_name}: #{inspect(results)}\n")
|
||||
File.close(file)
|
||||
Farside.Server.Supervisor.update_children()
|
||||
end
|
||||
end
|
||||
|
|
|
@ -29,12 +29,6 @@ defmodule Farside.Router do
|
|||
send_resp(conn, 200, resp)
|
||||
end
|
||||
|
||||
get "/ping" do
|
||||
# Useful for app healthcheck
|
||||
{:ok, resp} = Redix.command(:redix, ["PING"])
|
||||
send_resp(conn, 200, resp)
|
||||
end
|
||||
|
||||
get "/_/:service/*glob" do
|
||||
r_path = String.slice(conn.request_path, 2..-1)
|
||||
|
||||
|
@ -48,37 +42,45 @@ defmodule Farside.Router do
|
|||
end
|
||||
|
||||
get "/:service/*glob" do
|
||||
service_name = cond do
|
||||
service =~ "http" ->
|
||||
List.first(glob)
|
||||
true ->
|
||||
service
|
||||
end
|
||||
service_name =
|
||||
cond do
|
||||
service =~ "http" ->
|
||||
List.first(glob)
|
||||
|
||||
path = cond do
|
||||
service_name != service ->
|
||||
Enum.join(Enum.slice(glob, 1..-1), "/")
|
||||
true ->
|
||||
Enum.join(glob, "/")
|
||||
end
|
||||
true ->
|
||||
service
|
||||
end
|
||||
|
||||
instance = cond do
|
||||
conn.assigns[:throttle] != nil ->
|
||||
Farside.get_service(service_name)
|
||||
|> Farside.last_instance
|
||||
|> Farside.amend_instance(service_name, path)
|
||||
true ->
|
||||
Farside.get_service(service_name)
|
||||
|> Farside.pick_instance
|
||||
|> Farside.amend_instance(service_name, path)
|
||||
end
|
||||
path =
|
||||
cond do
|
||||
service_name != service ->
|
||||
Enum.join(Enum.slice(glob, 1..-1), "/")
|
||||
|
||||
# Redirect to the available instance
|
||||
conn
|
||||
|> Plug.Conn.resp(:found, "")
|
||||
|> Plug.Conn.put_resp_header(
|
||||
"location",
|
||||
"#{instance}/#{path}#{get_query_params(conn)}"
|
||||
)
|
||||
true ->
|
||||
Enum.join(glob, "/")
|
||||
end
|
||||
|
||||
case service_name do
|
||||
"favicon.ico" ->
|
||||
conn |> Plug.Conn.resp(:not_found, "")
|
||||
|
||||
_ ->
|
||||
instance =
|
||||
cond do
|
||||
conn.assigns[:throttle] != nil ->
|
||||
Farside.get_service(service_name)
|
||||
|
||||
true ->
|
||||
Farside.get_service(service_name)
|
||||
end
|
||||
|
||||
# Redirect to the available instance
|
||||
conn
|
||||
|> Plug.Conn.resp(:found, "")
|
||||
|> Plug.Conn.put_resp_header(
|
||||
"location",
|
||||
"#{instance}/#{path}#{get_query_params(conn)}"
|
||||
)
|
||||
end
|
||||
end
|
||||
end
|
||||
|
|
|
@ -1,3 +0,0 @@
|
|||
defmodule Farside.Scheduler do
|
||||
use Quantum, otp_app: :farside
|
||||
end
|
|
@ -1,22 +1,107 @@
|
|||
defmodule Farside.Server do
|
||||
defmodule Farside.Instance.Server do
|
||||
use GenServer
|
||||
import Crontab.CronExpression
|
||||
|
||||
require Logger
|
||||
|
||||
@registry_name :servers
|
||||
|
||||
def child_spec(args) do
|
||||
%{
|
||||
id: __MODULE__,
|
||||
start: {__MODULE__, :start_link, [args]},
|
||||
type: :worker
|
||||
}
|
||||
end
|
||||
|
||||
def init(init_arg) do
|
||||
{:ok, init_arg}
|
||||
ref =
|
||||
:ets.new(String.to_atom(init_arg.type), [
|
||||
:set,
|
||||
:named_table,
|
||||
:public,
|
||||
read_concurrency: true,
|
||||
write_concurrency: true
|
||||
])
|
||||
|
||||
:ets.insert(ref, {:data, init_arg})
|
||||
|
||||
{:ok, %{type: init_arg.type, ref: ref}}
|
||||
end
|
||||
|
||||
def start_link(arg) do
|
||||
if System.get_env("FARSIDE_TEST") do
|
||||
IO.puts("Skipping sync job setup...")
|
||||
else
|
||||
Farside.Scheduler.new_job()
|
||||
|> Quantum.Job.set_name(:sync)
|
||||
|> Quantum.Job.set_schedule(~e[*/5 * * * *])
|
||||
|> Quantum.Job.set_task(fn -> Farside.Instances.sync() end)
|
||||
|> Farside.Scheduler.add_job()
|
||||
end
|
||||
name = via_tuple(arg.type)
|
||||
GenServer.start_link(__MODULE__, arg, name: name)
|
||||
end
|
||||
|
||||
GenServer.start_link(__MODULE__, arg)
|
||||
def shutdown() do
|
||||
GenServer.call(__MODULE__, :shutdown)
|
||||
end
|
||||
|
||||
def handle_call(
|
||||
:shutdown,
|
||||
_from,
|
||||
state
|
||||
) do
|
||||
{:stop, {:ok, "Normal Shutdown"}, state}
|
||||
end
|
||||
|
||||
def handle_cast(
|
||||
:shutdown,
|
||||
state
|
||||
) do
|
||||
{:stop, :normal, state}
|
||||
end
|
||||
|
||||
def handle_cast(
|
||||
:update,
|
||||
state
|
||||
) do
|
||||
service = :ets.lookup(String.to_atom(state.type), :data)
|
||||
|
||||
{_, service} = List.first(service)
|
||||
|
||||
queries = Application.fetch_env!(:farside, :queries)
|
||||
|
||||
instances =
|
||||
Enum.filter(service.instances, fn instance_url ->
|
||||
request_url =
|
||||
instance_url <>
|
||||
EEx.eval_string(
|
||||
service.test_url,
|
||||
query: Enum.random(queries)
|
||||
)
|
||||
|
||||
Logger.info("Testing: #{request_url}")
|
||||
|
||||
Farside.Http.request(request_url) == :good
|
||||
end)
|
||||
|
||||
values = %{service | instances: instances}
|
||||
|
||||
:ets.delete_all_objects(String.to_atom(state.type))
|
||||
|
||||
:ets.insert(state.ref, {:data, values})
|
||||
|
||||
update_file = Application.fetch_env!(:farside, :update_file)
|
||||
|
||||
File.write(update_file, values.fallback)
|
||||
|
||||
{:noreply, state}
|
||||
end
|
||||
|
||||
@doc false
|
||||
def via_tuple(data, registry \\ @registry_name) do
|
||||
{:via, Registry, {registry, data}}
|
||||
end
|
||||
|
||||
@impl true
|
||||
def handle_info({:DOWN, ref, :process, _pid, _reason}, {names, refs}) do
|
||||
:ets.delete(names)
|
||||
{:noreply, {names, refs}}
|
||||
end
|
||||
|
||||
@impl true
|
||||
def handle_info(_msg, state) do
|
||||
{:noreply, state}
|
||||
end
|
||||
end
|
||||
|
|
93
lib/farside/server.supervisor.ex
Normal file
93
lib/farside/server.supervisor.ex
Normal file
|
@ -0,0 +1,93 @@
|
|||
defmodule Farside.Server.Supervisor do
|
||||
use DynamicSupervisor
|
||||
|
||||
alias __MODULE__, as: SUPERVISOR
|
||||
alias Farside.Instance.Server, as: SERVER
|
||||
|
||||
@name :server_supervisor
|
||||
@registry_name :servers
|
||||
|
||||
def child_spec() do
|
||||
%{
|
||||
id: __MODULE__,
|
||||
start: {__MODULE__, :start_link, []},
|
||||
type: :supervisor
|
||||
}
|
||||
end
|
||||
|
||||
def start_link(init_arg) do
|
||||
DynamicSupervisor.start_link(__MODULE__, init_arg, name: @name)
|
||||
end
|
||||
|
||||
def start_link() do
|
||||
DynamicSupervisor.start_link(__MODULE__, [], name: @name)
|
||||
end
|
||||
|
||||
@impl true
|
||||
def init(_) do
|
||||
DynamicSupervisor.init(strategy: :one_for_one)
|
||||
end
|
||||
|
||||
def start(opts \\ %{}) do
|
||||
child_spec = {Farside.Instance.Server, opts}
|
||||
|
||||
DynamicSupervisor.start_child(@name, child_spec)
|
||||
end
|
||||
|
||||
def stop(id) do
|
||||
case Registry.lookup(@registry_name, id) do
|
||||
[] ->
|
||||
:ok
|
||||
|
||||
[{pid, _}] ->
|
||||
Process.exit(pid, :shutdown)
|
||||
:ok
|
||||
end
|
||||
end
|
||||
|
||||
def update_children() do
|
||||
list()
|
||||
|> Enum.each(fn x ->
|
||||
Farside.Instance.Server.via_tuple(x)
|
||||
|> GenServer.cast(:update)
|
||||
end)
|
||||
end
|
||||
|
||||
def whereis(id) do
|
||||
case Registry.lookup(@registry_name, id) do
|
||||
[{pid, _}] -> pid
|
||||
[] -> nil
|
||||
end
|
||||
end
|
||||
|
||||
def find_or_create(id) do
|
||||
if process_exists?(id) do
|
||||
{:ok, id}
|
||||
else
|
||||
id |> start
|
||||
end
|
||||
end
|
||||
|
||||
def exists?(id) do
|
||||
case Registry.lookup(@registry_name, id) do
|
||||
[] -> false
|
||||
_ -> true
|
||||
end
|
||||
end
|
||||
|
||||
def list do
|
||||
DynamicSupervisor.which_children(@name)
|
||||
|> Enum.map(fn {_, account_proc_pid, _, _} ->
|
||||
Registry.keys(@registry_name, account_proc_pid)
|
||||
|> List.first()
|
||||
end)
|
||||
|> Enum.sort()
|
||||
end
|
||||
|
||||
def process_exists?(hash) do
|
||||
case Registry.lookup(@registry_name, hash) do
|
||||
[] -> false
|
||||
_ -> true
|
||||
end
|
||||
end
|
||||
end
|
28
lib/farside/sync.ex
Normal file
28
lib/farside/sync.ex
Normal file
|
@ -0,0 +1,28 @@
|
|||
defmodule Farside.Sync do
|
||||
use Task
|
||||
|
||||
def child_spec(args) do
|
||||
%{
|
||||
id: __MODULE__,
|
||||
start: {__MODULE__, :start_link, [args]},
|
||||
type: :worker
|
||||
}
|
||||
end
|
||||
|
||||
def start_link(_arg) do
|
||||
Task.start_link(&poll/0)
|
||||
end
|
||||
|
||||
def poll() do
|
||||
receive do
|
||||
after
|
||||
10_000 ->
|
||||
sync()
|
||||
poll()
|
||||
end
|
||||
end
|
||||
|
||||
defp sync() do
|
||||
Farside.Instances.sync()
|
||||
end
|
||||
end
|
15
lib/farside/updated.ex
Normal file
15
lib/farside/updated.ex
Normal file
|
@ -0,0 +1,15 @@
|
|||
defmodule Farside.LastUpdated do
|
||||
use Agent
|
||||
|
||||
def start_link(initial_value) do
|
||||
Agent.start_link(fn -> initial_value end, name: __MODULE__)
|
||||
end
|
||||
|
||||
def value do
|
||||
Agent.get(__MODULE__, & &1)
|
||||
end
|
||||
|
||||
def value(data) do
|
||||
Agent.update(__MODULE__, & &1)
|
||||
end
|
||||
end
|
Loading…
Add table
Add a link
Reference in a new issue