I'm using a library that does an asynchronous request (push
) that always returns ok. It calls a callback with the actual response, whether ok or an error.
callback = fn(response) ->
# handle error or ok
end
:ok = Pigeon.APNS.push(n, callback)
# push returns immediately, but I want to block
# until callback is called and return that response
In this case I want to block and wait for the callback, turning this into a synchronous request. Is there an OTP feature like Task.await
or some other solution to turn this into a synchronous request?
答案 0 :(得分:3)
You can send a message from the callback to parent process and use receive
like this:
defmodule Pigeon.APNS do
def push(_n, callback) do
spawn_link(fn ->
:timer.sleep(2000)
callback.(:ok)
end)
:ok
end
end
ref = make_ref()
pid = self()
callback = fn(_response) ->
IO.puts "executing callback"
send(pid, ref)
end
:ok = Pigeon.APNS.push(0, callback)
IO.puts "called push"
receive do
^ref -> :ok
end
IO.puts "callback called"
Output:
called push
executing callback
callback called
答案 1 :(得分:0)
您可以发送消息,然后等待回调之外的消息继续,而不是从回调中返回。确保邮件包含唯一引用,并且您正在等待来自该引用的邮件,否则您将无法知道邮件的来源。
# Create a unique reference so you know
# where the return is coming from
id = make_ref()
# A function for waiting until a value
# comes in from a reference
wait_for_response = fn (id) ->
receive do
{^id, val} -> val
end
end
callback = fn (val) ->
IO.puts("In Callback")
# instead of returning, send the value to self with
# the right reference
send(self, {id, "I was passed the argument #{inspect val}"})
end
# Async fun knows nothing about this diferment
# and functions as normal
async_fun = fn (i, cb) ->
IO.puts("In Async Function")
Process.sleep(2000)
cb.(i)
end
# Usage
IO.puts("Starting")
async_fun.(1, callback)
val = wait_for_response.(id)
IO.puts "Callback returned: #{inspect val}"
IO.puts("All Done")