如何正确地将 Postgrex.Notifications 传递给主管

How to correctly pass Postgrex.Notifications to a supervisor

我正在尝试在 phoenix 中设置 postgres 触发器。

docs状态

In order to use it, first you need to start the notification process. In your supervision tree:

{Postgrex.Notifications, name: MyApp.Notifications}

所以这是我的实现:

application.ex

defmodule Foo.Application do
  ...

  def start do
    children = [Foo.Repo, {Postgrex.Notifications, Name: Foo.Notifier}]
    opts = [strategy: :one_for_one, name: Foo.Supervisor]
    Supervisor.start_link(children, ops)
  end
end

notifier.ex

defmodule Foo.Notifier do
  def child_spec(opts) do
    %{
      id: __MODULE__,
      start: {__MODULE__, :start_link, [opts]}
    }
  end

  def start_link(opts \ []),
    do: GenServer.start_link(__MODULE__, opts)

  def init(opts) do
    # setup postgres listeners
  end
end

我收到一条错误消息说

The module Postgrex.Notifications was given as a child to a supervisor but it does not implement child_spec/1.

If you own the given module, please define a child_spec/1 function that receives an argument and returns a child specification as a map.

However, if you don't own the given module and it doesn't implement child_spec/1, instead of passing the module name directly as a supervisor child, you will have to pass a child specification as a map

所以我按照错误中的例子做了

    %{
      id: Postgrex.Notifications,
      start: {Postgrex.Notifications, :start_link, [arg1, arg2]}
    }

我的实现:

children = [
  Foo.Repo,
  %{
    id: Postgrex.Notifications,
    start: {Postgrex.Notifications, :start_link, opts}
  }
]

Supervisor.start_link(children, opts)

但现在我得到了错误

** (Mix) Could not start application survey: exited in: Foo.Application.start(:normal, [])
    ** (EXIT) an exception was raised:
        ** (UndefinedFunctionError) function Supervisor.start_link/1 is undefined or private

我找到了this tutorial

无需将元组传递给主管树,只需传递您的模块并手动调用 start_link

application.ex

children = [Foo.Repo, Foo.Notifier]

notifier.ex

@impl true
def init(opts) do
  with {:ok, _pid, _ref} <- Repo.listen("some_channel_name") do
    {:ok, opts}
  else
    error -> {:stop, error}
  end
end

repo.ex

defmodule Foo.Repo do
  def listen(channel) do
    with {:ok, pid} <- Postgrex.Notifications.start_link(__MODULE__.config()),
         {:ok, ref} <- Postgrex.Notifications.listen(pid, channel) do
      {:ok, pid, ref}
  end
end