kernelsauce / turbo

Turbo is a framework built for LuaJIT 2 to simplify the task of building fast and scalable network applications. It uses a event-driven, non-blocking, no thread design to deliver excellent performance and minimal footprint to high-load applications while also providing excellent support for embedded uses.
http://turbo.readthedocs.io/
Apache License 2.0
525 stars 84 forks source link

multiple connections with a long process #353

Closed Chipsterjulien closed 4 years ago

Chipsterjulien commented 4 years ago

Hello. I am trying to create a REST server with turbo. During my tests, I create a long and heavy response (route "/") which results in freeze of turbo throughout the long operation. No one can contact the REST server. I tried the coroutine and thread but everything I did crashed. I am making an example where the burnCPU function represented many os.execute(). I tried to replace it with sleep via FFI but it's the same. My example:

local turbo = require("turbo")

function burnCPU()
  -- try to simulate a long operation. Replace it by many longs os.execute()
  for _=1, 1000000000 do end
end

-- Create a new requesthandler with a method get() for HTTP GET.
local HelloWorldHandler = class("HelloWorldHandler", turbo.web.RequestHandler)
function HelloWorldHandler:get()
  burnCPU() -- this function represente longs actions
  self:write({info = "Hello world !"})
end

local printHello = class("printHello", turbo.web.RequestHandler)
function printHello:get()
  self:write({info = "Hello"})
end

-- Create an Application object and bind our HelloWorldHandler to the route '/hello'.
local app = turbo.web.Application({
  {"^/$", HelloWorldHandler},
  {"/hello", printHello}
})

-- Set the server to listen on port 8888 and start the ioloop.
app:listen(8888)
turbo.ioloop.instance():start()

Thanks for your help Best regards

Julien

Chipsterjulien commented 4 years ago

No idea ?

hippi777 commented 4 years ago

hi there! :)

i wanted to write, just i forgot about it.... i believe its a timeout, and i think u could check out the relevant headers (like keep alive? dunno...), or if the case is this but headers cant solve it then anything like fetch api, xhr or websocket could be utilized to avoid the waiting...

good luck, and please update if uve found anything relevant, im curious! :)

Chipsterjulien commented 4 years ago

Hello. Using fetch or whatever to do asynchronous doesn't work. In the example above, even if you replace burnCPU with a sleep, the problem is the same and the server becomes inaccessible for the duration of the sleep. Sleep that I use:

local ffi = require "ffi"
ffi.cdef "unsigned int sleep(unsigned int seconds);"
ffi.C.sleep(10)

I think I'm doing it wrong and the code should be changed but I have to make a mistake. Would it be possible to modify my code above so that, despite sleep (or burn), the server remains accessible when I do 2 access in 2 differents consoles in same time? I launch access with those commands:

http localhost:8888/

and the other in the second console

http localhost:8888/hello

You can use curl in place of httpie ;)

hippi777 commented 4 years ago

sooo, im not a turbo user at the moment, just planning to use it (for a long while now, but it seems like its kinda near now) and therefore i dunno enough about its internals... however i just made some minor investigations and if i understood correctly then u can only avoid this by breaking up big task to smaller ones, or do it in the background to not make it a showstopper, as things are handled by an event loop that really needs to be fed by fast/small tasks to be responsive...

btw see this: https://turbo.readthedocs.io/en/latest/modules.html

back in time ive chose turbo as it has all the necessary stuffs i can wish for, and cuz its small and easy to read (and that way to customize as well) so i think u should check out the relevant source bits as well, and i think its not a big deal, but anyhow i will be around and try my best to help whenever i can :)

currently the most important question is that what does the burnCpu() stands for in ur real program?

Chipsterjulien commented 4 years ago

Thank you for your prompt response. I saw the page https://turbo.readthedocs.io/en/latest/modules.html but I cannot use it correctly because everything I have tried does not work. So I'm going to use turbo for a rest API. For now, I want to start / stop starting a camera (raspberry) with streaming. Basically, I need to run this line:

(raspimjpeg.py -w 640 -h 480 -r 15 | streameye -d -p 8081) &

After i test if raspimjpeg and streameye are running with pgrep command but all this take some times and I wish it was non-blocking

hippi777 commented 4 years ago

then i think u could start it in the 1st step without waiting and then use the event loop in a 2nd step to check back for the result, as i think the idle time is for waiting in place for the result instead of giving back the control to turbo... btw do u get the resoponse for the 2nd call after some delay or u dont get any? the latter case would make me sad... however timeout may still apply in that case, but i think thats more than 10s, otherwise wordpress would die out :D

Chipsterjulien commented 4 years ago

I apologize for the question but how to use the event loop to call another function and check that everything is started?

If I understood your answer correctly if I make a call on / and immediately after on /hello in another console, the loop having no latency on the response arrives once that on / is completed since the program is blocked on the first call

hippi777 commented 4 years ago

if u take the coroutine approach, then its like yield after start and then the event loop will restart the coroutine until it finally returns, and yield every time uve found ur command is still about initializing itself, and finally return when its up and running, or take the necessary steps in case of a fail...

my curiosity was about handling properly a second request while the 1st is idle, so i could imagine that turbo doesnt even listen while its busy, but i think that would be a serious issue and would be known and solved, otherwise it would be nearly a garbage project :D back in time when i discovered it, i only checked out it on a hello world level and then i did a lotsa other things and so far now i didnt reach the point to make use of it, now i dont even have it installed, as im on a rescue system after my hdd crashed in december and currently i make a custom linux (mostly based on void linux) for myself, that takes much learning :D

Chipsterjulien commented 4 years ago

I'm just a beginner so the use of coroutine is not within my reach

hippi777 commented 4 years ago

there are examples on that page i linked, otherwise u can check out the lua manual, the programming in lua book or just search for it, but coroutines arent mandatory based on the asynch page of the turbo manual... ur actual problem is that ur waiting for the initialization to complete, and in the meantime the event loop must wait, while u should let it run in the meantime... otherwise now as i just realized how this works i should think about all of my use-cases to reevaluate turbo, but in worst case i think it still can give me useful resources to make anything for myself in the future, just i wanted to jump into the middle of it right after ive been done with my new system... uhm i mean here that maybe u should think about it as well, but its reasonably lightweight and simple, so reshaping ur code is probably the best way to go for u as well, but it depends on ur future plans...

Chipsterjulien commented 4 years ago

stop, it's a deaf dialogue. I waste my time answering you

hippi777 commented 4 years ago

sorry :/

kernelsauce commented 4 years ago

hippi777 is right. Turbo is a single process framework. You cant use a tight loop like that as it will never return the control to the main loop. You must use yielding or callbacks. You can use the new thread functionality however if you must use a tight loop like that to run it in a seperate thread.