wintermeyer
wintermeyer

Reputation: 8318

Recursion to call an external API

I have to use an external API to generate a screenshot. In the first step I trigger the generation of the screenshot and receive a job_id. Than I have to wait and can download the screenshot with the given job_id. Unfortunately I don't know how long I have to wait. Sometimes the result is ready after 10 seconds and sometimes not. If it is not ready the function image_url/1 returns nil. If it is ready it returns the image URL.

Currently I use a sleep for 45 seconds which is suboptimal.

I don't understand how I can use the concept of recursion to achieve that the function generate_screenshot/1, first runs new_job_id(url) and than tries image_url/1 10 times with a 10 second sleep between or until it is not nil.

How can I solve this with a recursion?

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

Upvotes: 0

Views: 188

Answers (2)

James Byrne
James Byrne

Reputation: 310

You should be able to do it using pattern matching and by breaking up your logic a bit. Something like this should work :

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

The important part here is we broke the actual fetching of the content away from the image_url/2 function and can now call it from within the case statement. This lets us use pattern matching to call image_url/2 and match on the 10th response with the count variable.

Hope this is helpful I wanted to comment and ask for more info but I can't leave comments quite yet.

Upvotes: 2

r0b0urd0n
r0b0urd0n

Reputation: 21

First I don't understand why you want/have to use a recursion.

IMHO, an elegant way would be to make a loop that check for image_url, sleep a fixed number of seconds (2, 5, 10, ...?) if the image is not ready then continue the loop (to check again in n seconds) and stop the loop when image is ready.

Does this solution meet your needs ?

Upvotes: 0

Related Questions