Reputation: 562
I'm trying to monitor several APIs at the same time. Currently I'm starting my application, which then causes my Supervisor to start and that in turn starts the monitoring processes. My feeble brain has managed to get to the point where I am spawning all 4 of child processes.
My APIMon.Monitor
module is a mess and I'm not really sure how to fix it. What I want here is for each of these to start as children of the Supervisor, and then indefinitely run in their own scan()
loops while all outputting information to the console independently.
I've been playing with this for a while and trying to go through the Task docs and I can't seem to find a way to make this work where I'm not blocking the console entirely in iex -S mix
, which I assume means I'm blocking entirely. I want to be able to execute commands in the console while these Tasks are running or sleeping.
Any help would be greatly appreciated.
defmodule APIMon do
@API [
%{id: "A", host: '192.168.1.5', port: 3001},
%{id: "B", host: '192.168.1.7', port: 3001},
%{id: "C", host: '192.168.1.8', port: 3001},
%{id: "D", host: '192.168.1.9', port: 3001}
]
def start(_type, _args) do
APIMon.Supervisor.start_link(@API)
end
end
defmodule APIMon.Supervisor do
use Supervisor
def start_link(args) do
Supervisor.start_link(__MODULE__, args, name: __MODULE__)
end
def init(args) do
children =
args
|> Enum.reduce([], fn child, acc ->
acc =
acc ++ [Supervisor.child_spec({APIMon.Monitor, child}, id: "Worker_#{child.id}")]
end)
Supervisor.init(children, strategy: :one_for_one)
end
end
defmodule APIMon.Monitor do
use GenServer
def start_link(arg) do
id = arg.id
GenServer.start_link(__MODULE__, arg, name: :"#{__MODULE__} [#{id}]")
end
## Callbacks
def init(arg) do
pid = Kernel.inspect(self())
IO.puts "Adding API monitor #{arg.id} to the stack as #{pid}"
scan()
{:ok, arg}
end
def scan() do
task = Task.async(fn ->
#do individual API health checks here
end)
Task.await(task)
:timer.sleep(2500)
scan()
end
end
Upvotes: 0
Views: 54
Reputation: 9639
The problem with your APIMon.Monitor
is it doesn't return from init
- you're getting into infinite loop calling scan()
. You could get around this by sending message to itself.
Sounds a bit cryptic, so let me show you an example:
defmodule APIMon.Monitor do
use GenServer
def start_link(arg) do
id = arg.id
GenServer.start_link(__MODULE__, arg, name: :"#{__MODULE__} [#{id}]")
end
## Callbacks
def init(arg) do
pid = Kernel.inspect(self())
IO.puts "Adding API monitor #{arg.id} to the stack as #{pid}"
Process.send_after(self(), :scan, 2500)
{:ok, arg}
end
def handle_info(:scan, state) do
#do individual API health checks here
Process.send_after(self(), :scan, 2500)
{:noreply, state}
end
end
Other than that I don't think your code is a mess - this is really nicely structured Elixir/OTP code!
Hope that helps!
Upvotes: 4