#129 ✓resolved
Matt Aimonetti (mattetti)

timeout doesn't seem to work properly

Reported by Matt Aimonetti (mattetti) | March 13th, 2010 @ 12:27 PM

require 'thin'
require 'sequel'

app = proc do |env|
  body = ['should not display!']
   db = Sequel.connect('mysql://root@localhost:3306/test')
   db.execute("select sleep(15)")
  
  
  [
    200,                                        # Status code
    { 'Content-Type' => 'text/html' },          # Reponse headers
    body                                        # Body of the response
  ]
end

Start as:

$ thin start -R timeout_test.ru -t 2

And try to load localhost:3000, in theory the request should timeout since the timeout limit is set to 2 seconds and the query will take 15s.

Tested against Thin 1.2.6 with Ruby 1.9 and 1.2.2 on Ruby 1.8.7

Comments and changes to this ticket

  • macournoyer

    macournoyer March 16th, 2010 @ 02:23 PM

    • State changed from “new” to “resolved”
    • Tag set to timeout

    Hey Matt,

    This is because the timeout is handled at the connection level by EventMachine. Since Thin is single-threaded and the db.execute line is blocking the whole process, the control is never given back to EM during the whole time the proc executes.

    Using a non-blocking MySQL driver could solve that issue (like I presented at Confoo) as it would give back the control to EM after sending the query, and before receiving the results.

    Long story short... the solution is to use ruby Timeout module (or better, SystemTimer gem):

    require 'thin'
    require 'sequel'
    require 'system_timer'
    
    DB = Sequel.connect('mysql://root@localhost:3306/talker_development')
    
    app = proc do |env|
      body = ['should not display!']
      
      puts "Sending db query..."
      SystemTimer.timeout_after(2) do
        DB.execute("select sleep(15)")
        puts "Got db results!"
      end
    
      [
        200,                                        # Status code
        { 'Content-Type' => 'text/html' },          # Reponse headers
        body                                        # Body of the response
      ]
    end
    
    run app
    

    Let me know if something is not clear.

  • Matt Aimonetti (mattetti)

    Matt Aimonetti (mattetti) March 16th, 2010 @ 03:20 PM

    Thanks Marc André, the problem is that when using Rails, you can't easily setup a timeout, I guess I could write a middleware that would automatically timeout my requests but it would be nice to have thin handle that for us. I believe passenger has this option too, I don't know about the other webservers.

    Thanks again for looking into this

  • macournoyer

    macournoyer March 16th, 2010 @ 03:34 PM

    hmm right, I'll think about replacing Thin's timeout logic w/ SystemTimer...

    in the meantime, this middleware will do the trick:

    require 'system_timer'
    
    class Timeout
      def initialize(app, sec)
        @app = app
        @sec = sec
      end
      
      def call(env)
        SystemTimer.timeout_after(@sec) { @app.call(env) }
      end
    end
    

Please Sign in or create a free account to add a new ticket.

With your very own profile, you can contribute to projects, track your activity, watch tickets, receive and update tickets through your email and much more.

New-ticket Create new ticket

Create your profile

Help contribute to this project by taking a few moments to create your personal profile. Create your profile »

People watching this ticket

Tags

Pages