backlog_reporter 0.2.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +7 -0
- data/.gitignore +9 -0
- data/.rspec +2 -0
- data/.travis.yml +5 -0
- data/CHANGELOG.md +9 -0
- data/Gemfile +9 -0
- data/LICENSE +21 -0
- data/README.md +76 -0
- data/Rakefile +34 -0
- data/backlog_reporter.gemspec +25 -0
- data/bin/console +14 -0
- data/bin/setup +8 -0
- data/doc/images/.keep +1 -0
- data/doc/images/after_backlog.png +0 -0
- data/doc/images/before_backlog.png +0 -0
- data/jenkins.sh +4 -0
- data/lib/backlog_reporter/railtie.rb +36 -0
- data/lib/backlog_reporter/version.rb +23 -0
- data/lib/backlog_reporter.rb +69 -0
- metadata +119 -0
checksums.yaml
ADDED
@@ -0,0 +1,7 @@
|
|
1
|
+
---
|
2
|
+
SHA1:
|
3
|
+
metadata.gz: 6eb400858084826fc89a815e578f16df5eda6239
|
4
|
+
data.tar.gz: 2588b718a53a120e52c46d041f3e7c46268eb7a1
|
5
|
+
SHA512:
|
6
|
+
metadata.gz: 4d435dad0c4d13c40910a87eeb8afa74b73c44453f286b0d726188b53b56c17be046ef32873c5d6ff7aa92dae451bb87555a0d273a271744b982eefe6612992e
|
7
|
+
data.tar.gz: 29a5529a6dfbbcfee7c6c09d7a54d401b2a29abe6c433ef3b8d475699cf866e322428218d555c7c868786a74bd34abdc50c01f5bba01de15e63d1e8411253e69
|
data/.gitignore
ADDED
data/.rspec
ADDED
data/.travis.yml
ADDED
data/CHANGELOG.md
ADDED
data/Gemfile
ADDED
data/LICENSE
ADDED
@@ -0,0 +1,21 @@
|
|
1
|
+
MIT License
|
2
|
+
|
3
|
+
Copyright (c) 2016 Conjur Inc.
|
4
|
+
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
7
|
+
in the Software without restriction, including without limitation the rights
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
10
|
+
furnished to do so, subject to the following conditions:
|
11
|
+
|
12
|
+
The above copyright notice and this permission notice shall be included in all
|
13
|
+
copies or substantial portions of the Software.
|
14
|
+
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
21
|
+
SOFTWARE.
|
data/README.md
ADDED
@@ -0,0 +1,76 @@
|
|
1
|
+
# Backlog Reporter
|
2
|
+
|
3
|
+
This gem monitors the size of the web server internal request backlog. (The backlog is requests whose socket has been accepted, but which are not yet being processed by the web server.) Once the request backlog exceeds a certain threshold, a flag file is touched. This flag file can be monitored by a fronting web server (e.g. Nginx) to proactively return 503 Service Unavailable, so that the backlog does not grow further. Once the request backlog falls back below the threshold, the flag file is deleted.
|
4
|
+
|
5
|
+
The rapid 503 response prevents the backlog from growing without bound, and it prevents the server from trying to process too many requests in parallel. When the server is trying to process too many requests at once, the average latency starts to climb and all clients start to see longer and longer response times.
|
6
|
+
|
7
|
+
# Requirements
|
8
|
+
|
9
|
+
Currently, `backlog_reporter` works only with the Puma web server.
|
10
|
+
|
11
|
+
# Example
|
12
|
+
|
13
|
+
Here's an example of a web service whose behavior was improved with the Backlog Reporter.
|
14
|
+
|
15
|
+
## Without Backlog Reporter
|
16
|
+
|
17
|
+
At the 10 request per second rate, the response time starts to degrade until it climbs above 20 seconds per request and the remainder of the requests time out.
|
18
|
+
|
19
|
+
![Before backlog reporter](./doc/images/before_backlog.png)
|
20
|
+
|
21
|
+
## With Backlog Reporter
|
22
|
+
|
23
|
+
Once the server starts to become overloaded, it degrades in a predictable way. The average response time increases to about 5 seconds; however, it does not increase further from this level. With client retry, all requests will eventually be served successfully.
|
24
|
+
|
25
|
+
![After backlog reporter](./doc/images/after_backlog.png)
|
26
|
+
|
27
|
+
(Note: The performance of this application was also improved at the same time; that's why even the initial responses are faster).
|
28
|
+
|
29
|
+
## Installation
|
30
|
+
|
31
|
+
Add this line to your application's Gemfile:
|
32
|
+
|
33
|
+
```ruby
|
34
|
+
gem 'backlog_reporter'
|
35
|
+
```
|
36
|
+
|
37
|
+
And then execute:
|
38
|
+
|
39
|
+
$ bundle
|
40
|
+
|
41
|
+
Or install it yourself as:
|
42
|
+
|
43
|
+
$ gem install backlog_reporter
|
44
|
+
|
45
|
+
## Usage
|
46
|
+
|
47
|
+
In rails config:
|
48
|
+
|
49
|
+
```ruby
|
50
|
+
config.backlog_reporter.flag_path = '/run/app/congested.flag'
|
51
|
+
config.backlog_reporter.max_backlog = 16
|
52
|
+
config.backlog_reporter.check_interval = 0.01 # seconds
|
53
|
+
```
|
54
|
+
|
55
|
+
In nginx config:
|
56
|
+
|
57
|
+
```
|
58
|
+
location / {
|
59
|
+
proxy_pass http://localhost:300;
|
60
|
+
|
61
|
+
if (-f /run/app/congested.flag) {
|
62
|
+
return 503;
|
63
|
+
}
|
64
|
+
}
|
65
|
+
```
|
66
|
+
|
67
|
+
## Development
|
68
|
+
|
69
|
+
After checking out the repo, run `bin/setup` to install dependencies. Then, run `rake spec` to run the tests. You can also run `bin/console` for an interactive prompt that will allow you to experiment.
|
70
|
+
|
71
|
+
To install this gem onto your local machine, run `bundle exec rake install`. To release a new version, update the version number in `version.rb`, and then run `bundle exec rake release`, which will create a git tag for the version, push git commits and tags, and push the `.gem` file to [rubygems.org](https://rubygems.org).
|
72
|
+
|
73
|
+
## Contributing
|
74
|
+
|
75
|
+
Bug reports and pull requests are welcome on GitHub at https://github.com/conjurinc/backlog-reporter.
|
76
|
+
|
data/Rakefile
ADDED
@@ -0,0 +1,34 @@
|
|
1
|
+
require "bundler/gem_tasks"
|
2
|
+
require "rspec/core/rake_task"
|
3
|
+
|
4
|
+
RSpec::Core::RakeTask.new(:spec)
|
5
|
+
|
6
|
+
task :default => :spec
|
7
|
+
|
8
|
+
task :headers do
|
9
|
+
require 'rubygems'
|
10
|
+
require 'copyright_header'
|
11
|
+
|
12
|
+
spec = Gem::Specification.load 'puma_backlog_detector.gemspec'
|
13
|
+
|
14
|
+
args = {
|
15
|
+
license: spec.license,
|
16
|
+
copyright_software: spec.name,
|
17
|
+
copyright_software_description: spec.summary,
|
18
|
+
:copyright_holders => ['Conjur Inc.'],
|
19
|
+
:copyright_years => ['2016'],
|
20
|
+
:add_path => 'lib:spec',
|
21
|
+
:output_dir => '.'
|
22
|
+
}
|
23
|
+
|
24
|
+
command_line = CopyrightHeader::CommandLine.new( args )
|
25
|
+
command_line.execute
|
26
|
+
end
|
27
|
+
|
28
|
+
begin
|
29
|
+
require 'ci/reporter/rake/rspec'
|
30
|
+
|
31
|
+
task jenkins: ['ci:setup:rspec', :spec]
|
32
|
+
rescue LoadError
|
33
|
+
# expected on non-jenkins
|
34
|
+
end
|
@@ -0,0 +1,25 @@
|
|
1
|
+
# coding: utf-8
|
2
|
+
lib = File.expand_path('../lib', __FILE__)
|
3
|
+
$LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
|
4
|
+
require 'backlog_reporter/version'
|
5
|
+
|
6
|
+
Gem::Specification.new do |spec|
|
7
|
+
spec.name = "backlog_reporter"
|
8
|
+
spec.version = BacklogReporter::VERSION
|
9
|
+
spec.authors = ["Rafał Rzepecki"]
|
10
|
+
spec.email = ["rafal@conjur.net"]
|
11
|
+
spec.license = "MIT"
|
12
|
+
|
13
|
+
spec.summary = %q{Periodically check Puma backlog and write a flag file}
|
14
|
+
spec.homepage = "https://github.com/conjurinc/backlog-reporter"
|
15
|
+
|
16
|
+
spec.files = `git ls-files -z`.split("\x0").reject { |f| f.match(%r{^(test|spec|features)/}) }
|
17
|
+
spec.bindir = "exe"
|
18
|
+
spec.executables = spec.files.grep(%r{^exe/}) { |f| File.basename(f) }
|
19
|
+
spec.require_paths = ["lib"]
|
20
|
+
|
21
|
+
spec.add_dependency "puma", "~> 3.6"
|
22
|
+
spec.add_development_dependency "bundler", "~> 1.8"
|
23
|
+
spec.add_development_dependency "rake", "~> 10.0"
|
24
|
+
spec.add_development_dependency "rspec", "~> 3.0"
|
25
|
+
end
|
data/bin/console
ADDED
@@ -0,0 +1,14 @@
|
|
1
|
+
#!/usr/bin/env ruby
|
2
|
+
|
3
|
+
require "bundler/setup"
|
4
|
+
require "puma_backlog_detector"
|
5
|
+
|
6
|
+
# You can add fixtures and/or initialization code here to make experimenting
|
7
|
+
# with your gem easier. You can also use a different console, if you like.
|
8
|
+
|
9
|
+
# (If you use this, don't forget to add pry to your Gemfile!)
|
10
|
+
# require "pry"
|
11
|
+
# Pry.start
|
12
|
+
|
13
|
+
require "irb"
|
14
|
+
IRB.start
|
data/bin/setup
ADDED
data/doc/images/.keep
ADDED
@@ -0,0 +1 @@
|
|
1
|
+
|
Binary file
|
Binary file
|
data/jenkins.sh
ADDED
@@ -0,0 +1,36 @@
|
|
1
|
+
#
|
2
|
+
# Copyright (C) 2016 Conjur Inc.
|
3
|
+
#
|
4
|
+
# Permission is hereby granted, free of charge, to any person obtaining a copy of
|
5
|
+
# this software and associated documentation files (the "Software"), to deal in
|
6
|
+
# the Software without restriction, including without limitation the rights to
|
7
|
+
# use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of
|
8
|
+
# the Software, and to permit persons to whom the Software is furnished to do so,
|
9
|
+
# subject to the following conditions:
|
10
|
+
#
|
11
|
+
# The above copyright notice and this permission notice shall be included in all
|
12
|
+
# copies or substantial portions of the Software.
|
13
|
+
#
|
14
|
+
# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
15
|
+
# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
|
16
|
+
# FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
|
17
|
+
# COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
|
18
|
+
# IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
|
19
|
+
# CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
20
|
+
#
|
21
|
+
class BacklogReporter
|
22
|
+
class Railtie < Rails::Railtie
|
23
|
+
config.backlog_reporter = ActiveSupport::OrderedOptions.new
|
24
|
+
config.backlog_reporter.max_backlog = 16
|
25
|
+
config.backlog_reporter.check_interval = 0.01
|
26
|
+
config.backlog_reporter.flag_path = nil
|
27
|
+
|
28
|
+
initializer "backlog_reporter.run" do
|
29
|
+
conf = config.backlog_reporter
|
30
|
+
if conf.flag_path
|
31
|
+
@backlog_reporter = BacklogReporter.new conf.flag_path, conf.max_backlog
|
32
|
+
@backlog_reporter.check_in_background conf.check_interval
|
33
|
+
end
|
34
|
+
end
|
35
|
+
end
|
36
|
+
end
|
@@ -0,0 +1,23 @@
|
|
1
|
+
#
|
2
|
+
# Copyright (C) 2016 Conjur Inc.
|
3
|
+
#
|
4
|
+
# Permission is hereby granted, free of charge, to any person obtaining a copy of
|
5
|
+
# this software and associated documentation files (the "Software"), to deal in
|
6
|
+
# the Software without restriction, including without limitation the rights to
|
7
|
+
# use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of
|
8
|
+
# the Software, and to permit persons to whom the Software is furnished to do so,
|
9
|
+
# subject to the following conditions:
|
10
|
+
#
|
11
|
+
# The above copyright notice and this permission notice shall be included in all
|
12
|
+
# copies or substantial portions of the Software.
|
13
|
+
#
|
14
|
+
# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
15
|
+
# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
|
16
|
+
# FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
|
17
|
+
# COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
|
18
|
+
# IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
|
19
|
+
# CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
20
|
+
#
|
21
|
+
class BacklogReporter
|
22
|
+
VERSION = "0.2.0"
|
23
|
+
end
|
@@ -0,0 +1,69 @@
|
|
1
|
+
#
|
2
|
+
# Copyright (C) 2016 Conjur Inc.
|
3
|
+
#
|
4
|
+
# Permission is hereby granted, free of charge, to any person obtaining a copy of
|
5
|
+
# this software and associated documentation files (the "Software"), to deal in
|
6
|
+
# the Software without restriction, including without limitation the rights to
|
7
|
+
# use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of
|
8
|
+
# the Software, and to permit persons to whom the Software is furnished to do so,
|
9
|
+
# subject to the following conditions:
|
10
|
+
#
|
11
|
+
# The above copyright notice and this permission notice shall be included in all
|
12
|
+
# copies or substantial portions of the Software.
|
13
|
+
#
|
14
|
+
# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
15
|
+
# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
|
16
|
+
# FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
|
17
|
+
# COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
|
18
|
+
# IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
|
19
|
+
# CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
20
|
+
#
|
21
|
+
require "backlog_reporter/version"
|
22
|
+
require "backlog_reporter/railtie" if defined? Rails
|
23
|
+
|
24
|
+
class BacklogReporter
|
25
|
+
def initialize flag_path, max_backlog = 16
|
26
|
+
@flag = FlagFile.new flag_path
|
27
|
+
@max_backlog = max_backlog
|
28
|
+
end
|
29
|
+
|
30
|
+
def check
|
31
|
+
if server = Puma::Server.current
|
32
|
+
@flag.set server.backlog > @max_backlog
|
33
|
+
end
|
34
|
+
end
|
35
|
+
|
36
|
+
def check_periodically interval_s = 0.01
|
37
|
+
while true
|
38
|
+
check
|
39
|
+
sleep interval_s
|
40
|
+
end
|
41
|
+
end
|
42
|
+
|
43
|
+
def check_in_background interval_s = 0.01
|
44
|
+
@thread = Thread.new { check_periodically interval_s }
|
45
|
+
end
|
46
|
+
|
47
|
+
def stop
|
48
|
+
if @thread
|
49
|
+
@thread.exit
|
50
|
+
@thread.join
|
51
|
+
@thread = nil
|
52
|
+
end
|
53
|
+
end
|
54
|
+
|
55
|
+
class FlagFile
|
56
|
+
def initialize path
|
57
|
+
@path = path
|
58
|
+
@exists = File.exists? path
|
59
|
+
set false
|
60
|
+
end
|
61
|
+
|
62
|
+
def set value
|
63
|
+
if @exists != value
|
64
|
+
FileUtils.send((value ? :touch : :rm_f), @path)
|
65
|
+
@exists = value
|
66
|
+
end
|
67
|
+
end
|
68
|
+
end
|
69
|
+
end
|
metadata
ADDED
@@ -0,0 +1,119 @@
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
2
|
+
name: backlog_reporter
|
3
|
+
version: !ruby/object:Gem::Version
|
4
|
+
version: 0.2.0
|
5
|
+
platform: ruby
|
6
|
+
authors:
|
7
|
+
- Rafał Rzepecki
|
8
|
+
autorequire:
|
9
|
+
bindir: exe
|
10
|
+
cert_chain: []
|
11
|
+
date: 2016-09-07 00:00:00.000000000 Z
|
12
|
+
dependencies:
|
13
|
+
- !ruby/object:Gem::Dependency
|
14
|
+
name: puma
|
15
|
+
requirement: !ruby/object:Gem::Requirement
|
16
|
+
requirements:
|
17
|
+
- - ~>
|
18
|
+
- !ruby/object:Gem::Version
|
19
|
+
version: '3.6'
|
20
|
+
type: :runtime
|
21
|
+
prerelease: false
|
22
|
+
version_requirements: !ruby/object:Gem::Requirement
|
23
|
+
requirements:
|
24
|
+
- - ~>
|
25
|
+
- !ruby/object:Gem::Version
|
26
|
+
version: '3.6'
|
27
|
+
- !ruby/object:Gem::Dependency
|
28
|
+
name: bundler
|
29
|
+
requirement: !ruby/object:Gem::Requirement
|
30
|
+
requirements:
|
31
|
+
- - ~>
|
32
|
+
- !ruby/object:Gem::Version
|
33
|
+
version: '1.8'
|
34
|
+
type: :development
|
35
|
+
prerelease: false
|
36
|
+
version_requirements: !ruby/object:Gem::Requirement
|
37
|
+
requirements:
|
38
|
+
- - ~>
|
39
|
+
- !ruby/object:Gem::Version
|
40
|
+
version: '1.8'
|
41
|
+
- !ruby/object:Gem::Dependency
|
42
|
+
name: rake
|
43
|
+
requirement: !ruby/object:Gem::Requirement
|
44
|
+
requirements:
|
45
|
+
- - ~>
|
46
|
+
- !ruby/object:Gem::Version
|
47
|
+
version: '10.0'
|
48
|
+
type: :development
|
49
|
+
prerelease: false
|
50
|
+
version_requirements: !ruby/object:Gem::Requirement
|
51
|
+
requirements:
|
52
|
+
- - ~>
|
53
|
+
- !ruby/object:Gem::Version
|
54
|
+
version: '10.0'
|
55
|
+
- !ruby/object:Gem::Dependency
|
56
|
+
name: rspec
|
57
|
+
requirement: !ruby/object:Gem::Requirement
|
58
|
+
requirements:
|
59
|
+
- - ~>
|
60
|
+
- !ruby/object:Gem::Version
|
61
|
+
version: '3.0'
|
62
|
+
type: :development
|
63
|
+
prerelease: false
|
64
|
+
version_requirements: !ruby/object:Gem::Requirement
|
65
|
+
requirements:
|
66
|
+
- - ~>
|
67
|
+
- !ruby/object:Gem::Version
|
68
|
+
version: '3.0'
|
69
|
+
description:
|
70
|
+
email:
|
71
|
+
- rafal@conjur.net
|
72
|
+
executables: []
|
73
|
+
extensions: []
|
74
|
+
extra_rdoc_files: []
|
75
|
+
files:
|
76
|
+
- .gitignore
|
77
|
+
- .rspec
|
78
|
+
- .travis.yml
|
79
|
+
- CHANGELOG.md
|
80
|
+
- Gemfile
|
81
|
+
- LICENSE
|
82
|
+
- README.md
|
83
|
+
- Rakefile
|
84
|
+
- backlog_reporter.gemspec
|
85
|
+
- bin/console
|
86
|
+
- bin/setup
|
87
|
+
- doc/images/.keep
|
88
|
+
- doc/images/after_backlog.png
|
89
|
+
- doc/images/before_backlog.png
|
90
|
+
- jenkins.sh
|
91
|
+
- lib/backlog_reporter.rb
|
92
|
+
- lib/backlog_reporter/railtie.rb
|
93
|
+
- lib/backlog_reporter/version.rb
|
94
|
+
homepage: https://github.com/conjurinc/backlog-reporter
|
95
|
+
licenses:
|
96
|
+
- MIT
|
97
|
+
metadata: {}
|
98
|
+
post_install_message:
|
99
|
+
rdoc_options: []
|
100
|
+
require_paths:
|
101
|
+
- lib
|
102
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
103
|
+
requirements:
|
104
|
+
- - '>='
|
105
|
+
- !ruby/object:Gem::Version
|
106
|
+
version: '0'
|
107
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
108
|
+
requirements:
|
109
|
+
- - '>='
|
110
|
+
- !ruby/object:Gem::Version
|
111
|
+
version: '0'
|
112
|
+
requirements: []
|
113
|
+
rubyforge_project:
|
114
|
+
rubygems_version: 2.0.14.1
|
115
|
+
signing_key:
|
116
|
+
specification_version: 4
|
117
|
+
summary: Periodically check Puma backlog and write a flag file
|
118
|
+
test_files: []
|
119
|
+
has_rdoc:
|