Giter Club home page Giter Club logo

slowpoke's Introduction

Slowpoke

Rack::Timeout enhancements for Rails

  • safer service timeouts
  • dynamic timeouts
  • custom error pages

Build Status

Installation

Add this line to your application’s Gemfile:

gem "slowpoke"

And run:

rails generate slowpoke:install

This creates a public/503.html you can customize.

Development

To try out custom error pages in development, temporarily add to config/environments/development.rb:

config.slowpoke.timeout = 1
config.consider_all_requests_local = false

And add a sleep call to one of your actions:

sleep(2)

The custom error page should appear.

Production

The default timeout is 15 seconds. You can change this in config/environments/production.rb with:

config.slowpoke.timeout = 5

For dynamic timeouts, use:

config.slowpoke.timeout = lambda do |env|
  request = Rack::Request.new(env)
  request.path.start_with?("/admin") ? 15 : 5
end

Subscribe to timeouts with:

ActiveSupport::Notifications.subscribe "timeout.slowpoke" do |name, start, finish, id, payload|
  # report timeout
end

To learn more, see the Rack::Timeout documentation.

Safer Service Timeouts

Rack::Timeout can raise an exception at any point in the code, which can leave your app in an unclean state. The safest way to recover from a request timeout is to spawn a new process. This is the default behavior for Slowpoke.

For threaded servers like Puma, this means killing all threads when any one of them times out. This can have a significant impact on performance.

You can customize this behavior with:

Slowpoke.on_timeout do |env|
  next if Rails.env.development? || Rails.env.test?

  exception = env["action_dispatch.exception"]
  if exception && exception.backtrace.first.include?("/active_record/")
    Slowpoke.kill
  end
end

Note: To access env["action_dispatch.exception"] in development, temporarily add to config/environments/development.rb:

config.consider_all_requests_local = false

Database Timeouts

It’s a good idea to set a statement timeout and a connect timeout. For Postgres, your config/database.yml should include something like:

production:
  connect_timeout: 3 # sec
  variables:
    statement_timeout: 5s

Upgrading

0.3.0

If you set the timeout with:

Slowpoke.timeout = 5

Remove it and add to config/environments/production.rb:

config.slowpoke.timeout = 5

If you use migration timeouts, check out this guide for how to configure them directly in config/database.yml.

0.1.0

0.1.0 removes database timeouts, since Rails supports them by default. To restore the previous behavior, use:

production:
  variables:
    statement_timeout: <%= Slowpoke.timeout * 1000 %>

History

View the changelog

Contributing

Everyone is encouraged to help improve this project. Here are a few ways you can help:

To get started with development:

git clone https://github.com/ankane/slowpoke.git
cd slowpoke
bundle install
bundle exec rake test

slowpoke's People

Contributors

ankane avatar bjeanes avatar douwem avatar hundredwatt avatar joevandyk avatar jpteti avatar juanitofatas avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar

slowpoke's Issues

after timeout, my server becomes unreachable.

I am running local puma server, allowing 1 query at a time, and set the Slowpoke.timeout = 1 in the initializer.

After my first query received timeout error. my app just logs this.. and all my other query just fails with net::ERR_ADDRESS_UNREACHABLE

LOG:
...

