2017-02-24 99 views
0

我必须使用外部API来生成屏幕截图。在第一步中,我触发屏幕截图的生成并收到job_id。比我必须等待,并可以下载给定的job_id截图。不幸的是,我不知道我需要等多久。有时结果在10秒后准备就绪,有时不成功。如果它没有准备好,功能image_url/1返回nil。如果准备就绪,则返回图片网址。递归调用外部API

目前我使用睡眠45秒,这是不理想的。

我不明白我怎么可以使用递归的概念来实现该功能generate_screenshot/1,首先运行new_job_id(url)比尝试image_url/1 10次,或直至它不是nil 10秒的睡眠。

我该如何解决这个递归?

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 
+0

您可能想看看['ElixirRetry'](https://github.com/safwank/ElixirRetry)。 – mudasobwa

回答

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,并将第10个响应与count变量进行匹配。

希望这是有帮助我想评论和要求更多的信息,但我还不能留下评论呢。

0

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

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

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

+3

Elixir有[尾巴呼叫优化](https://stackoverflow.com/questions/310974/what-is-tail-call-optimization)(TCO)。递归或通过循环执行某些操作之间没有太大区别。 –