unicorn-soft-timeout 0.0.1 → 0.2.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 +7 -0
- data/.gitignore +1 -0
- data/.travis.yml +18 -0
- data/README.md +14 -7
- data/Rakefile +16 -0
- data/lib/unicorn/soft_timeout.rb +2 -3
- data/lib/unicorn/soft_timeout/version.rb +1 -1
- data/test/test_helper.rb +65 -0
- data/test/unicorn_soft_timeout_test.rb +42 -0
- data/unicorn-soft-timeout.gemspec +3 -2
- metadata +39 -28
checksums.yaml
ADDED
@@ -0,0 +1,7 @@
|
|
1
|
+
---
|
2
|
+
SHA1:
|
3
|
+
metadata.gz: 1e8e7534c2f58736c14c45d873c8b789f758946f
|
4
|
+
data.tar.gz: 65be8d82059bca947dbfd2129fe077b5c33903ad
|
5
|
+
SHA512:
|
6
|
+
metadata.gz: 446843280c827b22e27f8a71c4f885f145c5d8afa4180009a74d8720471315270d861095681fcafc2738be416b68d9b9ee06057f601e7fea54591167c2518df6
|
7
|
+
data.tar.gz: 3f87ef723bb1c9664352596ef13adfabaddca50821b7dd19ff07d202526387a8d28595918ac2033118486a7b2d4e50571ddefe8644aad89a1300cb774eae11e2
|
data/.gitignore
CHANGED
data/.travis.yml
ADDED
@@ -0,0 +1,18 @@
|
|
1
|
+
language: ruby
|
2
|
+
cache: bundler
|
3
|
+
before_install:
|
4
|
+
- gem install bundler
|
5
|
+
rvm:
|
6
|
+
- 2.3
|
7
|
+
- 2.4
|
8
|
+
- ruby-head
|
9
|
+
- jruby-23mode
|
10
|
+
- jruby-head
|
11
|
+
- rubinius-3
|
12
|
+
matrix:
|
13
|
+
allow_failures:
|
14
|
+
- rvm: ruby-head
|
15
|
+
- rvm: jruby-head
|
16
|
+
- rvm: jruby-23mode
|
17
|
+
- rvm: rubinius-3
|
18
|
+
fast_finish: true
|
data/README.md
CHANGED
@@ -1,11 +1,15 @@
|
|
1
|
-
#
|
1
|
+
# unicorn-soft-timeout
|
2
2
|
|
3
|
-
This gem adds support for soft timeout in Unicorn.
|
4
|
-
requests which are taking longer than configured
|
3
|
+
This gem adds support for **soft timeout** in [Unicorn](http://unicorn.bogomips.org/)
|
4
|
+
configurations, by default requests which are taking longer than configured `timeout` are
|
5
5
|
[SIGKILL-ed](http://unicorn.bogomips.org/Unicorn/Configurator.html#method-i-timeout).
|
6
|
-
In some cases we need to intercept those requests to display a
|
7
|
-
custom content instead of the error page.
|
8
6
|
|
7
|
+
In some cases we need to intercept requests which will reach `timeout` to display a
|
8
|
+
custom content instead of the error page. This extension will raise `Timeout::Error`
|
9
|
+
when reaching the soft timeout and will restart the worker sending a `SIGQUIT`
|
10
|
+
signal to it.
|
11
|
+
|
12
|
+
- [](https://travis-ci.org/vitalie/unicorn-soft-timeout)
|
9
13
|
|
10
14
|
## Installation
|
11
15
|
|
@@ -30,10 +34,13 @@ Edit your config.ru file and load the Unicorn::SoftTimeout middleware:
|
|
30
34
|
|
31
35
|
# Specify your soft timeout (default 12 seconds), it should
|
32
36
|
# be a lower value than **timeout** specified in your unicorn config.
|
33
|
-
# This extension will raise Timeout::Error when reaching
|
34
|
-
# the **soft timeout**.
|
35
37
|
use Unicorn::SoftTimeout, 10
|
36
38
|
|
39
|
+
## Credits
|
40
|
+
|
41
|
+
* [Kazuki Ohta](https://github.com/kzk)
|
42
|
+
* [Pierre Baillet](https://github.com/octplane)
|
43
|
+
|
37
44
|
## Contributing
|
38
45
|
|
39
46
|
1. Fork it
|
data/Rakefile
CHANGED
@@ -1 +1,17 @@
|
|
1
|
+
# encoding: UTF-8
|
1
2
|
require "bundler/gem_tasks"
|
3
|
+
require "rake/testtask"
|
4
|
+
require "rdoc/task"
|
5
|
+
|
6
|
+
desc "Default: run tests."
|
7
|
+
task default: :test
|
8
|
+
|
9
|
+
|
10
|
+
desc "Run unit tests."
|
11
|
+
Rake::TestTask.new do |t|
|
12
|
+
t.libs << "test"
|
13
|
+
t.libs << "lib"
|
14
|
+
t.test_files = Dir[ "test/*_test.rb" ]
|
15
|
+
t.verbose = true
|
16
|
+
end
|
17
|
+
|
data/lib/unicorn/soft_timeout.rb
CHANGED
@@ -1,4 +1,4 @@
|
|
1
|
-
require
|
1
|
+
require 'unicorn/soft_timeout/version'
|
2
2
|
|
3
3
|
module Unicorn
|
4
4
|
module SoftTimeout
|
@@ -18,7 +18,7 @@ module Unicorn
|
|
18
18
|
sleep(@_soft_timeout)
|
19
19
|
logger.warn "#{self}: worker (pid: #{worker_pid}) exceeds soft timeout (limit: #{@_soft_timeout})"
|
20
20
|
Process.kill :QUIT, worker_pid # graceful shutdown
|
21
|
-
current_thread.raise Timeout::Error.new(
|
21
|
+
current_thread.raise Timeout::Error.new('Soft timeout exceeded')
|
22
22
|
end
|
23
23
|
|
24
24
|
super(client) # Unicorn::HttpServer#process_client
|
@@ -26,4 +26,3 @@ module Unicorn
|
|
26
26
|
end
|
27
27
|
end
|
28
28
|
end
|
29
|
-
|
data/test/test_helper.rb
ADDED
@@ -0,0 +1,65 @@
|
|
1
|
+
require 'unicorn'
|
2
|
+
require 'unicorn/soft_timeout'
|
3
|
+
require 'minitest/autorun'
|
4
|
+
require 'minitest/unit'
|
5
|
+
require 'net/http'
|
6
|
+
|
7
|
+
STDIN.sync = STDOUT.sync = STDERR.sync = true
|
8
|
+
|
9
|
+
DEFAULT_TRIES = 100
|
10
|
+
DEFAULT_RES = 0.2
|
11
|
+
|
12
|
+
def redirect_test_io
|
13
|
+
orig_err = STDERR.dup
|
14
|
+
orig_out = STDOUT.dup
|
15
|
+
STDERR.reopen("test_stderr.#{$$}.log", "a")
|
16
|
+
STDOUT.reopen("test_stdout.#{$$}.log", "a")
|
17
|
+
STDERR.sync = STDOUT.sync = true
|
18
|
+
|
19
|
+
at_exit do
|
20
|
+
File.unlink("test_stderr.#{$$}.log") rescue nil
|
21
|
+
File.unlink("test_stdout.#{$$}.log") rescue nil
|
22
|
+
end
|
23
|
+
|
24
|
+
begin
|
25
|
+
yield
|
26
|
+
ensure
|
27
|
+
STDERR.reopen(orig_err)
|
28
|
+
STDOUT.reopen(orig_out)
|
29
|
+
end
|
30
|
+
end
|
31
|
+
|
32
|
+
def wait_workers_ready(path, nr_workers)
|
33
|
+
tries = DEFAULT_TRIES
|
34
|
+
lines = []
|
35
|
+
while (tries -= 1) > 0
|
36
|
+
begin
|
37
|
+
lines = File.readlines(path).grep(/worker=\d+ ready/)
|
38
|
+
lines.size == nr_workers and return
|
39
|
+
rescue Errno::ENOENT
|
40
|
+
end
|
41
|
+
sleep DEFAULT_RES
|
42
|
+
end
|
43
|
+
raise "#{nr_workers} workers never became ready:" \
|
44
|
+
"\n\t#{lines.join("\n\t")}\n"
|
45
|
+
end
|
46
|
+
|
47
|
+
def hit(uris)
|
48
|
+
results = []
|
49
|
+
uris.each do |u|
|
50
|
+
res = nil
|
51
|
+
|
52
|
+
if u.kind_of? String
|
53
|
+
u = 'http://127.0.0.1:8080/' if u == 'http://0.0.0.0:8080/'
|
54
|
+
res = Net::HTTP.get(URI.parse(u))
|
55
|
+
else
|
56
|
+
url = URI.parse(u[0])
|
57
|
+
res = Net::HTTP.new(url.host, url.port).start {|h| h.request(u[1]) }
|
58
|
+
end
|
59
|
+
|
60
|
+
assert res != nil, "Didn't get a response: #{u}"
|
61
|
+
results << res
|
62
|
+
end
|
63
|
+
|
64
|
+
return results
|
65
|
+
end
|
@@ -0,0 +1,42 @@
|
|
1
|
+
require 'test_helper'
|
2
|
+
|
3
|
+
include Unicorn
|
4
|
+
|
5
|
+
class TestHandler
|
6
|
+
def call(env)
|
7
|
+
while env['rack.input'].read(4096)
|
8
|
+
end
|
9
|
+
sleep 5
|
10
|
+
[200, { 'Content-Type' => 'text/plain' }, ['hello!\n']]
|
11
|
+
rescue Timeout::Error
|
12
|
+
[200, { 'Content-Type' => 'text/plain' }, ['timeout!\n']]
|
13
|
+
rescue Unicorn::ClientShutdown, Unicorn::HttpParserError => e
|
14
|
+
$stderr.syswrite("#{e.class}: #{e.message} #{e.backtrace.empty?}\n")
|
15
|
+
raise e
|
16
|
+
end
|
17
|
+
end
|
18
|
+
|
19
|
+
class UnicornSoftTimeoutTest < Minitest::Test
|
20
|
+
def setup
|
21
|
+
@port = 5000
|
22
|
+
@tester = TestHandler.new
|
23
|
+
redirect_test_io do
|
24
|
+
@server = Unicorn::HttpServer.new(@tester, listeners: ["127.0.0.1:#{@port}"])
|
25
|
+
@tester = Unicorn::SoftTimeout.new(@tester, 3)
|
26
|
+
@server.start
|
27
|
+
end
|
28
|
+
end
|
29
|
+
|
30
|
+
def teardown
|
31
|
+
redirect_test_io do
|
32
|
+
wait_workers_ready("test_stderr.#$$.log", 1)
|
33
|
+
File.truncate("test_stderr.#$$.log", 0)
|
34
|
+
@server.stop(false)
|
35
|
+
end
|
36
|
+
end
|
37
|
+
|
38
|
+
def test_simple_server
|
39
|
+
results = hit(["http://localhost:#{@port}/test"])
|
40
|
+
assert_equal 'timeout!\n', results[0], "Handler didn't really run"
|
41
|
+
end
|
42
|
+
end
|
@@ -18,8 +18,9 @@ Gem::Specification.new do |spec|
|
|
18
18
|
spec.test_files = spec.files.grep(%r{^(test|spec|features)/})
|
19
19
|
spec.require_paths = ["lib"]
|
20
20
|
|
21
|
-
spec.add_dependency "unicorn", "~>
|
21
|
+
spec.add_dependency "unicorn", "~> 5"
|
22
22
|
|
23
|
-
spec.add_development_dependency "
|
23
|
+
spec.add_development_dependency "minitest"
|
24
24
|
spec.add_development_dependency "rake"
|
25
|
+
spec.add_development_dependency "bump"
|
25
26
|
end
|
metadata
CHANGED
@@ -1,62 +1,69 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: unicorn-soft-timeout
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.0
|
5
|
-
prerelease:
|
4
|
+
version: 0.2.0
|
6
5
|
platform: ruby
|
7
6
|
authors:
|
8
7
|
- Vitalie Cherpec
|
9
8
|
autorequire:
|
10
9
|
bindir: bin
|
11
10
|
cert_chain: []
|
12
|
-
date:
|
11
|
+
date: 2017-07-11 00:00:00.000000000 Z
|
13
12
|
dependencies:
|
14
13
|
- !ruby/object:Gem::Dependency
|
15
14
|
name: unicorn
|
16
15
|
requirement: !ruby/object:Gem::Requirement
|
17
|
-
none: false
|
18
16
|
requirements:
|
19
|
-
- - ~>
|
17
|
+
- - "~>"
|
20
18
|
- !ruby/object:Gem::Version
|
21
|
-
version: '
|
19
|
+
version: '5'
|
22
20
|
type: :runtime
|
23
21
|
prerelease: false
|
24
22
|
version_requirements: !ruby/object:Gem::Requirement
|
25
|
-
none: false
|
26
23
|
requirements:
|
27
|
-
- - ~>
|
24
|
+
- - "~>"
|
28
25
|
- !ruby/object:Gem::Version
|
29
|
-
version: '
|
26
|
+
version: '5'
|
30
27
|
- !ruby/object:Gem::Dependency
|
31
|
-
name:
|
28
|
+
name: minitest
|
32
29
|
requirement: !ruby/object:Gem::Requirement
|
33
|
-
none: false
|
34
30
|
requirements:
|
35
|
-
- -
|
31
|
+
- - ">="
|
36
32
|
- !ruby/object:Gem::Version
|
37
|
-
version: '
|
33
|
+
version: '0'
|
38
34
|
type: :development
|
39
35
|
prerelease: false
|
40
36
|
version_requirements: !ruby/object:Gem::Requirement
|
41
|
-
none: false
|
42
37
|
requirements:
|
43
|
-
- -
|
38
|
+
- - ">="
|
44
39
|
- !ruby/object:Gem::Version
|
45
|
-
version: '
|
40
|
+
version: '0'
|
46
41
|
- !ruby/object:Gem::Dependency
|
47
42
|
name: rake
|
48
43
|
requirement: !ruby/object:Gem::Requirement
|
49
|
-
none: false
|
50
44
|
requirements:
|
51
|
-
- -
|
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'
|
55
|
+
- !ruby/object:Gem::Dependency
|
56
|
+
name: bump
|
57
|
+
requirement: !ruby/object:Gem::Requirement
|
58
|
+
requirements:
|
59
|
+
- - ">="
|
52
60
|
- !ruby/object:Gem::Version
|
53
61
|
version: '0'
|
54
62
|
type: :development
|
55
63
|
prerelease: false
|
56
64
|
version_requirements: !ruby/object:Gem::Requirement
|
57
|
-
none: false
|
58
65
|
requirements:
|
59
|
-
- -
|
66
|
+
- - ">="
|
60
67
|
- !ruby/object:Gem::Version
|
61
68
|
version: '0'
|
62
69
|
description: Graceful handling of requests which are reaching the timeout limit to
|
@@ -67,37 +74,41 @@ executables: []
|
|
67
74
|
extensions: []
|
68
75
|
extra_rdoc_files: []
|
69
76
|
files:
|
70
|
-
- .gitignore
|
77
|
+
- ".gitignore"
|
78
|
+
- ".travis.yml"
|
71
79
|
- Gemfile
|
72
80
|
- LICENSE.txt
|
73
81
|
- README.md
|
74
82
|
- Rakefile
|
75
83
|
- lib/unicorn/soft_timeout.rb
|
76
84
|
- lib/unicorn/soft_timeout/version.rb
|
85
|
+
- test/test_helper.rb
|
86
|
+
- test/unicorn_soft_timeout_test.rb
|
77
87
|
- unicorn-soft-timeout.gemspec
|
78
88
|
homepage: https://github.com/vitalie/unicorn-soft-timeout
|
79
89
|
licenses:
|
80
90
|
- MIT
|
91
|
+
metadata: {}
|
81
92
|
post_install_message:
|
82
93
|
rdoc_options: []
|
83
94
|
require_paths:
|
84
95
|
- lib
|
85
96
|
required_ruby_version: !ruby/object:Gem::Requirement
|
86
|
-
none: false
|
87
97
|
requirements:
|
88
|
-
- -
|
98
|
+
- - ">="
|
89
99
|
- !ruby/object:Gem::Version
|
90
100
|
version: '0'
|
91
101
|
required_rubygems_version: !ruby/object:Gem::Requirement
|
92
|
-
none: false
|
93
102
|
requirements:
|
94
|
-
- -
|
103
|
+
- - ">="
|
95
104
|
- !ruby/object:Gem::Version
|
96
105
|
version: '0'
|
97
106
|
requirements: []
|
98
107
|
rubyforge_project:
|
99
|
-
rubygems_version:
|
108
|
+
rubygems_version: 2.4.5.1
|
100
109
|
signing_key:
|
101
|
-
specification_version:
|
110
|
+
specification_version: 4
|
102
111
|
summary: Unicorn soft timeout
|
103
|
-
test_files:
|
112
|
+
test_files:
|
113
|
+
- test/test_helper.rb
|
114
|
+
- test/unicorn_soft_timeout_test.rb
|