Exiting
2015-08-27 15:39:31 -0400: Rack app error: #<ThreadError: Attempt to unlock a mutex which is locked by another thread>2015-08-27 15:39:31 -0400: Rack app error: #<ThreadError: Attempt to unlock a mutex which is locked by another thread>
/usr/local/var/rbenv/versions/2.2.3/lib/ruby/gems/2.2.0/gems/rack-1.5.5/lib/rack/lock.rb:22:in `unlock'
/usr/local/var/rbenv/versions/2.2.3/lib/ruby/gems/2.2.0/gems/rack-1.5.5/lib/rack/lock.rb:22:in `ensure in call'
/usr/local/var/rbenv/versions/2.2.3/lib/ruby/gems/2.2.0/gems/rack-1.5.5/lib/rack/lock.rb:23:in `call'
/usr/local/var/rbenv/versions/2.2.3/lib/ruby/gems/2.2.0/gems/newrelic_rpm-3.13.0.299/lib/new_relic/agent/instrumentation/middleware_tracing.rb:67:in `call'
/usr/local/var/rbenv/versions/2.2.3/lib/ruby/gems/2.2.0/gems/actionpack-4.1.12/lib/action_dispatch/middleware/static.rb:84:in `call'
/usr/local/var/rbenv/versions/2.2.3/lib/ruby/gems/2.2.0/gems/newrelic_rpm-3.13.0.299/lib/new_relic/agent/instrumentation/middleware_tracing.rb:67:in `call'
/usr/local/var/rbenv/versions/2.2.3/lib/ruby/gems/2.2.0/gems/rack-cors-0.4.0/lib/rack/cors.rb:80:in `call'
/usr/local/var/rbenv/versions/2.2.3/lib/ruby/gems/2.2.0/gems/newrelic_rpm-3.13.0.299/lib/new_relic/agent/instrumentation/middleware_tracing.rb:67:in `call'
/usr/local/var/rbenv/versions/2.2.3/lib/ruby/gems/2.2.0/gems/slowpoke-0.1.1/lib/slowpoke/middleware.rb:8:in `call'
/usr/local/var/rbenv/versions/2.2.3/lib/ruby/gems/2.2.0/gems/newrelic_rpm-3.13.0.299/lib/new_relic/agent/instrumentation/middleware_tracing.rb:67:in `call'
/usr/local/var/rbenv/versions/2.2.3/lib/ruby/gems/2.2.0/gems/railties-4.1.12/lib/rails/engine.rb:514:in `call'
/usr/local/var/rbenv/versions/2.2.3/lib/ruby/gems/2.2.0/gems/railties-4.1.12/lib/rails/application.rb:144:in `call'
/usr/local/var/rbenv/versions/2.2.3/lib/ruby/gems/2.2.0/gems/newrelic_rpm-3.13.0.299/lib/new_relic/agent/instrumentation/middleware_tracing.rb:67:in `call'
/usr/local/var/rbenv/versions/2.2.3/lib/ruby/gems/2.2.0/gems/rack-1.5.5/lib/rack/content_length.rb:14:in `call'
/usr/local/var/rbenv/versions/2.2.3/lib/ruby/gems/2.2.0/gems/puma-2.13.4/lib/puma/server.rb:541:in `handle_request'
/usr/local/var/rbenv/versions/2.2.3/lib/ruby/gems/2.2.0/gems/puma-2.13.4/lib/puma/server.rb:388:in `process_client'
/usr/local/var/rbenv/versions/2.2.3/lib/ruby/gems/2.2.0/gems/puma-2.13.4/lib/puma/server.rb:270:in `block in run'
/usr/local/var/rbenv/versions/2.2.3/lib/ruby/gems/2.2.0/gems/puma-2.13.4/lib/puma/thread_pool.rb:106:in `call'
/usr/local/var/rbenv/versions/2.2.3/lib/ruby/gems/2.2.0/gems/puma-2.13.4/lib/puma/thread_pool.rb:106:in `block in spawn_thread'2015-08-27 15:39:31 -0400: Rack app error: #<ThreadError: Attempt to unlock a mutex which is locked by another thread>
/usr/local/var/rbenv/versions/2.2.3/lib/ruby/gems/2.2.0/gems/rack-1.5.5/lib/rack/lock.rb:22:in `unlock'
/usr/local/var/rbenv/versions/2.2.3/lib/ruby/gems/2.2.0/gems/rack-1.5.5/lib/rack/lock.rb:22:in `ensure in call'
/usr/local/var/rbenv/versions/2.2.3/lib/ruby/gems/2.2.0/gems/rack-1.5.5/lib/rack/lock.rb:23:in `call'
/usr/local/var/rbenv/versions/2.2.3/lib/ruby/gems/2.2.0/gems/newrelic_rpm-3.13.0.299/lib/new_relic/agent/instrumentation/middleware_tracing.rb:67:in `call'
/usr/local/var/rbenv/versions/2.2.3/lib/ruby/gems/2.2.0/gems/actionpack-4.1.12/lib/action_dispatch/middleware/static.rb:84:in `call'
/usr/local/var/rbenv/versions/2.2.3/lib/ruby/gems/2.2.0/gems/newrelic_rpm-3.13.0.299/lib/new_relic/agent/instrumentation/middleware_tracing.rb:67:in `call'
/usr/local/var/rbenv/versions/2.2.3/lib/ruby/gems/2.2.0/gems/rack-cors-0.4.0/lib/rack/cors.rb:80:in `call'
/usr/local/var/rbenv/versions/2.2.3/lib/ruby/gems/2.2.0/gems/newrelic_rpm-3.13.0.299/lib/new_relic/agent/instrumentation/middleware_tracing.rb:67
:in `call'
/usr/local/var/rbenv/versions/2.2.3/lib/ruby/gems/2.2.0/gems/slowpoke-0.1.1/lib/slowpoke/middleware.rb:8:in `call'
/usr/local/var/rbenv/versions/2.2.3/lib/ruby/gems/2.2.0/gems/newrelic_rpm-3.13.0.299/lib/new_relic/agent/instrumentation/middleware_tracing.rb:67:in `call'
/usr/local/var/rbenv/versions/2.2.3/lib/ruby/gems/2.2.0/gems/railties-4.1.12/lib/rails/engine.rb:514:in `call'
/usr/local/var/rbenv/versions/2.2.3/lib/ruby/gems/2.2.0/gems/railties-4.1.12/lib/rails/application.rb:144:in `call'
/usr/local/var/rbenv/versions/2.2.3/lib/ruby/gems/2.2.0/gems/newrelic_rpm-3.13.0.299/lib/new_relic/agent/instrumentation/middleware_tracing.rb:67:in `call'
/usr/local/var/rbenv/versions/2.2.3/lib/ruby/gems/2.2.0/gems/rack-1.5.5/lib/rack/content_length.rb:14:in `call'
/usr/local/var/rbenv/versions/2.2.3/lib/ruby/gems/2.2.0/gems/puma-2.13.4/lib/puma/server.rb:541:in `handle_request'
/usr/local/var/rbenv/versions/2.2.3/lib/ruby/gems/2.2.0/gems/puma-2.13.4/lib/puma/server.rb:388:in `process_client'
/usr/local/var/rbenv/versions/2.2.3/lib/ruby/gems/2.2.0/gems/puma-2.13.4/lib/puma/server.rb:270:in `block in run'
/usr/local/var/rbenv/versions/2.2.3/lib/ruby/gems/2.2.0/gems/puma-2.13.4/lib/puma/thread_pool.rb:106:in `call'
/usr/local/var/rbenv/versions/2.2.3/lib/ruby/gems/2.2.0/gems/puma-2.13.4/lib/puma/thread_pool.rb:106:in `block in spawn_thread'2015-08-27 15:39:31 -0400: Rack app error: #<ThreadError: Attempt to unlock a mutex which is locked by another thread>2015-08-27 15:39:31 -0400: Rack app error: #<ThreadError: Attempt to unlock a mutex which is locked by another thread>
/usr/local/var/rbenv/versions/2.2.3/lib/ruby/gems/2.2.0/gems/rack-1.5.5/lib/rack/lock.rb:22:in `unlock'
/usr/local/var/rbenv/versions/2.2.3/lib/ruby/gems/2.2.0/gems/rack-1.5.5/lib/rack/lock.rb:22:in `ensure in call'
/usr/local/var/rbenv/versions/2.2.3/lib/ruby/gems/2.2.0/gems/rack-1.5.5/lib/rack/lock.rb:23:in `call'
/usr/local/var/rbenv/versions/2.2.3/lib/ruby/gems/2.2.0/gems/newrelic_rpm-3.13.0.299/lib/new_relic/agent/instrumentation/middleware_tracing.rb:67:in `call'
/usr/local/var/rbenv/versions/2.2.3/lib/ruby/gems/2.2.0/gems/actionpack-4.1.12/lib/action_dispatch/middleware/static.rb:84:in `call'
/usr/local/var/rbenv/versions/2.2.3/lib/ruby/gems/2.2.0/gems/newrelic_rpm-3.13.0.299/lib/new_relic/agent/instrumentation/middleware_tracing.rb:67:in `call'
/usr/local/var/rbenv/versions/2.2.3/lib/ruby/gems/2.2.0/gems/rack-cors-0.4.0/lib/rack/cors.rb:80:in `call'
/usr/local/var/rbenv/versions/2.2.3/lib/ruby/gems/2.2.0/gems/newrelic_rpm-3.13.0.299/lib/new_relic/agent/instrumentation/middleware_tracing.rb:67:in `call'
/usr/local/var/rbenv/versions/2.2.3/lib/ruby/gems/2.2.0/gems/slowpoke-0.1.1/lib/slowpoke/middleware.rb:8:in `call'
/usr/local/var/rbenv/versions/2.2.3/lib/ruby/gems/2.2.0/gems/newrelic_rpm-3.13.0.299/lib/new_relic/agent/instrumentation/middleware_tracing.rb:67:in `call'
/usr/local/var/rbenv/versions/2.2.3/lib/ruby/gems/2.2.0/gems/railties-4.1.12/lib/rails/engine.rb:514:in `call'
/usr/local/var/rbenv/versions/2.2.3/lib/ruby/gems/2.2.0/gems/railties-4.1.12/lib/rails/application.rb:144:in `call'
/usr/local/var/rbenv/versions/2.2.3/lib/ruby/gems/2.2.0/gems/newrelic_rpm-3.13.0.299/lib/new_relic/agent/instrumentation/middleware_tracing.rb:67:in `call'
/usr/local/var/rbenv/versions/2.2.3/lib/ruby/gems/2.2.0/gems/rack-1.5.5/lib/rack/content_length.rb:14:in `call'
/usr/local/var/rbenv/versions/2.2.3/lib/ruby/gems/2.2.0/gems/puma-2.13.4/lib/puma/server.rb:541:in `handle_request'
/usr/local/var/rbenv/versions/2.2.3/lib/ruby/gems/2.2.0/gems/puma-2.13.4/lib/puma/server.rb:388:in `process_client'
/usr/local/var/rbenv/versions/2.2.3/lib/ruby/gems/2.2.0/gems/puma-2.13.4/lib/puma/server.rb:270:in `block in run'
/usr/local/var/rbenv/versions/2.2.3/lib/ruby/gems/2.2.0/gems/puma-2.13.4/lib/puma/thread_pool.rb:106:in `call'
/usr/local/var/rbenv/versions/2.2.3/lib/ruby/gems/2.2.0/gems/puma-2.13.4/lib/puma/thread_pool.rb:106:in `block in spawn_thread'/usr/local/var/rbenv/versions/2.2.3/lib/ruby/gems/2.2.0/gems/rack-1.5.5/lib/rack/lock.rb:22:in `unlock'
/usr/local/var/rbenv/versions/2.2.3/lib/ruby/gems/2.2.0/gems/rack-1.5.5/lib/rack/lock.rb:22:in `ensure in call'
/usr/local/var/rbenv/versions/2.2.3/lib/ruby/gems/2.2.0/gems/rack-1.5.5/lib/rack/lock.rb:23:in `call'
/usr/local/var/rbenv/versions/2.2.3/lib/ruby/gems/2.2.0/gems/newrelic_rpm-3.13.0.299/lib/new_relic/agent/instrumentation/middleware_tracing.rb:67:in `call'
/usr/local/var/rbenv/versions/2.2.3/lib/ruby/gems/2.2.0/gems/actionpack-4.1.12/lib/action_dispatch/middleware/static.rb:84:in `call'
/usr/local/var/rbenv/versions/2.2.3/lib/ruby/gems/2.2.0/gems/newrelic_rpm-3.13.0.299/lib/new_relic/agent/instrumentation/middleware_tracing.rb:67:in `call'
/usr/local/var/rbenv/versions/2.2.3/lib/ruby/gems/2.2.0/gems/rack-cors-0.4.0/lib/rack/cors.rb:80:in `call'
/usr/local/var/rbenv/versions/2.2.3/lib/ruby/gems/2.2.0/gems/newrelic_rpm-3.13.0.299/lib/new_relic/agent/instrumentation/middleware_tracing.rb:67:i
n `call'
/usr/local/var/rbenv/versions/2.2.3/lib/ruby/gems/2.2.0/gems/slowpoke-0.1.1/lib/slowpoke/middleware.rb:8:in `call'
/usr/local/var/rbenv/versions/2.2.3/lib/ruby/gems/2.2.0/gems/newrelic_rpm-3.13.0.299/lib/new_relic/agent/instrumentation/middleware_tracing.rb:67:in `call'
/usr/local/var/rbenv/versions/2.2.3/lib/ruby/gems/2.2.0/gems/railties-4.1.12/lib/rails/engine.rb:514:in `call'
/usr/local/var/rbenv/versions/2.2.3/lib/ruby/gems/2.2.0/gems/railties-4.1.12/lib/rails/application.rb:144:in `call'
/usr/local/var/rbenv/versions/2.2.3/lib/ruby/gems/2.2.0/gems/newrelic_rpm-3.13.0.299/lib/new_relic/agent/instrumentation/middleware_tracing.rb:67:in `call'
/usr/local/var/rbenv/versions/2.2.3/lib/ruby/gems/2.2.0/gems/rack-1.5.5/lib/rack/content_length.rb:14:in `call'
/usr/local/var/rbenv/versions/2.2.3/lib/ruby/gems/2.2.0/gems/puma-2.13.4/lib/puma/server.rb:541:in `handle_request'
/usr/local/var/rbenv/versions/2.2.3/lib/ruby/gems/2.2.0/gems/puma-2.13.4/lib/puma/server.rb:388:in `process_client'
/usr/local/var/rbenv/versions/2.2.3/lib/ruby/gems/2.2.0/gems/puma-2.13.4/lib/puma/server.rb:270:in `block in run'
/usr/local/var/rbenv/versions/2.2.3/lib/ruby/gems/2.2.0/gems/puma-2.13.4/lib/puma/thread_pool.rb:106:in `call'
/usr/local/var/rbenv/versions/2.2.3/lib/ruby/gems/2.2.0/gems/puma-2.13.4/lib/puma/thread_pool.rb:106:in `block in spawn_thread'


