Coroutines and sync http requests

Hi everyone. I think I am missing about understanding how coroutines work.
I have searched forum and found some examples, but still could not make code work synchronously.

local co = coroutine.create(function()
	local co = coroutine.running()
	print('request is executed')
	http.request("http://d.defold.com/stable/info.json", "GET", function(self, id, response)
		print('result is fetched')
		coroutine.resume(co, response)
	end)
	
	return coroutine.yield()
end)

local ok, err = coroutine.resume(co)
print('should not be executed before fetched result')

From my understand last print(‘should not be executed…’) should printed last, since we are pausing coroutine until we receive response from the http request. But it does not work like this.
The output, which I get is:

DEBUG:SCRIPT: request is executed
DEBUG:SCRIPT: should not be executed before fetched result
DEBUG:SCRIPT: result is fetched

Can somebody advice something about it?

It is the code within the coroutine that doesn’t continue to execute. In this case as soon as you yield you give back control to the main thread and the print() will be executed.

The correct code would be:

local function http_request(url, method)
	local co = coroutine.running()
	http.request("http://d.defold.com/stable/info.json", "GET", function(self, id, response)
		print('result is fetched')
		coroutine.resume(co, response)
	end)
	return coroutine.yield()
end

local co = coroutine.create(function()
	print('request is executed')
	local response = http_request("http://d.defold.com/stable/info.json", "GET")
	print('should not be executed before fetched result')
end)

local ok, err = coroutine.resume(co)

2 Likes

Sorry, but still not very clear for me. If I will add print after ‘local ok, err = coroutine.resume(co)’, then it will be executed before result is fetched.

Yes, this is completely expected. Illustration:

1 - We start the coroutine. The current “thread” (main) is paused when coroutine.resume() is called and we start execution of the coroutine function. The text “request is executed” is printed.

2 - We call the http_request() function which in turn calls the http.request() function. The call to http.request() is asynchronous and the callback doesn’t get immediately invoked.

3 - We proceed to call coroutine.yield(). This pauses the coroutine and returns control to the main “thread”. The text “foobar” is printed.

…

4 - Sometime later the call to http.request() is completed and the http.request() callback function is invoked. The text “result is fetched” is printed.

5 - The coroutine is resumed from the point in http_request where we called coroutine.yield(). Execution on the main “thread” is again paused. We end up on the line after the call to http_request and the text “should not be executed before fetched result” is printed. This is the last line of code in the coroutine function and the coroutine has now finished running.

2 Likes

Thank you very much for such detailed answer, but my idea was exactly to pause main thread until we get some results from http_request, so we can work with response in main thread synchronously.

Well, the async operation and the processing of the response has to be in the same coroutine. If you pause or block the main thread the whole engine will be affected.

2 Likes

Then here comes some message listener in place. I guess, I have thought of not correct design in the first place. Thank you for your responses, they are very valuable!

2 Likes