I've got an elixir (Phoenix) application that retrieves analytic data for users at regular intervals.
I've got an AnalyticSupervisor
to supervise AnalyticWorker
s.
defmodule AnalyticsSupervisor do
use Supervisor
def start_link do
Supervisor.start_link(__MODULE__, [], name: :analytics_supervisor)
end
def init(_) do
children = [
worker(AnalyticsWorker, [])
]
supervise(children, strategy: :simple_one_for_one)
end
def start_worker(user) do
Supervisor.start_child(:analytics_supervisor, [user])
end
end
The AnalyticWorker
is is using gproc as a process registry to create a dynamic process name and queue an analytic call.
defmodule AnalyticsWorker do
use GenServer
def start_link(user) do
GenServer.start_link(__MODULE__, user, name: via_tuple(user))
end
defp via_tuple(user) do
{:via, :gproc, {:n, :l, {:analytics_worker, user.id}}}
end
def init(user) do
queue_analytic_call(user)
{:ok, user}
end
def queue_analytic_call(user) do
:timer.apply_after(50000, __MODULE__, :call_anlaytics, [user])
end
end
The AnaylticSupervisor
is started when my Phoenix application is started, and will queue up analytic calls for any existing users.
The problem is, if I start off another iex
session, this will also start the supervisor and workers - I'll end up with multiple processes for the same job.
I thought that using gproc
as a process registry, this would be prevented - but each iex
session is creating it's own process registry.
How to I ensure that the processes are unique, regardless of whether they're being queued by an iex session or my Phoneix application?
Is there a better way of achieving unique scheduled jobs than what I'm doing?
By running the “another iex
instance” you are basically creating the new erlang node, that knows nothing about other nodes running around.
One option to ensure that the processes are unique, regardless of whether they're being queued by an iex session or my Phoneix application would be to attach the subsequently started iex
to the running one. Assuming, that the original process was started with:
# ⇓⇓⇓⇓⇓⇓⇓⇓⇓
MIX_ENV=prod elixir --sname analytics -S mix run --no-halt
to attach iex
to it use:
# put resolvable host name here ⇓⇓⇓⇓⇓⇓⇓⇓⇓
iex --sname console --remsh analytics@localhost
Since the second question is a) the second question in the same OP and b) highly opinion based, I would suggest you compare what you have to already existing implementations (the common approach would be to use Redis
or like to ensure uniqueness):
Also, Task.Supervisor
might suffice your requirements for zero cost.