防止重复命名进程
Prevent duplicate named processes
我有一个 elixir (Phoenix) 应用程序,可以定期为用户检索分析数据。
我有一个 AnalyticSupervisor
来监督 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
AnalyticWorker
正在使用 gproc 作为进程注册表来创建动态进程名称并排队分析调用。
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
AnaylticSupervisor
在我的 Phoenix 应用程序启动时启动,并将对任何现有用户的分析调用进行排队。
问题是,如果我开始另一个 iex
会话,这也会启动主管和工作人员 - 我最终会为同一个工作处理多个进程。
我认为使用 gproc
作为进程注册表可以避免这种情况 - 但每个 iex
会话都在创建自己的进程注册表。
如何确保进程是唯一的,无论它们是由 iex 会话还是我的 Phoneix 应用程序排队?
有没有比我正在做的更好的方法来实现独特的预定工作?
通过 运行 “另一个 iex
实例”,您基本上是在创建新的 erlang 节点,它对周围的其他节点一无所知 运行。
确保进程唯一的一个选项是 attach 随后开始 iex
到 运行 一个。假设,原始进程开始于:
# ⇓⇓⇓⇓⇓⇓⇓⇓⇓
MIX_ENV=prod elixir --sname analytics -S mix run --no-halt
附加 iex
使用:
# put resolvable host name here ⇓⇓⇓⇓⇓⇓⇓⇓⇓
iex --sname console --remsh analytics@localhost
由于第二个问题是 a) 同一 OP 中的第二个问题和 b) 基于高度意见,我建议您将您所拥有的与现有的实现进行比较(常见的方法是 使用 Redis
或喜欢 以确保唯一性):
- https://github.com/edgurgel/verk
- https://github.com/joakimk/toniq
- https://github.com/akira/exq
- https://github.com/mosic/exdisque
- https://github.com/ejholmes/exsidekiq
- https://github.com/PSPDFKit-labs/sidetask
此外,Task.Supervisor
可能会满足您对零成本的要求。
我有一个 elixir (Phoenix) 应用程序,可以定期为用户检索分析数据。
我有一个 AnalyticSupervisor
来监督 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
AnalyticWorker
正在使用 gproc 作为进程注册表来创建动态进程名称并排队分析调用。
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
AnaylticSupervisor
在我的 Phoenix 应用程序启动时启动,并将对任何现有用户的分析调用进行排队。
问题是,如果我开始另一个 iex
会话,这也会启动主管和工作人员 - 我最终会为同一个工作处理多个进程。
我认为使用 gproc
作为进程注册表可以避免这种情况 - 但每个 iex
会话都在创建自己的进程注册表。
如何确保进程是唯一的,无论它们是由 iex 会话还是我的 Phoneix 应用程序排队?
有没有比我正在做的更好的方法来实现独特的预定工作?
通过 运行 “另一个 iex
实例”,您基本上是在创建新的 erlang 节点,它对周围的其他节点一无所知 运行。
确保进程唯一的一个选项是 attach 随后开始 iex
到 运行 一个。假设,原始进程开始于:
# ⇓⇓⇓⇓⇓⇓⇓⇓⇓
MIX_ENV=prod elixir --sname analytics -S mix run --no-halt
附加 iex
使用:
# put resolvable host name here ⇓⇓⇓⇓⇓⇓⇓⇓⇓
iex --sname console --remsh analytics@localhost
由于第二个问题是 a) 同一 OP 中的第二个问题和 b) 基于高度意见,我建议您将您所拥有的与现有的实现进行比较(常见的方法是 使用 Redis
或喜欢 以确保唯一性):
- https://github.com/edgurgel/verk
- https://github.com/joakimk/toniq
- https://github.com/akira/exq
- https://github.com/mosic/exdisque
- https://github.com/ejholmes/exsidekiq
- https://github.com/PSPDFKit-labs/sidetask
此外,Task.Supervisor
可能会满足您对零成本的要求。