= Using Ruby 1.9 Fibers to drive your apps (uWSGI >=0.9.7-dev) = In the uWSGI [wiki:Rack Rack] plugin a LoopEngine for ruby 1.9 fibers is available. Fibers are a form of coroutine, useful for implementing cooperative multitasking in your apps. === Quickstart === First of all we have to compile the uWSGI server core {{{ python uwsgiconfig --build core }}} Then we will build the rack plugin {{{ python uwsgiconfig --plugin plugins/rack core }}} (do not remove the latest 'core' arg, otherwise the world will be destroyed) If your ruby 1.9 installation is not on the system path you can force a specific ruby interpreter with: {{{ UWSGICONFIG_RUBYPATH=/opt/ruby/bin/ruby python uwsgiconfig.py --plugin plugins/rack core }}} Finally compile the fiber plugin {{{ python uwsgiconfig --plugin plugins/fiber core }}} In debian sid you can use something like this: {{{ python uwsgiconfig.py --build core UWSGICONFIG_RUBYPATH="ruby1.9.1" python uwsgiconfig.py --plugin plugins/rack core UWSGICONFIG_RUBYPATH="ruby1.9.1" python uwsgiconfig.py --plugin plugins/fiber core }}} Now we write a rack app (call it fibers.ru) that will print the first 10 numbers but suspends its execution after every iteration to allow other requests to be accepted {{{ require 'fiber' class SuspendingBody def each for i in 1..10 yield "number: #{i}\n" Fiber.yield end end end class RackFoo def call(env) [200, { 'Content-Type' => 'text/plain'}, SuspendingBody.new] end end run RackFoo.new }}} Now run uWSGI with 20 async cores (or use a higher value). This time we will a use a yaml configuration file (call it fibers.yml) {{{ uwsgi: plugins: rack, fiber socket: 127.0.0.1:3031 rack: fibers.ru post-buffering: 4096 async: 20 loop: fiber }}} Now run uWSGI {{{ ./uwsgi fibers.yml }}} == Sleeping and non-blocking-io == You can use the uWSGI api to combien fibers with non-blocking io and sleeping For sleep without blocking you use '''UWSGI.async_sleep(secs)''' function {{{ require 'fiber' class SuspendingBody def each for i in 1..10 yield "number: #{i}\n" UWSGI.async_sleep(3) Fiber.yield end end end class RackFoo def call(env) [200, { 'Content-Type' => 'text/plain'}, SuspendingBody.new] end end run RackFoo.new }}} For non-blocking-io you can use the '''async_connect''', '''wait_fd_read''', '''wait_fd_write''' The following example will async sleep 3 times then will connect to a http server and returns the output. (it is a bit complex, but should cover 99% of the uses) {{{ require 'fiber' class SuspendingBody def each for i in 1..3 yield "number: #{i}\n" UWSGI.async_sleep(1) puts "sleep..." Fiber.yield end fd = UWSGI.async_connect("81.174.68.52:80") UWSGI.wait_fd_write(fd, 3) Fiber.yield io = IO.new(fd) puts "connected" io.syswrite("GET /uwsgi/export/1081%3A362d695b2f25/plugins/fiber/fiber.c HTTP/1.0\r\n") io.syswrite("Host: projects.unbit.it\r\n") io.syswrite("\r\n") UWSGI.wait_fd_read(fd, 3) Fiber.yield puts "data available" begin while body = io.sysread(fd) yield body Fiber.yield end rescue end io.close end end class RackFoo def call(env) [200, { 'Content-Type' => 'text/plain'}, SuspendingBody.new] end end run RackFoo.new }}} == Framework support == Sinatra has been tested with fibers. You can stream response in this way (simply return an object that respond to "each" method): {{{ require 'fiber' require 'sinatra' get '/hi' do class Response def each for i in 1..10 yield "ciao
" Fiber.yield end end end Response.new end run Sinatra::Application }}} === REMEMBER !!! === Coroutines are for increasing "concurrency" of your app, they do not allow you to execute code faster !!!