2023-06-27 19:28:00 +00:00
|
|
|
defmodule Prymn.Agents.Connection do
|
|
|
|
@moduledoc false
|
|
|
|
|
2023-08-19 18:14:07 +00:00
|
|
|
@timer_interval 120_000
|
2023-07-09 16:41:41 +00:00
|
|
|
|
2023-08-19 18:14:07 +00:00
|
|
|
defstruct [:channel, :timer_ref]
|
2023-06-27 19:28:00 +00:00
|
|
|
|
|
|
|
require Logger
|
2023-07-26 19:41:52 +00:00
|
|
|
|
|
|
|
use GenServer, restart: :transient
|
2023-06-27 19:28:00 +00:00
|
|
|
|
|
|
|
@spec start_link(String.t()) :: GenServer.on_start()
|
|
|
|
def start_link(addr) do
|
|
|
|
GenServer.start_link(__MODULE__, addr, name: via(addr))
|
|
|
|
end
|
|
|
|
|
2023-08-19 18:14:07 +00:00
|
|
|
@spec keep_alive(pid) :: :ok
|
|
|
|
def keep_alive(pid) do
|
|
|
|
GenServer.cast(pid, :reset_timer)
|
2023-06-27 19:28:00 +00:00
|
|
|
end
|
|
|
|
|
2023-08-19 18:14:07 +00:00
|
|
|
@impl true
|
|
|
|
def init(host) do
|
|
|
|
Process.flag(:trap_exit, true)
|
|
|
|
{:ok, %__MODULE__{}, {:continue, host}}
|
2023-06-27 19:28:00 +00:00
|
|
|
end
|
|
|
|
|
|
|
|
@impl true
|
2023-08-19 18:14:07 +00:00
|
|
|
def handle_continue(host, state) when is_binary(host) do
|
|
|
|
case GRPC.Stub.connect(host, 50012, []) do
|
2023-06-27 19:28:00 +00:00
|
|
|
{:ok, channel} ->
|
2023-08-19 18:14:07 +00:00
|
|
|
GenServer.cast(self(), :reset_timer)
|
|
|
|
{:noreply, %__MODULE__{channel: channel}, {:continue, :health}}
|
2023-06-27 19:28:00 +00:00
|
|
|
|
|
|
|
{:error, error} ->
|
2023-08-19 18:14:07 +00:00
|
|
|
{:stop, {:error, error}, state}
|
2023-06-27 19:28:00 +00:00
|
|
|
end
|
|
|
|
end
|
|
|
|
|
|
|
|
@impl true
|
2023-08-19 18:14:07 +00:00
|
|
|
def handle_continue(:health, state) do
|
|
|
|
pid = self()
|
|
|
|
|
|
|
|
Task.start_link(fn ->
|
|
|
|
{:ok, stream} = PrymnProto.Prymn.Agent.Stub.health(state.channel, %Google.Protobuf.Empty{})
|
|
|
|
|
|
|
|
stream
|
|
|
|
|> Stream.each(fn health -> send(pid, {:health, health}) end)
|
|
|
|
|> Enum.take_while(fn _ -> true end)
|
|
|
|
end)
|
|
|
|
|
|
|
|
{:noreply, state}
|
2023-06-27 19:28:00 +00:00
|
|
|
end
|
|
|
|
|
|
|
|
@impl true
|
2023-08-19 18:14:07 +00:00
|
|
|
def handle_cast(:reset_timer, state) do
|
|
|
|
if state.timer_ref, do: Process.cancel_timer(state.timer_ref)
|
|
|
|
ref = Process.send_after(self(), :drop_connection, @timer_interval)
|
|
|
|
{:noreply, put_in(state.timer_ref, ref)}
|
2023-06-27 19:28:00 +00:00
|
|
|
end
|
|
|
|
|
|
|
|
@impl true
|
2023-08-19 18:14:07 +00:00
|
|
|
def handle_info(:drop_connection, state) do
|
|
|
|
Logger.debug("shutting down connection with agent host #{inspect(state.channel.host)}")
|
|
|
|
{:stop, :shutdown, state}
|
2023-06-27 19:28:00 +00:00
|
|
|
end
|
|
|
|
|
|
|
|
@impl true
|
2023-08-19 18:14:07 +00:00
|
|
|
def handle_info({:health, health}, state) do
|
|
|
|
IO.inspect(health)
|
|
|
|
{:noreply, state}
|
|
|
|
end
|
|
|
|
|
|
|
|
@impl true
|
|
|
|
def handle_info({:gun_up, _pid, _protocol}, state) do
|
|
|
|
# TODO: If it's possible for the GRPC connection to be down when we receive
|
|
|
|
# this message, we should `{:continue, state.channel.host}`
|
|
|
|
{:noreply, state, {:continue, :health}}
|
|
|
|
end
|
2023-06-27 19:28:00 +00:00
|
|
|
|
2023-08-19 18:14:07 +00:00
|
|
|
@impl true
|
|
|
|
def handle_info({:gun_down, _pid, _proto, _reason, _}, %{channel: channel} = state) do
|
|
|
|
Logger.debug("disconnected from #{inspect(channel)}")
|
2023-06-27 19:28:00 +00:00
|
|
|
{:noreply, state}
|
|
|
|
end
|
|
|
|
|
|
|
|
@impl true
|
|
|
|
def handle_info(msg, state) do
|
2023-08-19 18:14:07 +00:00
|
|
|
Logger.warning("received unexpected message: #{inspect(msg)}")
|
2023-06-27 19:28:00 +00:00
|
|
|
{:noreply, state}
|
|
|
|
end
|
|
|
|
|
|
|
|
@impl true
|
|
|
|
def terminate(_reason, %{channel: channel}) do
|
2023-08-19 18:14:07 +00:00
|
|
|
if channel, do: GRPC.Stub.disconnect(channel)
|
2023-06-27 19:28:00 +00:00
|
|
|
end
|
|
|
|
|
|
|
|
defp via(name) do
|
|
|
|
{:via, Registry, {Prymn.Agents.Registry, name}}
|
|
|
|
end
|
|
|
|
end
|