-
-
Notifications
You must be signed in to change notification settings - Fork 148
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
How to setup quantum against libcluster #485
Comments
I tried adding quantum-swarm, global: true and Random Strategy but it didn't work. |
@felipeloha Currently, I used a library called highlander to make the process running only 1 process in the cluster (with random node) and set the strategy to |
Thanks for the hint. I tried using highlander to make the scheduler run in only 1 node with how did you solve this? or are your jobs running in only one node? thanks in advance |
@felipeloha Since you wrap scheduler process with highlander, the process will run only 1 process at a time per cluster (not per node). Set the strategy to Quantum.RunStrategy.Local will run only node that scheduler run. The warning that you found happens because quantum try to run in random node which's not work because it expected to run quantum on all node in the cluster but in your case isn't because of highlander. |
I tried adding quantum-swarm + global:true + Random strategy and the logs say that the nodes are found but then the jobs are run in all nodes instead of just one. Is there a way to run the jobs in a "distributed"/random manner in the cluster? |
@felipeloha i never use swarm extension but i guess that scheduler doesn't coordinate between node. The hack way that i think is use :global to perform distributed lock. |
I don't think you really need horde or w.e in your application.ex register your supervisor of Quantum using a "custom" Supervisor module (see bellow for details) children = [
# other children
%{
id: MyApp.SchedulerSupervisor,
start: {MyApp.Scheduler, :start_link, [[supervisor_module: MyApp.SchedulerSupervisor]]}
}
] in scheduler_supervisor.ex defmodule MyApp.SchedulerSupervisor do
def start_link(quantum, opts) do
opts = Keyword.put(opts, :name, {:global, __MODULE__})
:global.trans({__MODULE__, :start_link}, fn ->
case :global.whereis_name(__MODULE__) do
:undefined ->
Quantum.Supervisor.start_link(quantum, opts)
pid ->
# If the process is fine in the global table then simply link it to the current process.
Process.link(pid)
{:ok, pid}
end
end)
end
end The main purpose of this module is to change how Quantum supervisor works.
Now let's manage how libcluster will connect to other node. in cluster.ex defmodule MyApp.Cluster do
use GenServer
def start_link(_) do
GenServer.start_link(__MODULE__, nil)
end
def init(state), do: {:ok, state}
def connect_node(node) do
# retrieve the pid of our SchedulerSupervisor (in the global table)
pid = :global.whereis_name(MyApp.SchedulerSupervisor)
# connect to the specified node
result = :net_kernel.connect_node(node)
if result && is_pid(pid) do
# if we successfully connect and there is an instance of our global SchedulerSupervisor then stop it
Supervisor.terminate_child(MyApp.Supervisor, MyApp.SchedulerSupervisor)
end
# Force sync the global table
:global.sync()
# restart the SchedulerSupervisor (this will call `start_link` in `MyApp.SchedulerSupervisor`
Supervisor.restart_child(MyApp.Supervisor, MyApp.SchedulerSupervisor)
result
end
end
in config.exs config :my_app,
libcluster: [
example: [
connect: {MyApp.Cluster, :connect_node, []},
# config ...
]
] ℹ️ It's not fully related to libcluster you could also use Dunno if the maintenant of this lib want this kind of code in its lib (using the |
So update on this I got a better solution: defmodule MyApp.SchedulerSupervisor do
def start_link(quantum, opts) do
case :global.whereis_name(__MODULE__) do
:undefined ->
with {:error, {:already_started, pid}} <- do_start_link(quantum, opts) do
Process.link(pid)
{:ok, pid}
end
pid ->
Process.link(pid)
{:ok, pid}
end
end
defp do_start_link(quantum, opts) do
Supervisor.start_link(__MODULE__, {quantum, opts}, name: {:global, __MODULE__})
end
def init(state) do
:global.re_register_name(__MODULE__, self(), &resolve_global_conflict/3)
Quantum.Supervisor.init(state)
end
defp resolve_global_conflict(_name, pid_to_keep, pid_to_kill) do
Supervisor.stop(pid_to_kill)
pid_to_keep
end
end Using Hope it help. PS: 1 thing to know you can't know which process will be killed :/ |
I've a question about how to configuring quantum to run on libcluster, my use case is try to run on
n
node and let quantum run the job only once. As I observe in the issue, it has been the global mode but it seems removed in the old version. Do we have any way to tackle this use case?The text was updated successfully, but these errors were encountered: