递归以调用外部API

时间:2017-02-24 13:00:57

标签: elixir phoenix-framework

我必须使用外部API来生成屏幕截图。在第一步中,我触发生成屏幕截图并收到job_id。我必须等待并且可以下载给定job_id的屏幕截图。不幸的是,我不知道我需要等多久。有时结果在10秒后就绪,有时则没有。如果尚未就绪,则函数image_url/1将返回nil。如果已准备就绪,则返回图像URL。

目前我使用睡眠时间为45秒,这是次优的。

我不明白如何使用递归的概念来实现函数generate_screenshot/1,首先运行new_job_id(url),然后尝试image_url/1 10次,10秒在nil之间或之前睡觉。

如何通过递归来解决这个问题?

def generate_screenshot(url) do
  job_id = new_job_id(url)
  :timer.sleep(45000)

  image_url(job_id)
end

defp new_job_id(url) do
  # This function triggers a process on 
  # an external web server an returns 
  # the job_id of it.
  12345
end

defp image_url(job_id) do
  # This function fetches something from 
  # a webserver. The result is nil or 
  # a URL of an image.
  [...]
end

2 个答案:

答案 0 :(得分:2)

您应该可以使用模式匹配和稍微分解逻辑来实现。这样的事情应该有效:

def generate_screenshot(url) do
  job_id = new_job_id(url)

  image_url(job_id))
end

defp new_job_id(url) do
  # This function triggers a process on 
  # an external web server an returns 
  # the job_id of it.
  12345
end

defp image_url(job_id) do
  # Call the version of this function with arity /2
  # and check the result. The 0 will act as a counting variable
  image_url(job_id), 0)
end

# When the counter reaches 10 return the value regardless
defp image_url(_, 10) do fetch_something()

# Add a case statement that checks the value returned
# if its nil call image_url/2 again after 10 seconds 
# and increment the counter by 1 
# Otherwise its not nil so we return the value
defp image_url(job_id, count) do
  case fetch_something() do
    nil -> 
      :timer.sleep(10000)
      image_url(job_id, count + 1) 
    url -> url
  end
end

defp fetch_something() do
  # This function fetches something from 
  # a webserver. The result is nil or 
  # a URL of an image.
  [...]
end

这里的重要部分是我们打破了从image_url/2函数中取出内容的实际内容,现在可以在case语句中调用它。这使我们可以使用模式匹配来调用image_url/2,并使用count变量匹配第10个响应。

希望这有用,我想发表评论并询问更多信息,但我还不能发表评论。

答案 1 :(得分:0)

首先,我不明白你为什么要/必须使用递归。

恕我直言,一个优雅的方法是制作一个检查 image_url 的循环,如果图像没有准备好,则睡眠固定的秒数(2,5,10,......?)然后继续循环(在n秒内再次检查)并在图像准备好时停止循环。

此解决方案是否满足您的需求?