rack-timeout 0.4.0 → 0.6.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +5 -5
- data/{CHANGELOG → CHANGELOG.md} +41 -0
- data/Gemfile +3 -0
- data/README.md +118 -0
- data/Rakefile +16 -0
- data/UPGRADING.md +19 -0
- data/doc/exceptions.md +24 -0
- data/doc/logging.md +41 -0
- data/doc/observers.md +22 -0
- data/doc/request-lifecycle.md +27 -0
- data/doc/risks.md +35 -0
- data/doc/rollbar.md +30 -0
- data/doc/settings.md +101 -0
- data/lib/rack/timeout/core.rb +45 -16
- data/lib/rack/timeout/logger.rb +0 -1
- data/lib/rack/timeout/logging-observer.rb +4 -1
- data/lib/rack/timeout/rails.rb +7 -2
- data/lib/rack/timeout/rollbar.rb +1 -53
- data/lib/rack/timeout/support/monotonic_time.rb +0 -1
- data/lib/rack/timeout/support/scheduler.rb +6 -1
- data/lib/rack/timeout/support/timeout.rb +0 -1
- data/lib/rack-timeout.rb +1 -1
- data/test/basic_test.rb +23 -0
- data/test/env_settings_test.rb +27 -0
- data/test/test_helper.rb +45 -0
- metadata +73 -12
- data/README.markdown +0 -319
- data/lib/rack/timeout/legacy.rb +0 -46
data/lib/rack/timeout/core.rb
CHANGED
@@ -3,7 +3,6 @@ require "securerandom"
|
|
3
3
|
require_relative "support/monotonic_time"
|
4
4
|
require_relative "support/scheduler"
|
5
5
|
require_relative "support/timeout"
|
6
|
-
require_relative "legacy"
|
7
6
|
|
8
7
|
module Rack
|
9
8
|
class Timeout
|
@@ -31,6 +30,7 @@ module Rack
|
|
31
30
|
:service, # time rack spent processing the request (updated ~ every second)
|
32
31
|
:timeout, # the actual computed timeout to be used for this request
|
33
32
|
:state, # the request's current state, see VALID_STATES below
|
33
|
+
:term,
|
34
34
|
) {
|
35
35
|
def ms(k) # helper method used for formatting values in milliseconds
|
36
36
|
"%.fms" % (self[k] * 1000) if self[k]
|
@@ -43,14 +43,18 @@ module Rack
|
|
43
43
|
:timed_out, # This request has run for too long and we're raising a timeout error in it
|
44
44
|
:completed, # We're done with this request (also set after having timed out a request)
|
45
45
|
]
|
46
|
-
ENV_INFO_KEY = "rack-timeout.info" # key under which each request's RequestDetails instance is stored in its env.
|
46
|
+
ENV_INFO_KEY = "rack-timeout.info".freeze # key under which each request's RequestDetails instance is stored in its env.
|
47
|
+
HTTP_X_REQUEST_ID = "HTTP_X_REQUEST_ID".freeze # key where request id is stored if generated by upstream client/proxy
|
48
|
+
ACTION_DISPATCH_REQUEST_ID = "action_dispatch.request_id".freeze # key where request id is stored if generated by action dispatch
|
47
49
|
|
48
50
|
# helper methods to read timeout properties. Ensure they're always positive numbers or false. When set to false (or 0), their behaviour is disabled.
|
49
51
|
def read_timeout_property value, default
|
50
52
|
case value
|
51
|
-
when nil ; default
|
53
|
+
when nil ; read_timeout_property default, default
|
52
54
|
when false ; false
|
53
55
|
when 0 ; false
|
56
|
+
when String
|
57
|
+
read_timeout_property value.to_i, default
|
54
58
|
else
|
55
59
|
value.is_a?(Numeric) && value > 0 or raise ArgumentError, "value #{value.inspect} should be false, zero, or a positive number."
|
56
60
|
value
|
@@ -61,13 +65,21 @@ module Rack
|
|
61
65
|
:service_timeout, # How long the application can take to complete handling the request once it's passed down to it.
|
62
66
|
:wait_timeout, # How long the request is allowed to have waited before reaching rack. If exceeded, the request is 'expired', i.e. dropped entirely without being passed down to the application.
|
63
67
|
:wait_overtime, # Additional time over @wait_timeout for requests with a body, like POST requests. These may take longer to be received by the server before being passed down to the application, but should not be expired.
|
64
|
-
:service_past_wait
|
65
|
-
|
66
|
-
|
67
|
-
|
68
|
-
@
|
69
|
-
@
|
70
|
-
@
|
68
|
+
:service_past_wait, # when false, reduces the request's computed timeout from the service_timeout value if the complete request lifetime (wait + service) would have been longer than wait_timeout (+ wait_overtime when applicable). When true, always uses the service_timeout value. we default to false under the assumption that the router would drop a request that's not responded within wait_timeout, thus being there no point in servicing beyond seconds_service_left (see code further down) up until service_timeout.
|
69
|
+
:term_on_timeout
|
70
|
+
|
71
|
+
def initialize(app, service_timeout:nil, wait_timeout:nil, wait_overtime:nil, service_past_wait:"not_specified", term_on_timeout: nil)
|
72
|
+
@term_on_timeout = read_timeout_property term_on_timeout, ENV.fetch("RACK_TIMEOUT_TERM_ON_TIMEOUT", false)
|
73
|
+
@service_timeout = read_timeout_property service_timeout, ENV.fetch("RACK_TIMEOUT_SERVICE_TIMEOUT", 15).to_i
|
74
|
+
@wait_timeout = read_timeout_property wait_timeout, ENV.fetch("RACK_TIMEOUT_WAIT_TIMEOUT", 30).to_i
|
75
|
+
@wait_overtime = read_timeout_property wait_overtime, ENV.fetch("RACK_TIMEOUT_WAIT_OVERTIME", 60).to_i
|
76
|
+
@service_past_wait = service_past_wait == "not_specified" ? ENV.fetch("RACK_TIMEOUT_SERVICE_PAST_WAIT", false).to_s != "false" : service_past_wait
|
77
|
+
|
78
|
+
Thread.main['RACK_TIMEOUT_COUNT'] ||= 0
|
79
|
+
if @term_on_timeout
|
80
|
+
raise "term_on_timeout must be an integer but is #{@term_on_timeout.class}: #{@term_on_timeout}" unless @term_on_timeout.is_a?(Numeric)
|
81
|
+
raise "Current Runtime does not support processes" unless ::Process.respond_to?(:fork)
|
82
|
+
end
|
71
83
|
@app = app
|
72
84
|
end
|
73
85
|
|
@@ -75,7 +87,7 @@ module Rack
|
|
75
87
|
RT = self # shorthand reference
|
76
88
|
def call(env)
|
77
89
|
info = (env[ENV_INFO_KEY] ||= RequestDetails.new)
|
78
|
-
info.id ||= env[
|
90
|
+
info.id ||= env[HTTP_X_REQUEST_ID] || env[ACTION_DISPATCH_REQUEST_ID] || SecureRandom.uuid
|
79
91
|
|
80
92
|
time_started_service = Time.now # The wall time the request started being processed by rack
|
81
93
|
ts_started_service = fsecs # The monotonic time the request started being processed by rack
|
@@ -89,7 +101,9 @@ module Rack
|
|
89
101
|
seconds_waited = 0 if seconds_waited < 0 # make up for potential time drift between the routing server and the application server
|
90
102
|
final_wait_timeout = wait_timeout + effective_overtime # how long the request will be allowed to have waited
|
91
103
|
seconds_service_left = final_wait_timeout - seconds_waited # first calculation of service timeout (relevant if request doesn't get expired, may be overriden later)
|
92
|
-
info.wait
|
104
|
+
info.wait = seconds_waited # updating the info properties; info.timeout will be the wait timeout at this point
|
105
|
+
info.timeout = final_wait_timeout
|
106
|
+
|
93
107
|
if seconds_service_left <= 0 # expire requests that have waited for too long in the queue (as they are assumed to have been dropped by the web server / routing layer at this point)
|
94
108
|
RT._set_state! env, :expired
|
95
109
|
raise RequestExpiryError.new(env), "Request older than #{info.ms(:timeout)}."
|
@@ -102,7 +116,7 @@ module Rack
|
|
102
116
|
# compute actual timeout to be used for this request; if service_past_wait is true, this is just service_timeout. If false (the default), and wait time was determined, we'll use the shortest value between seconds_service_left and service_timeout. See comment above at service_past_wait for justification.
|
103
117
|
info.timeout = service_timeout # nice and simple, when service_past_wait is true, not so much otherwise:
|
104
118
|
info.timeout = seconds_service_left if !service_past_wait && seconds_service_left && seconds_service_left > 0 && seconds_service_left < service_timeout
|
105
|
-
|
119
|
+
info.term = term_on_timeout
|
106
120
|
RT._set_state! env, :ready # we're good to go, but have done nothing yet
|
107
121
|
|
108
122
|
heartbeat_event = nil # init var so it's in scope for following proc
|
@@ -115,7 +129,22 @@ module Rack
|
|
115
129
|
|
116
130
|
timeout = RT::Scheduler::Timeout.new do |app_thread| # creates a timeout instance responsible for timing out the request. the given block runs if timed out
|
117
131
|
register_state_change.call :timed_out
|
118
|
-
|
132
|
+
|
133
|
+
message = "Request "
|
134
|
+
message << "waited #{info.ms(:wait)}, then " if info.wait
|
135
|
+
message << "ran for longer than #{info.ms(:timeout)} "
|
136
|
+
if term_on_timeout
|
137
|
+
Thread.main['RACK_TIMEOUT_COUNT'] += 1
|
138
|
+
|
139
|
+
if Thread.main['RACK_TIMEOUT_COUNT'] >= @term_on_timeout
|
140
|
+
message << ", sending SIGTERM to process #{Process.pid}"
|
141
|
+
Process.kill("SIGTERM", Process.pid)
|
142
|
+
else
|
143
|
+
message << ", #{Thread.main['RACK_TIMEOUT_COUNT']}/#{term_on_timeout} timeouts allowed before SIGTERM for process #{Process.pid}"
|
144
|
+
end
|
145
|
+
end
|
146
|
+
|
147
|
+
app_thread.raise(RequestTimeoutException.new(env), message)
|
119
148
|
end
|
120
149
|
|
121
150
|
response = timeout.timeout(info.timeout) do # perform request with timeout
|
@@ -146,8 +175,9 @@ module Rack
|
|
146
175
|
# This is a code extraction for readability, this method is only called from a single point.
|
147
176
|
RX_NGINX_X_REQUEST_START = /^(?:t=)?(\d+)\.(\d{3})$/
|
148
177
|
RX_HEROKU_X_REQUEST_START = /^(\d+)$/
|
178
|
+
HTTP_X_REQUEST_START = "HTTP_X_REQUEST_START".freeze
|
149
179
|
def self._read_x_request_start(env)
|
150
|
-
return unless s = env[
|
180
|
+
return unless s = env[HTTP_X_REQUEST_START]
|
151
181
|
return unless m = s.match(RX_HEROKU_X_REQUEST_START) || s.match(RX_NGINX_X_REQUEST_START)
|
152
182
|
Time.at(m[1,2].join.to_f / 1000)
|
153
183
|
end
|
@@ -189,6 +219,5 @@ module Rack
|
|
189
219
|
def self.notify_state_change_observers(env)
|
190
220
|
@state_change_observers.values.each { |observer| observer.call(env) }
|
191
221
|
end
|
192
|
-
|
193
222
|
end
|
194
223
|
end
|
data/lib/rack/timeout/logger.rb
CHANGED
@@ -8,6 +8,9 @@ class Rack::Timeout::StateChangeLoggingObserver
|
|
8
8
|
:timed_out => :error,
|
9
9
|
:completed => :info,
|
10
10
|
}
|
11
|
+
def initialize
|
12
|
+
@logger = nil
|
13
|
+
end
|
11
14
|
|
12
15
|
# returns the Proc to be used as the observer callback block
|
13
16
|
def callback
|
@@ -45,9 +48,9 @@ class Rack::Timeout::StateChangeLoggingObserver
|
|
45
48
|
s << " wait=" << info.ms(:wait) if info.wait
|
46
49
|
s << " timeout=" << info.ms(:timeout) if info.timeout
|
47
50
|
s << " service=" << info.ms(:service) if info.service
|
51
|
+
s << " term_on_timeout=" << info.term.to_s if info.term
|
48
52
|
s << " state=" << info.state.to_s if info.state
|
49
53
|
s
|
50
54
|
end
|
51
55
|
end
|
52
|
-
|
53
56
|
end
|
data/lib/rack/timeout/rails.rb
CHANGED
@@ -3,6 +3,11 @@ require_relative "base"
|
|
3
3
|
class Rack::Timeout::Railtie < Rails::Railtie
|
4
4
|
initializer("rack-timeout.prepend") do |app|
|
5
5
|
next if Rails.env.test?
|
6
|
-
|
6
|
+
|
7
|
+
if defined?(ActionDispatch::RequestId)
|
8
|
+
app.config.middleware.insert_after(ActionDispatch::RequestId, Rack::Timeout)
|
9
|
+
else
|
10
|
+
app.config.middleware.insert_before(Rack::Runtime, Rack::Timeout)
|
11
|
+
end
|
7
12
|
end
|
8
|
-
end
|
13
|
+
end
|
data/lib/rack/timeout/rollbar.rb
CHANGED
@@ -1,53 +1 @@
|
|
1
|
-
|
2
|
-
|
3
|
-
# Groups timeout exceptions in rollbar by exception class, http method, and url.
|
4
|
-
#
|
5
|
-
# Usage: after requiring rollbar (say, in your rollbar initializer file), call:
|
6
|
-
#
|
7
|
-
# require "rack/timeout/rollbar"
|
8
|
-
#
|
9
|
-
# Ruby 2.0 is required as we use `Module.prepend`.
|
10
|
-
#
|
11
|
-
# To use a custom fingerprint for grouping:
|
12
|
-
#
|
13
|
-
# Rack::Timeout::Rollbar.fingerprint do |exception, env|
|
14
|
-
# # … return some kind of string derived from exception and env
|
15
|
-
# end
|
16
|
-
|
17
|
-
module Rack::Timeout::Rollbar
|
18
|
-
|
19
|
-
def self.fingerprint(&block)
|
20
|
-
define_method(:rack_timeout_fingerprint) { |exception, env| block[exception, env] }
|
21
|
-
end
|
22
|
-
|
23
|
-
def self.default_rack_timeout_fingerprint(exception, env)
|
24
|
-
request = ::Rack::Request.new(env)
|
25
|
-
[ exception.class.name,
|
26
|
-
request.request_method,
|
27
|
-
request.path
|
28
|
-
].join(" ")
|
29
|
-
end
|
30
|
-
|
31
|
-
fingerprint &method(:default_rack_timeout_fingerprint)
|
32
|
-
|
33
|
-
|
34
|
-
def build_payload(level, message, exception, extra)
|
35
|
-
payload = super(level, message, exception, extra)
|
36
|
-
|
37
|
-
return payload unless exception.is_a?(::Rack::Timeout::ExceptionWithEnv) \
|
38
|
-
&& payload.respond_to?(:[]) \
|
39
|
-
&& payload.respond_to?(:[]=)
|
40
|
-
|
41
|
-
data = payload["data"]
|
42
|
-
return payload unless data.respond_to?(:[]=)
|
43
|
-
|
44
|
-
payload = payload.dup
|
45
|
-
data = data.dup
|
46
|
-
data["fingerprint"] = rack_timeout_fingerprint(exception, exception.env)
|
47
|
-
payload["data"] = data
|
48
|
-
|
49
|
-
return payload
|
50
|
-
end
|
51
|
-
end
|
52
|
-
|
53
|
-
::Rollbar::Notifier.prepend ::Rack::Timeout::Rollbar
|
1
|
+
warn 'DEPRECATION WARNING: The Rollbar module was removed from rack-timeout. For more details check the README on heroku/rack-timeout'
|
@@ -21,6 +21,11 @@ class Rack::Timeout::Scheduler
|
|
21
21
|
|
22
22
|
# stores a proc to run later, and the time it should run at
|
23
23
|
class RunEvent < Struct.new(:monotime, :proc)
|
24
|
+
def initialize(*args)
|
25
|
+
@cancelled = false
|
26
|
+
super(*args)
|
27
|
+
end
|
28
|
+
|
24
29
|
def cancel!
|
25
30
|
@cancelled = true
|
26
31
|
end
|
@@ -51,6 +56,7 @@ class Rack::Timeout::Scheduler
|
|
51
56
|
end
|
52
57
|
|
53
58
|
def initialize
|
59
|
+
@runner = nil
|
54
60
|
@events = [] # array of `RunEvent`s
|
55
61
|
@mx_events = Mutex.new # mutex to change said array
|
56
62
|
@mx_runner = Mutex.new # mutex for creating a runner thread
|
@@ -145,5 +151,4 @@ class Rack::Timeout::Scheduler
|
|
145
151
|
instance_methods(false).each do |m|
|
146
152
|
define_singleton_method(m) { |*a, &b| singleton.send(m, *a, &b) }
|
147
153
|
end
|
148
|
-
|
149
154
|
end
|
data/lib/rack-timeout.rb
CHANGED
@@ -1,2 +1,2 @@
|
|
1
1
|
require_relative "rack/timeout/base"
|
2
|
-
require_relative "rack/timeout/rails" if defined?(Rails) && [3,4].include?(Rails::VERSION::MAJOR)
|
2
|
+
require_relative "rack/timeout/rails" if defined?(Rails) && [3,4,5,6].include?(Rails::VERSION::MAJOR)
|
data/test/basic_test.rb
ADDED
@@ -0,0 +1,23 @@
|
|
1
|
+
require "test_helper"
|
2
|
+
|
3
|
+
class BasicTest < RackTimeoutTest
|
4
|
+
def test_ok
|
5
|
+
self.settings = { service_timeout: 1 }
|
6
|
+
get "/"
|
7
|
+
assert last_response.ok?
|
8
|
+
end
|
9
|
+
|
10
|
+
def test_timeout
|
11
|
+
self.settings = { service_timeout: 1 }
|
12
|
+
assert_raises(Rack::Timeout::RequestTimeoutError) do
|
13
|
+
get "/sleep"
|
14
|
+
end
|
15
|
+
end
|
16
|
+
|
17
|
+
def test_wait_timeout
|
18
|
+
self.settings = { service_timeout: 1, wait_timeout: 15 }
|
19
|
+
assert_raises(Rack::Timeout::RequestExpiryError) do
|
20
|
+
get "/", "", 'HTTP_X_REQUEST_START' => time_in_msec(Time.now - 100)
|
21
|
+
end
|
22
|
+
end
|
23
|
+
end
|
@@ -0,0 +1,27 @@
|
|
1
|
+
require 'test_helper'
|
2
|
+
|
3
|
+
class EnvSettingsTest < RackTimeoutTest
|
4
|
+
|
5
|
+
def test_service_timeout
|
6
|
+
with_env(RACK_TIMEOUT_SERVICE_TIMEOUT: 1) do
|
7
|
+
assert_raises(Rack::Timeout::RequestTimeoutError) do
|
8
|
+
get "/sleep"
|
9
|
+
end
|
10
|
+
end
|
11
|
+
end
|
12
|
+
|
13
|
+
def test_zero_wait_timeout
|
14
|
+
with_env(RACK_TIMEOUT_WAIT_TIMEOUT: 0) do
|
15
|
+
get "/", "", 'HTTP_X_REQUEST_START' => time_in_msec(Time.now - 100)
|
16
|
+
assert last_response.ok?
|
17
|
+
end
|
18
|
+
end
|
19
|
+
|
20
|
+
def test_term
|
21
|
+
with_env(RACK_TIMEOUT_TERM_ON_TIMEOUT: 1) do
|
22
|
+
assert_raises(SignalException) do
|
23
|
+
get "/sleep"
|
24
|
+
end
|
25
|
+
end
|
26
|
+
end
|
27
|
+
end
|
data/test/test_helper.rb
ADDED
@@ -0,0 +1,45 @@
|
|
1
|
+
require "test/unit"
|
2
|
+
require "rack/test"
|
3
|
+
require "rack-timeout"
|
4
|
+
|
5
|
+
class RackTimeoutTest < Test::Unit::TestCase
|
6
|
+
include Rack::Test::Methods
|
7
|
+
|
8
|
+
attr_accessor :settings
|
9
|
+
|
10
|
+
def initialize(*args)
|
11
|
+
self.settings ||= {}
|
12
|
+
super(*args)
|
13
|
+
end
|
14
|
+
|
15
|
+
def app
|
16
|
+
settings = self.settings
|
17
|
+
Rack::Builder.new do
|
18
|
+
use Rack::Timeout, settings
|
19
|
+
|
20
|
+
map "/" do
|
21
|
+
run lambda { |env| [200, {'Content-Type' => 'text/plain'}, ['OK']] }
|
22
|
+
end
|
23
|
+
|
24
|
+
map "/sleep" do
|
25
|
+
run lambda { |env| sleep }
|
26
|
+
end
|
27
|
+
end
|
28
|
+
end
|
29
|
+
|
30
|
+
# runs the test with the given environment, but doesnt restore the original
|
31
|
+
# environment afterwards. This should be sufficient for rack-timeout testing.
|
32
|
+
def with_env(hash)
|
33
|
+
hash.each_pair do |k, v|
|
34
|
+
ENV[k.to_s] = v.to_s
|
35
|
+
end
|
36
|
+
yield
|
37
|
+
hash.each_key do |k|
|
38
|
+
ENV[k.to_s] = nil
|
39
|
+
end
|
40
|
+
end
|
41
|
+
|
42
|
+
def time_in_msec(t = Time.now)
|
43
|
+
"#{t.tv_sec}#{t.tv_usec/1000}"
|
44
|
+
end
|
45
|
+
end
|
metadata
CHANGED
@@ -1,15 +1,57 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: rack-timeout
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.
|
4
|
+
version: 0.6.0
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Caio Chassot
|
8
8
|
autorequire:
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
|
-
date:
|
12
|
-
dependencies:
|
11
|
+
date: 2019-12-11 00:00:00.000000000 Z
|
12
|
+
dependencies:
|
13
|
+
- !ruby/object:Gem::Dependency
|
14
|
+
name: rake
|
15
|
+
requirement: !ruby/object:Gem::Requirement
|
16
|
+
requirements:
|
17
|
+
- - ">="
|
18
|
+
- !ruby/object:Gem::Version
|
19
|
+
version: '0'
|
20
|
+
type: :development
|
21
|
+
prerelease: false
|
22
|
+
version_requirements: !ruby/object:Gem::Requirement
|
23
|
+
requirements:
|
24
|
+
- - ">="
|
25
|
+
- !ruby/object:Gem::Version
|
26
|
+
version: '0'
|
27
|
+
- !ruby/object:Gem::Dependency
|
28
|
+
name: rack-test
|
29
|
+
requirement: !ruby/object:Gem::Requirement
|
30
|
+
requirements:
|
31
|
+
- - ">="
|
32
|
+
- !ruby/object:Gem::Version
|
33
|
+
version: '0'
|
34
|
+
type: :development
|
35
|
+
prerelease: false
|
36
|
+
version_requirements: !ruby/object:Gem::Requirement
|
37
|
+
requirements:
|
38
|
+
- - ">="
|
39
|
+
- !ruby/object:Gem::Version
|
40
|
+
version: '0'
|
41
|
+
- !ruby/object:Gem::Dependency
|
42
|
+
name: test-unit
|
43
|
+
requirement: !ruby/object:Gem::Requirement
|
44
|
+
requirements:
|
45
|
+
- - ">="
|
46
|
+
- !ruby/object:Gem::Version
|
47
|
+
version: '0'
|
48
|
+
type: :development
|
49
|
+
prerelease: false
|
50
|
+
version_requirements: !ruby/object:Gem::Requirement
|
51
|
+
requirements:
|
52
|
+
- - ">="
|
53
|
+
- !ruby/object:Gem::Version
|
54
|
+
version: '0'
|
13
55
|
description: Rack middleware which aborts requests that have been running for longer
|
14
56
|
than a specified timeout.
|
15
57
|
email: caio@heroku.com
|
@@ -17,13 +59,22 @@ executables: []
|
|
17
59
|
extensions: []
|
18
60
|
extra_rdoc_files: []
|
19
61
|
files:
|
20
|
-
- CHANGELOG
|
62
|
+
- CHANGELOG.md
|
63
|
+
- Gemfile
|
21
64
|
- MIT-LICENSE
|
22
|
-
- README.
|
65
|
+
- README.md
|
66
|
+
- Rakefile
|
67
|
+
- UPGRADING.md
|
68
|
+
- doc/exceptions.md
|
69
|
+
- doc/logging.md
|
70
|
+
- doc/observers.md
|
71
|
+
- doc/request-lifecycle.md
|
72
|
+
- doc/risks.md
|
73
|
+
- doc/rollbar.md
|
74
|
+
- doc/settings.md
|
23
75
|
- lib/rack-timeout.rb
|
24
76
|
- lib/rack/timeout/base.rb
|
25
77
|
- lib/rack/timeout/core.rb
|
26
|
-
- lib/rack/timeout/legacy.rb
|
27
78
|
- lib/rack/timeout/logger.rb
|
28
79
|
- lib/rack/timeout/logging-observer.rb
|
29
80
|
- lib/rack/timeout/rails.rb
|
@@ -32,10 +83,17 @@ files:
|
|
32
83
|
- lib/rack/timeout/support/namespace.rb
|
33
84
|
- lib/rack/timeout/support/scheduler.rb
|
34
85
|
- lib/rack/timeout/support/timeout.rb
|
35
|
-
|
86
|
+
- test/basic_test.rb
|
87
|
+
- test/env_settings_test.rb
|
88
|
+
- test/test_helper.rb
|
89
|
+
homepage: https://github.com/sharpstone/rack-timeout
|
36
90
|
licenses:
|
37
91
|
- MIT
|
38
|
-
metadata:
|
92
|
+
metadata:
|
93
|
+
bug_tracker_uri: https://github.com/sharpstone/rack-timeout/issues
|
94
|
+
changelog_uri: https://github.com/sharpstone/rack-timeout/blob/v0.6.0/CHANGELOG.md
|
95
|
+
documentation_uri: https://rubydoc.info/gems/rack-timeout/0.6.0/
|
96
|
+
source_code_uri: https://github.com/sharpstone/rack-timeout
|
39
97
|
post_install_message:
|
40
98
|
rdoc_options: []
|
41
99
|
require_paths:
|
@@ -51,10 +109,13 @@ required_rubygems_version: !ruby/object:Gem::Requirement
|
|
51
109
|
- !ruby/object:Gem::Version
|
52
110
|
version: '0'
|
53
111
|
requirements: []
|
54
|
-
|
55
|
-
rubygems_version: 2.5.1
|
112
|
+
rubygems_version: 3.0.6
|
56
113
|
signing_key:
|
57
114
|
specification_version: 4
|
58
115
|
summary: Abort requests that are taking too long
|
59
|
-
test_files:
|
60
|
-
|
116
|
+
test_files:
|
117
|
+
- test/basic_test.rb
|
118
|
+
- test/env_settings_test.rb
|
119
|
+
- test/test_helper.rb
|
120
|
+
- Gemfile
|
121
|
+
- Rakefile
|