Callback in coroutines not working

Am I doing something silly here that means the callback within the coroutine isn’t being called?
I don’t think it’s a garbage collection issue.

I have a feeling it may be an issue with how the callback is called when the callback is inside a coroutine?

function setup()
    
    -- Works
    print("Downloading on main thread")
    http.request("https://baconipsum.com/api/?type=meat-and-filler&paras=5&format=text", function(data)
        print("Main thread request done.")
    end)
    
    -- Does not work
    local co = coroutine.create(function()
        print("Downloading on coroutine thread")
        http.request("https://baconipsum.com/api/?type=meat-and-filler&paras=5&format=text", function(data)
            print("Coroutine request done.")
        end)
    end)
    coroutine.resume(co)
    
end

Cheers,
Steppers

@Steppers - is the second end bracket (IE last line in setup function) necessary ?

@Bri_G Yep, syntactically there’s nothing wrong with it.

I suspect it’s because the coroutine is dead, having done its yield. If you did get back in there, you;d get a second unexpected yield, I think.

Try this:

    -- Does not work
    local co = coroutine.create(function()
        print("Downloading on coroutine thread")
        http.request("https://baconipsum.com/api/?type=meat-and-filler&paras=5&format=text", function(data)
            print("Coroutine request done.")
        end)
    end)
    print(coroutine.status(co))
    coroutine.resume(co)
    print(coroutine.status(co))

You will find, as @RonJeffries said, that co is dead.

@binaryblues @RonJeffries The Coroutine is dead but I don’t think that’s the immediate cause.

This still doesn’t work even though the coroutine is just suspended instead.

function setup()
    
    -- Works
    print("Downloading on main thread")
    http.request("https://baconipsum.com/api/?type=meat-and-filler&paras=5&format=text", function(data)
        print("Main thread request done.")
    end)
    
    -- Does not work
    local co = coroutine.create(function()
        print("Downloading on coroutine thread")
        http.request("https://baconipsum.com/api/?type=meat-and-filler&paras=5&format=text", function(data)
            t = data
        end)
        coroutine.yield()
    end)
    print(coroutine.status(co))
    coroutine.resume(co)
    print(coroutine.status(co))
end

function draw()
    print(t)
end

@Simeon Is there something odd going on in the backend that would cause the callback to never be called at all?

the coroutine runs, it’s the data that is not return from the http request


function setup()
  t = ""
  local co = coroutine.create(function()
    print("Downloading on coroutine thread")
    http.request("https://baconipsum.com/api/?type=meat-and-filler&paras=5&format=text", function(data)
      print("success")
      t = data
    end, function () print("failed") end )
    --coroutine.yield()
  end)
  print(coroutine.status(co))
  coroutine.resume(co)
  print(coroutine.status(co))
end

function draw()
  print(t)
end

neither success or failed are printed

@skar Yeah the http callback is never called, the coroutine is fine.

my guess is once the coroutine runs the reference to the pass or fail functions is deleted, this must happen somewhere in the http.request function because i tested using a global reference function in pass and fail and it still does not work


-- Use this function to perform your initial setup
function setup()
  t = ""
  pass = function(data)
      print("success")
      t = data
  end
  fail = function ()
    print("failed")
  end
  local co = coroutine.create(function()
    print("Downloading on coroutine thread")
    http.request("https://baconipsum.com/api/?type=meat-and-filler&paras=5&format=text", pass, fail )
    --coroutine.yield()
  end)
  print(coroutine.status(co))
  coroutine.resume(co)
  print(coroutine.status(co))
  --print("Downloading in setup")
  --http.request("https://baconipsum.com/api/?type=meat-and-filler&paras=5&format=text", pass, fail )
end

function draw()
  print(t)
end


i’m also inclined to believe the issue is with .request because i use coroutine as thread to load my scenes behind a loading screen and have never seen a callback fail

@skar After a little more digging I believe the issue could potentially stem from native side.

When the native side calls the callback It’ll be using lua_pcall, passing in the lua_State* but by the look of it, coroutines use a different lua_State object.

@Simeon this along the right lines? I’m guessing blindly here.

that’s deeper than my knowledge but what i can say is if you replace http.request with something else that uses callbacks like tween it works as expected

-- Use this function to perform your initial setup
function setup()
  t = ""
  pass = function(data)
      print("success")
      t = data
  end
  fail = function ()
    print("failed")
  end
  local co = coroutine.create(function()
    --print("Downloading on coroutine thread")
    --http.request("https://baconipsum.com/api/?type=meat-and-filler&paras=5&format=text", pass, fail )
    --coroutine.yield()
    tween (2, {}, {}, nil, function () print ("tween done") end)
  end)
  print(coroutine.status(co))
  coroutine.resume(co)
  print(coroutine.status(co))
  --print("Downloading in setup")
  --http.request("https://baconipsum.com/api/?type=meat-and-filler&paras=5&format=text", pass, fail )
end

function draw()
  print(t)
end

you can piggy back into the tween end function and pass data there, it’s a bit of a hack but it works


-- Use this function to perform your initial setup
function setup()
  t = ""
  pass = function(data)
    print("success")
    t = data
  end
  fail = function ()
    print("failed")
  end
  local co = coroutine.create(function()
    print("Downloading on coroutine thread")
    tween (2, {}, {}, nil, function () 
      http.request("https://baconipsum.com/api/?type=meat-and-filler&paras=5&format=text",  pass, fail )
    end)

    coroutine.yield()

  end)
  print(coroutine.status(co))
  coroutine.resume(co)
  print(coroutine.status(co))
  --print("Downloading in setup")
  --http.request("https://baconipsum.com/api/?type=meat-and-filler&paras=5&format=text", pass, fail )
end

function draw()
  print(t)
end

@skar Ah, nice find! Other than being a little unwieldy that works quite nicely for what I’m trying to do.
Cheers :smile:

@skar You can also see that the callback inside the tween is running on the ‘main’ coroutine too:

function setup()
    
    -- Works
    print("Downloading on main thread", coroutine.running())
    http.request("https://baconipsum.com/api/?type=meat-and-filler&paras=5&format=text", function(data)
        print("Main thread request done.", coroutine.running())
    end)
    
    -- Does not work
    local co = coroutine.create(function()
        print("Downloading on coroutine thread", coroutine.running())
        
        tween(0.01, {}, {}, nil, function()
            http.request("https://baconipsum.com/api/?type=meat-and-filler&paras=5&format=text", function(data)
                print("Coroutine request done.", coroutine.running())
            end)
        end).time = 0.0
    end)
    coroutine.resume(co)
end

function draw()
    print()
end