首页 > 解决方案 > 如何监督长生不老药中的方法

问题描述

我正在尝试监督长生不老药中的一种方法。我有这个模块EvercamMedia.SnapshotExtractor.CloudExtractorGenStage我正在向它传递一些参数,例如。

def handle_cast({:snapshot_extractor, config}, state) do
  _start_extractor(config)
  {:noreply, [], state}
end

这个_strat_extractor方法本身很长,方法很多。但在所有这些方法中,我使用一种方法不是直接发送 HTTPoison 请求,而是通过一个dropboxapi 包装器发送 HTTPoison 请求。

  def upload(200, response, starting, camera_exid, id, requestor) do
    construction =
      case requestor do
        "marklensmen@gmail.com" ->
          "Construction"
        _ ->
          "Construction2"
      end

    image_save_path = "#{@root_dir}/#{camera_exid}/extract/#{id}/#{starting}.jpg"
    path = "#{@root_dir}/#{camera_exid}/extract/#{id}/"
    File.write(image_save_path, response, [:binary]) |> File.close

    client = ElixirDropbox.Client.new(System.get_env["DROP_BOX_TOKEN"])
    {:ok, file_size} = get_file_size(image_save_path)

    try do
      %{"session_id" => session_id} = ElixirDropbox.Files.UploadSession.start(client, true, image_save_path)
      write_sessional_values(session_id, file_size, "/#{construction}/#{camera_exid}/#{id}/#{starting}.jpg", path)
      check_1000_chunk(path) |> length() |> commit_if_1000(client, path)
    rescue
      _ ->
        :timer.sleep(:timer.seconds(3))
        upload(200, response, starting, camera_exid, id, requestor)
    end
  end
  def upload(_, _response, _starting, _camera_exid, _id, _requestor), do: :noop

现在,我的问题是如何监督这种方法?

有时这部分会失败ElixirDropbox.Files.UploadSession.start(client, true, image_save_path)。我还为它添加了一个主管,但它不会在崩溃时重新启动它,而是在应用程序停止时恢复它。

我如何利用Supervisor策略并在崩溃时恢复此方法。

def upload(200, response, starting, camera_exid, id, requestor) do

不管怎样,我的主管看起来像这样。

defmodule EvercamMedia.SnapshotExtractor.ExtractorSupervisor do

  use Supervisor
  require Logger
  alias EvercamMedia.SnapshotExtractor.Extractor
  alias EvercamMedia.SnapshotExtractor.CloudExtractor
  import Commons

  @root_dir Application.get_env(:evercam_media, :storage_dir)

  def start_link() do
    Supervisor.start_link(__MODULE__, :ok, name: __MODULE__)
  end

  def init(:ok) do
    Task.start_link(&initiate_workers/0)
    extractor_children = [worker(Extractor, [], restart: :permanent)]
    supervise(extractor_children, strategy: :simple_one_for_one, max_restarts: 1_000_000)
    cloud_extractor_childern = [worker(CloudExtractor, [], restart: :permanent)]
    supervise(cloud_extractor_childern, strategy: :simple_one_for_one, max_restarts: 1_000_000)
  end

PS:我尝试将两个工人都添加到子列表中,并立即将其传递给监督,但效果不佳。

标签: elixir

解决方案


有很多问题ExtractorSupervisor.init/1

def init(:ok) do
  Task.start_link(&initiate_workers/0)
  children1 = ...
  supervise(children1, ...)
  children2 = ...
  supervise(children2, ...)
end

首先,您使用不推荐使用的遗留方式来初始化主管和遗留策略中的子项。

这种方法的主要问题是children1永远不会受到监督。Supervisor.Spec.supervise/2不是凭空监督的魔杖制作过程。它只是从回调中返回规范,调用者init/1可以理解,最终将子项嵌入到监督树中。这意味着,第一次调用是 noop。监督所有孩子应该做的事supervise/2

def init(:ok) do
  children1 = ...
  children2 = ...

  supervise(children1 ++ children2, ...)
end

可能会有更多的故障,但除非这两个被修复,否则很难推理。

旁注:虽然它在某种程度上是合法的,但我很确定可能会有更好的地方打电话Task.start_link/1而不是init/1回调主管。


推荐阅读