/usr/local/var/rbenv/versions/2.2.3/lib/ruby/gems/2.2.0/gems/rack-1.5.5/lib/rack/lock.rb:22:in `unlock'
/usr/local/var/rbenv/versions/2.2.3/lib/ruby/gems/2.2.0/gems/rack-1.5.5/lib/rack/lock.rb:22:in `ensure in call'
/usr/local/var/rbenv/versions/2.2.3/lib/ruby/gems/2.2.0/gems/rack-1.5.5/lib/rack/lock.rb:23:in `call'
/usr/local/var/rbenv/versions/2.2.3/lib/ruby/gems/2.2.0/gems/newrelic_rpm-3.13.0.299/lib/new_relic/agent/instrumentation/middleware_tracing.rb:67:in `call'
/usr/local/var/rbenv/versions/2.2.3/lib/ruby/gems/2.2.0/gems/actionpack-4.1.12/lib/action_dispatch/middleware/static.rb:84:in `call'
/usr/local/var/rbenv/versions/2.2.3/lib/ruby/gems/2.2.0/gems/newrelic_rpm-3.13.0.299/lib/new_relic/agent/instrumentation/middleware_tracing.rb:67:in `call'
/usr/local/var/rbenv/versions/2.2.3/lib/ruby/gems/2.2.0/gems/rack-cors-0.4.0/lib/rack/cors.rb:80:in `call'
/usr/local/var/rbenv/versions/2.2.3/lib/ruby/gems/2.2.0/gems/newrelic_rpm-3.13.0.299/lib/new_relic/agent/instrumentation/middleware_tracing.rb:67:in `call'
/usr/local/var/rbenv/versions/2.2.3/lib/ruby/gems/2.2.0/gems/slowpoke-0.1.1/lib/slowpoke/middleware.rb:8:in `call'
/usr/local/var/rbenv/versions/2.2.3/lib/ruby/gems/2.2.0/gems/newrelic_rpm-3.13.0.299/lib/new_relic/agent/instrumentation/middleware_tracing.rb:67:in `call'
/usr/local/var/rbenv/versions/2.2.3/lib/ruby/gems/2.2.0/gems/railties-4.1.12/lib/rails/engine.rb:514:in `call'
/usr/local/var/rbenv/versions/2.2.3/lib/ruby/gems/2.2.0/gems/railties-4.1.12/lib/rails/application.rb:144:in `call'
/usr/local/var/rbenv/versions/2.2.3/lib/ruby/gems/2.2.0/gems/newrelic_rpm-3.13.0.299/lib/new_relic/agent/instrumentation/middleware_tracing.rb:67:in `call'
/usr/local/var/rbenv/versions/2.2.3/lib/ruby/gems/2.2.0/gems/rack-1.5.5/lib/rack/content_length.rb:14:in `call'
/usr/local/var/rbenv/versions/2.2.3/lib/ruby/gems/2.2.0/gems/puma-2.13.4/lib/puma/server.rb:541:in `handle_request'
/usr/local/var/rbenv/versions/2.2.3/lib/ruby/gems/2.2.0/gems/puma-2.13.4/lib/puma/server.rb:388:in `process_client'
/usr/local/var/rbenv/versions/2.2.3/lib/ruby/gems/2.2.0/gems/puma-2.13.4/lib/puma/server.rb:270:in `block in run'
/usr/local/var/rbenv/versions/2.2.3/lib/ruby/gems/2.2.0/gems/puma-2.13.4/lib/puma/thread_pool.rb:106:in `call'
/usr/local/var/rbenv/versions/2.2.3/lib/ruby/gems/2.2.0/gems/puma-2.13.4/lib/puma/thread_pool.rb:106:in `block in spawn_thread'

2015-08-27 15:39:31 -0400: Read error: #<IOError: closed stream>
/usr/local/var/rbenv/versions/2.2.3/lib/ruby/gems/2.2.0/gems/puma-2.13.4/lib/puma/reactor.rb:167:in `write'
/usr/local/var/rbenv/versions/2.2.3/lib/ruby/gems/2.2.0/gems/puma-2.13.4/lib/puma/reactor.rb:167:in `<<'
/usr/local/var/rbenv/versions/2.2.3/lib/ruby/gems/2.2.0/gems/puma-2.13.4/lib/puma/reactor.rb:167:in `block in add'
/usr/local/var/rbenv/versions/2.2.3/lib/ruby/gems/2.2.0/gems/puma-2.13.4/lib/puma/reactor.rb:165:in `synchronize'
/usr/local/var/rbenv/versions/2.2.3/lib/ruby/gems/2.2.0/gems/puma-2.13.4/lib/puma/reactor.rb:165:in `add'
/usr/local/var/rbenv/versions/2.2.3/lib/ruby/gems/2.2.0/gems/puma-2.13.4/lib/puma/server.rb:401:in `process_client'
/usr/local/var/rbenv/versions/2.2.3/lib/ruby/gems/2.2.0/gems/puma-2.13.4/lib/puma/server.rb:270:in `block in run'
/usr/local/var/rbenv/versions/2.2.3/lib/ruby/gems/2.2.0/gems/puma-2.13.4/lib/puma/thread_pool.rb:106:in `call'
/usr/local/var/rbenv/versions/2.2.3/lib/ruby/gems/2.2.0/gems/puma-2.13.4/lib/puma/thread_pool.rb:106:in `block in spawn_thread'
2015-08-27 15:39:31 -0400: Read error: #<IOError: closed stream>
/usr/local/var/rbenv/versions/2.2.3/lib/ruby/gems/2.2.0/gems/puma-2.13.4/lib/puma/reactor.rb:167:in `write'
/usr/local/var/rbenv/versions/2.2.3/lib/ruby/gems/2.2.0/gems/puma-2.13.4/lib/puma/reactor.rb:167:in `<<'
/usr/local/var/rbenv/versions/2.2.3/lib/ruby/gems/2.2.0/gems/puma-2.13.4/lib/puma/reactor.rb:167:in `block in add'
/usr/local/var/rbenv/versions/2.2.3/lib/ruby/gems/2.2.0/gems/puma-2.13.4/lib/puma/reactor.rb:165:in `synchronize'
/usr/local/var/rbenv/versions/2.2.3/lib/ruby/gems/2.2.0/gems/puma-2.13.4/lib/puma/reactor.rb:165:in `add'
/usr/local/var/rbenv/versions/2.2.3/lib/ruby/gems/2.2.0/gems/puma-2.13.4/lib/puma/server.rb:401:in `process_client'
/usr/local/var/rbenv/versions/2.2.3/lib/ruby/gems/2.2.0/gems/puma-2.13.4/lib/puma/server.rb:270:in `block in run'
/usr/local/var/rbenv/versions/2.2.3/lib/ruby/gems/2.2.0/gems/puma-2.13.4/lib/puma/thread_pool.rb:106:in `2015-08-27 15:39:31 -0400: Read error: #<IOError: closed stream>
call'
/usr/local/var/rbenv/versions/2.2.3/lib/ruby/gems/2.2.0/gems/puma-2.13.4/lib/puma/thread_pool.rb:106:in `block in spawn_thread'2015-08-27 15:39:31 -0400: Read error: #<IOError: closed stream>/usr/local/var/rbenv/versions/2.2.3/lib/ruby/gems/2.2.0/gems/puma-2.13.4/lib/puma/reactor.rb:167:in `write'
/usr/local/var/rbenv/versions/2.2.3/lib/ruby/gems/2.2.0/gems/puma-2.13.4/lib/puma/reactor.rb:167:in `<<'
/usr/local/var/rbenv/versions/2.2.3/lib/ruby/gems/2.2.0/gems/puma-2.13.4/lib/puma/reactor.rb:167:in `block in add'
/usr/local/var/rbenv/versions/2.2.3/lib/ruby/gems/2.2.0/gems/puma-2.13.4/lib/puma/reactor.rb:165:in `synchronize'
/usr/local/var/rbenv/versions/2.2.3/lib/ruby/gems/2.2.0/gems/puma-2.13.4/lib/puma/reactor.rb:165:in `add'
/usr/local/var/rbenv/versions/2.2.3/lib/ruby/gems/2.2.0/gems/puma-2.13.4/lib/puma/server.rb:401:in `process_client'
/usr/local/var/rbenv/versions/2.2.3/lib/ruby/gems/2.2.0/gems/puma-2.13.4/lib/puma/server.rb:270:in `block in run'
/usr/local/var/rbenv/versions/2.2.3/lib/ruby/gems/2.2.0/gems/puma-2.13.4/lib/puma/thread_pool.rb:106:in `call'
/usr/local/var/rbenv/versions/2.2.3/lib/ruby/gems/2.2.0/gems/puma-2.13.4/lib/puma/thread_pool.rb:106:in `block in spawn_thread'2015-08-27 15:39:31 -0400: Read error: #<IOError: closed stream>


/usr/local/var/rbenv/versions/2.2.3/lib/ruby/gems/2.2.0/gems/puma-2.13.4/lib/puma/reactor.rb:167:in `write'
/usr/local/var/rbenv/versions/2.2.3/lib/ruby/gems/2.2.0/gems/puma-2.13.4/lib/puma/reactor.rb:167:in `<<'
/usr/local/var/rbenv/versions/2.2.3/lib/ruby/gems/2.2.0/gems/puma-2.13.4/lib/puma/reactor.rb:167:in `block in add'
/usr/local/var/rbenv/versions/2.2.3/lib/ruby/gems/2.2.0/gems/puma-2.13.4/lib/puma/reactor.rb:165:in `synchronize'
/usr/local/var/rbenv/versions/2.2.3/lib/ruby/gems/2.2.0/gems/puma-2.13.4/lib/puma/reactor.rb:165:in `add'
/usr/local/var/rbenv/versions/2.2.3/lib/ruby/gems/2.2.0/gems/puma-2.13.4/lib/puma/server.rb:401:in `process_client'
/usr/local/var/rbenv/versions/2.2.3/lib/ruby/gems/2.2.0/gems/puma-2.13.4/lib/puma/server.rb:270:in `block in run'
/usr/local/var/rbenv/versions/2.2.3/lib/ruby/gems/2.2.0/gems/puma-2.13.4/lib/puma/thread_pool.rb:106:in `call'
/usr/local/var/rbenv/versions/2.2.3/lib/ruby/gems/2.2.0/gems/puma-2.13.4/lib/puma/thread_pool.rb:106:in `block in spawn_thread'

/usr/local/var/rbenv/versions/2.2.3/lib/ruby/gems/2.2.0/gems/puma-2.13.4/lib/puma/reactor.rb:167:in `write'
/usr/local/var/rbenv/versions/2.2.3/lib/ruby/gems/2.2.0/gems/puma-2.13.4/lib/puma/reactor.rb:167:in `<<'
/usr/local/var/rbenv/versions/2.2.3/lib/ruby/gems/2.2.0/gems/puma-2.13.4/lib/puma/reactor.rb:167:in `block in add'
/usr/local/var/rbenv/versions/2.2.3/lib/ruby/gems/2.2.0/gems/puma-2.13.4/lib/puma/reactor.rb:165:in `synchronize'
/usr/local/var/rbenv/versions/2.2.3/lib/ruby/gems/2.2.0/gems/puma-2.13.4/lib/puma/reactor.rb:165:in `add'
/usr/local/var/rbenv/versions/2.2.3/lib/ruby/gems/2.2.0/gems/puma-2.13.4/lib/puma/server.rb:401:in `process_client'
/usr/local/var/rbenv/versions/2.2.3/lib/ruby/gems/2.2.0/gems/puma-2.13.4/lib/puma/server.rb:270:in `block in run'
/usr/local/var/rbenv/versions/2.2.3/lib/ruby/gems/2.2.0/gems/puma-2.13.4/lib/puma/thread_pool.rb:106:in `call'
/usr/local/var/rbenv/versions/2.2.3/lib/ruby/gems/2.2.0/gems/puma-2.13.4/lib/puma/thread_pool.rb:106:in `block in spawn_thread'

Use in conjunction with Rack::Timeout?

It's not very clear from the documentation but does Slowpoke use Rack::Timeout baked in? I see that Rack::Timeout has various settings such as:

  service_timeout:   15,     # ENV["RACK_TIMEOUT_SERVICE_TIMEOUT"]
  wait_timeout:      30,     # ENV["RACK_TIMEOUT_WAIT_TIMEOUT"]
  wait_overtime:     60,     # ENV["RACK_TIMEOUT_WAIT_OVERTIME"]
  service_past_wait: false,  # ENV["RACK_TIMEOUT_SERVICE_PAST_WAIT"]
  term_on_timeout:   false   # ENV["RACK_TIMEOUT_TERM_ON_TIMEOUT"]

but I don't know if Slowpoke also catches these. From briefly reviewing your code it doesn't look like that's the case. Any guidance or best practice advice is much appreciated. Thank you.

Release 0.2.1?

We had trouble with Slowpoke on our CI server. I see this is fixed on master (9c0c677) but not in a released gem.

When you get a chance @ankane, could you release 0.2.1?

Thanks!

Any plan to update with latest rack-timeout?

@ankane thanks for this gem and awesome documentation on ruby timeouts.

This is more of a query than a bug.

The newer version of rack-timeout seems to have changed a lot (looking at the file list) and the API also has changed (timeout is now service_timeout, setting the timeouts via middleware seems to be the preferred option)
I wanted to know if you the issue mentioned in zombocom/rack-timeout#39 still exist? Are there any better ways of handling it today?

Documentation missing

Hi

I'm trying to get slowpoke to work with my rails app.

in the documentation it says:

The default timeout is 15 seconds. Change this with:

Slowpoke.timeout = 10

But where do I set this? If I set it in application.rb it says that Slowpoke is not known, and the same happens in an initializer.

Clarification on Safer Service Timeouts

In the readme it seems to imply that when using Puma a timeout will kill the process and all the threads. However is that still the case when you're sending TERM to the process which is supposed to "the worker will attempt to finish then exit" ? And if that's the case, what advantages are there from only killing processes if it's within an ActiveRecord code execution?

Thanks for your time.

rake db:migrate does not use the correct timeout

I am using rails 4.1, in my database.yml

development:
  adapter: postgresql
  encoding: unicode
  database: socialsift_development
  pool: 25
  variables:
    statement_timeout: 3000

When I run a migration longer than 3 s, it will fail due to statement_timeout. Even if I set MIGRATION_STATEMENT_TIMEOUT=0 in my env, it still fails after 3 second.

Usage with Rails API-only projects

Hi @ankane, thank you for putting this out. Given that the library generates pages, is this compatible with Rails in API-mode that strips out most of the relevant middleware for that?

PostgreSQL timeouts

Hi @ankane,
So, is it possible to catch the db timeout with gem? Using Heroku.
I've added

production:
  variables:
    statement_timeout: <%= Slowpoke.timeout * 1000 %>

And initializator has

Slowpoke.timeout = 29

But application raises 500 (instead of 503) with PG::QueryCanceled: ERROR: canceling statement due to statement timeout

Any suggestions?
Thanks!

Restarting Passenger process

Slowpoke is Unicorn specific when it comes to restarting application process.
To be able to cleanly restart aplication process managed by Passenger (5.0.x) I nedded to modify my initializer

if defined?(::PhusionPassenger)
  Rack::Timeout.unregister_state_change_observer(:slowpoke)

  Rack::Timeout.register_state_change_observer(:passenger_killer) do |env|
    case env[Rack::Timeout::ENV_INFO_KEY].state
      when :timed_out       
        `passenger-config detach-process #{Process.pid}`
    end
  end
end

Slowpoke on Puma

We recently tried introducing request timeouts for our Rails application using the Rack::Timeout gem which resulted in a couple of issues. After some more research, we discovered Slowpoke which seems to be more stable in our use case but whenever a request runs into the timeout, Puma doesn't seem to be killed correctly. We see a log "Gracefully stopping, waiting for requests to finish" indicating that Puma is shutting down but the application is not terminated.
How should we best handle this case?

Our setup is as follows:

  • JRuby 9.3.4.0
  • Rails 6.1.7.2
  • Puma 6.2.1

Note: We run Puma with only one worker

Any help would be very much appreciated

Subscribing to timeout notification but still fetching the exception

I realize that ActiveSupport's Notifications are just meant to instrument and subscribe to events, but since you're swallowing Rack Timeout's RequestTimeoutException, I am not sure how to grab the exception from a timeout and pass it to new relic. Previously, with Rack Timeout I could do this:

    rescue_from Rack::Timeout::RequestTimeoutException do |exception|
      Rails.logger.debug exception.message
      Rails.logger.debug exception.backtrace[0..20].join("\n")
      NewRelic::Agent.notice_error exception, custom_params: custom_new_relic_params
      # ...
      another_custom_method(exception)
    end

But now, with slowpoke, since the subscribing to the event doesn't give me the exception, what would you recommend? Since we're using this all api based and not using the customer 503 page, is there anyway to turn off your rescuing of the Rack::Timeout::RequestTimeoutException so that I can catch it myself?

This is what we've got so far:

    ActiveSupport::Notifications.subscribe "timeout.slowpoke" do |name, start, finish, id, payload|
      Rails.logger.debug name
      Rails.logger.debug payload
      # ... 
    end

MIGRATION_STATEMENT_TIMEOUT=0 and multiple migration

I have on my environment MIGRATION_STATEMENT_TIMEOUT=0 so my migration do not get a timeout.

But it seems I can not pass two migrations at the same time with this environement variable set.

Here is the error I get:

PG::ConnectionBad: connection is closed: ROLLBACK

Any ideas ?

Thanks.

No method error for Rack::Timeout

I'm getting this error when building production container, slowpoke 0.2.0 and master branch tested.

It seems Rack::Timeout just removed those methods from their 0.5.0 release zombocom/rack-timeout@eaba89e.

Downgrade Rack::Timeout to 0.4.2 solve the problem.

NoMethodError: undefined method `service_timeout=' for Rack::Timeout:Class
/usr/local/bundle/bundler/gems/slowpoke-2035bccce534/lib/slowpoke/railtie.rb:4:in `block in <class:Railtie>'
/usr/local/bundle/gems/railties-5.1.6/lib/rails/initializable.rb:30:in `instance_exec'
/usr/local/bundle/gems/railties-5.1.6/lib/rails/initializable.rb:30:in `run'
/usr/local/bundle/gems/railties-5.1.6/lib/rails/initializable.rb:59:in `block in run_initializers'
/usr/local/bundle/gems/railties-5.1.6/lib/rails/initializable.rb:58:in `run_initializers'
/usr/local/bundle/gems/railties-5.1.6/lib/rails/application.rb:353:in `initialize!'
/app/config/environment.rb:5:in `<main>'

Does this handle Puma?

I see that it sends Process.kill "QUIT" when it times out. It looks like you have to "TERM" to gracefully shutdown. Am I misunderstanding this or will this not work with Puma?

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.