Comments (7)
Hello and thank you for your thoughts and your test app!
I believe the default behavior is what people expect from historical versions of Rack Timeout: just raise an exception but continue on. I believe the TERM
behavior is something that people should opt-into as it's highly dependent on the nature of your production environment. Additionally, while the application may enter a bad state when using Rails + ActiveRecord, the middleware does not know what you are using -- your app might only be making network calls, for instance. If you find that you are aborting database calls with Rack Timeout that might be a good indication that you should try setting a database-level timeout, like statement_timeout
in Postgres.
from rack-timeout.
I think injecting unexpected scope can be a possibility of vulnerability stuff.
# Might be BlockedUser.where(user_id: timed_out_request_user_id).where(user_id: current_user.id).count after time out
if BlockedUser.where(user_id: current_user.id).count == 0
# Run something
end
Of course I respect your, rack-timeout and puma maintainer's opinion.
I just want you to know the possibility and I felt it's underestimated.
from rack-timeout.
@wuputah Thank you for responding.
I understand it's difficult to change the default behavior.
What do you think about showing warn if term_on_timeout
is false?
As you can see on above example, active record scope which used just before timeout is injected into all other scopes.
User.count
will be User.where(name: "foo").count
even it's written as User.count
.
I think it's so terrible and really difficult to be aware.
from rack-timeout.
@mtsmfm rails/rails#41356 was recently merged, does that change anything for you?
I'm not sure about warning on term_on_timeout: false
, what should it say? That you should opt-in to the TERM
behavior?
Why and how rack-timeout is used in an application, should be a well thought out decision by the application developers. Maybe rack-timeout should have a warning by default, "Are you really sure you need to use rack-timeout and do you understand the consequences?" Something similar to parallel --citation
. Hehe.
from rack-timeout.
rails/rails#41356 was recently merged, does that change anything for you?
No, the test I showed still fails.
# Running:
F
Failure:
BugTest#test_index [bar.rb:84]:
--- expected
+++ actual
@@ -1 +1,3 @@
-"2"
+# encoding: ASCII-8BIT
+# valid: true
+"1"
Entire code (just changes gem "rails" line)
require "bundler/inline"
gemfile do
source "https://rubygems.org"
gem "rails", github: "rails/rails", ref: "main"
gem "sqlite3"
gem "rack-timeout", require: "rack/timeout/base"
end
require "rack/test"
require "active_record/railtie"
require "action_controller/railtie"
ActiveRecord::Base.establish_connection(adapter: "sqlite3", database: ":memory:")
ActiveRecord::Base.logger = Logger.new(File::NULL)
ActiveRecord::Base.logger.level = Logger::ERROR
ActiveRecord::Schema.define do
create_table :users, force: true do |t|
t.string :name
end
end
class User < ActiveRecord::Base
scope :sleep_a_while, -> { all.tap { sleep(rand / 1000000.0) } }
end
User.create!(name: "foo")
User.create!(name: "bar")
class TestApp < Rails::Application
config.root = __dir__
config.hosts << "example.org"
config.session_store :cookie_store, key: "cookie_store_key"
secrets.secret_key_base = "secret_key_base"
config.logger = ActiveRecord::Base.logger
Rails.logger = config.logger
config.middleware.insert_before Rack::Runtime, Rack::Timeout, service_timeout: 0.1
config.exceptions_app = ->(*) { [500, {}, ['']] }
routes.draw do
get "/" => "test#index"
get "/timeout" => "test#timeout"
end
end
class TestController < ActionController::Base
include Rails.application.routes.url_helpers
def index
render plain: User.count
end
def timeout
loop do
User.where(name: "foo").sleep_a_while
end
end
end
require "minitest/autorun"
class BugTest < Minitest::Test
include Rack::Test::Methods
def test_index
get "/"
# Make sure User.count is 2
assert_equal "2", last_response.body
until last_response.body == "1"
get "/timeout"
get "/"
end
get "/"
# User.count must be always 2 but it's now 1
assert_equal "2", last_response.body
end
private
def app
Rails.application
end
end
Why and how rack-timeout is used in an application, should be a well thought out decision by the application developers.
Agree. But I hope the library uses safer option by default if it has.
In addition, if my understanding is correct:
- Puma doesn't have request timeout mechanism so rack-timeout is de facto standard gem to stop not only DB query but also CPU heavy processing
- Heroku had recommended to use rack-timeout without notice
I know application developers must investigate why a request timed out.
But we can't make sure every endpoint can respond fast enough before deploying.
rack-timeout can work as a safety valve I think.
rack-timeout can't cause any problem if we use application server with multi process mode and term_on_timeout: true
.
I just hope this gem is safe by default or has a caution if it's not safe by default despite it has safe option.
from rack-timeout.
rack-timeout can't cause any problem if we use application server with multi process mode and
term_on_timeout: true
Agree, but this gem can't know if your app server is using multiple processes...
As an example, Puma is not doing that by default – so then it wouldn't be a safe default IMHO
from rack-timeout.
Puma is not doing that by default
Yes, and it's also difficult to change I guess.
That's why I proposed to show warning on term_on_timeout: false
.
from rack-timeout.
Related Issues (20)
- Improve rack-timeout docs to map raised exceptions to desired status code HOT 11
- Request still running/completing after timeout? HOT 5
- Broken ActiveRecord connections after a timeout HOT 4
- Detect if the middleware is already loaded and prevent it from being loaded twice HOT 9
- Unicorn graceful shutdown seems incompatible with `TERM` usage HOT 4
- Push 0.6.1 to Rubygems HOT 4
- Prefer sending SIGKILL over SIGTERM to a process HOT 2
- is "active" observer turned off for non-debug? HOT 5
- PR needed/wanted: Incompatibility with Ruby on Windows HOT 1
- [Feature Request] Optionally notify observers only HOT 4
- Request: timeout exempt requests HOT 1
- problem with unicorn graceful restart HOT 2
- possibility to timeout only for GET requests ? HOT 1
- Puma and rack-timeout results in a null pointer after running for some time HOT 1
- Disable logging HOT 4
- ArgumentError: wrong number of arguments (given 2, expected 1) with Ruby 3.2.2 and Rails 6.1.4 HOT 2
- Question: RACK_TIMEOUT_TERM_ON_TIMEOUT on one cluster HOT 1
- RACK_TIMEOUT_TERM_ON_TIMEOUT=0 still does not allow TruffleRuby to run HOT 2
- Dynamic service_timeout HOT 2
Recommend Projects
-
React
A declarative, efficient, and flexible JavaScript library for building user interfaces.
-
Vue.js
🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.
-
Typescript
TypeScript is a superset of JavaScript that compiles to clean JavaScript output.
-
TensorFlow
An Open Source Machine Learning Framework for Everyone
-
Django
The Web framework for perfectionists with deadlines.
-
Laravel
A PHP framework for web artisans
-
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.
-
Visualization
Some thing interesting about visualization, use data art
-
Game
Some thing interesting about game, make everyone happy.
Recommend Org
-
Facebook
We are working to build community through open source technology. NB: members must have two-factor auth.
-
Microsoft
Open source projects and samples from Microsoft.
-
Google
Google ❤️ Open Source for everyone.
-
Alibaba
Alibaba Open Source for everyone
-
D3
Data-Driven Documents codes.
-
Tencent
China tencent open source team.
from rack-timeout.