繁体   English   中英

Phoenix应用启动时的调用功能

[英]Calling function on Phoenix app start

在Phoenix应用程序启动时,调用该函数从数据库加载一些数据的最简单方法是什么? 因此,我需要我的函数拥有Ecto.Query优良性,并在Phoenix开始处理任何请求之前调用它。

您可以在启动时在RepoEndpoint主管之间的my_app/application.ex中启动工作my_app/application.ex

# Define workers and child supervisors to be supervised
children = [
  # Start the Ecto repository
  supervisor(MyApp.Repo, []),

  # The new worker
  worker(MyApp.DoSomething, [], restart: :temporary),

  # Start the endpoint when the application starts
  supervisor(MyAppWeb.Endpoint, []),
  # Start your own worker by calling: MyApp.Worker.start_link(arg1, arg2, arg3)
  # worker(MyApp.Worker, [arg1, arg2, arg3]),
]

并创建一个文件my_app/do_something.ex

defmodule MyApp.DoSomething do
  use GenServer

  def start_link do
    GenServer.start_link(__MODULE__, %{})
  end

  @impl true
  def init(state) do
    user = MyApp.Accounts.get_user!(1)
    IO.inspect user

    Process.sleep(10_000)
    IO.inspect "Done sleeping"

    # Process will send :timeout to self after 1 second
    {:ok, state, 1_000}
  end

  @impl true
  def handle_info(:timeout, state) do
    # Stop this process, because it's temporary it will not be restarted
    IO.inspect "Terminating DoSomething"
    {:stop, :normal, state}
  end
end

在启动时,您应该在10秒钟的延迟后看到一些有关用户的信息: Running MyAppWeb.Endpoint with Cowboy using http://0.0.0.0:4000

我不确定这是否是最好,最安全的方法(也许根本不需要GenServer吗?),但还是可以100%确定。 该回购在工作进程中可用,并且端点在init返回之前不会启动。

编辑:我已经更新了代码,以(希望)完成后正确关闭该过程。

除了@zwippie很棒的答案外,我还对自己的问题给出了自己的答案,这是更通用的OTP标准,但我的却更简单,可以在某些情况下使用。

要在Phoenix端点开始服务请求之前立即调用该函数,我们可以从应用程序的Endpoint模块的init()回调中调用该函数,该回调在Ecto.Repo.Supervisor启动Ecto.Repo工作器之后立即调用。

因此,如果我们有:my_app应用程序,则可以打开lib / my_app_web / endpoint.ex文件,在其中找到回调函数init()并从那里调用某些函数。

这篇不错的文章还总结了第三种方法,即使用Task模块。 它省去了编写完整的Genserver的麻烦:

defmodule Danny.Application do
  use Application
  # ...
  def start(_type, _args) do
    children = [
      supervisor(Danny.Repo, []),
      # ...
      worker(Task, [&CacheWarmer.warm/0], restart: :temporary) # this worker starts, does its thing and dies
      # ...
      ]
    opts = [strategy: :one_for_one, name: Danny.Supervisor]
    Supervisor.start_link(children, opts)
  end
end

定义一个模块:

defmodule CacheWarmer do
  import Logger, only: [debug: 1]
  def warm do
    # warming the caches
    debug "warming the cache"
    # ...
    debug "finished warming the cache, shutting down"
  end
end

请注意, your_app.ex唯一的附加行是: worker(Task, [&CacheWarmer.warm/0], restart: :temporary)

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM