stalin 0.1.2 → 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 +4 -4
- data/README.md +37 -12
- data/Rakefile +1 -0
- data/VERSION +1 -1
- data/lib/stalin/adapter/rack.rb +18 -46
- data/stalin.gemspec +7 -4
- metadata +19 -18
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 76e53770ae0769f7bd129d9e29d33b614dd01376
|
4
|
+
data.tar.gz: 963fad2ce29f887865a71872c9cd41e64e629fd7
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 816bfc278b02ecea85221413c145d35a9feaab69a2ab78739aba8d892119b7d5b81cd42a15d350f2860d72649509e2f36b520f2d69b1926c68d1e6fc34e78b7b
|
7
|
+
data.tar.gz: 8aca03b3fe8cda1dcf950314e6f28aa7fa76e928abff60ea0061e72fb628fc1136337a05eb050055c4ecfeb923b0b13d9b13e30e9b45982c08f045171c2baae5
|
data/README.md
CHANGED
@@ -26,20 +26,22 @@ Servers known NOT to work:
|
|
26
26
|
As you can see, we are far short of our _goal_ to support many servers! More to come as needed;
|
27
27
|
let me know what you need!
|
28
28
|
|
29
|
-
#
|
29
|
+
# User's Guide
|
30
|
+
|
31
|
+
## Installation
|
30
32
|
|
31
33
|
Just include stalin in your Gemfile.
|
32
34
|
|
33
35
|
gem 'stalin'
|
34
36
|
|
35
|
-
|
37
|
+
## Usage
|
36
38
|
|
37
39
|
Decide on which application server you will use. Add some lines to your `config.ru` to
|
38
40
|
install a suitable Stalin middleware.
|
39
41
|
|
40
42
|
Because different app servers have different signal-handling and restart semantics, we
|
41
|
-
must specialize Stalin's behavior; this is done with
|
42
|
-
plus one derived class per supported application server.
|
43
|
+
must specialize Stalin's behavior; this is done with an abstract base class
|
44
|
+
(Stalin::Adapter::Rack) plus one derived class per supported application server.
|
43
45
|
|
44
46
|
# Gem that kills app processes when their heap becomes too fragmented.
|
45
47
|
require 'stalin'
|
@@ -50,17 +52,40 @@ plus one derived class per supported application server.
|
|
50
52
|
# Each worker will shutdown at some point between 192MB and 256MB of memory usage.
|
51
53
|
use Stalin::Adapter::Unicorn, (192*mb), (256*mb)
|
52
54
|
|
53
|
-
|
54
|
-
- Pass three parameters (app, graceful-shutdown signal and abrupt-shutdown signal) to decide on signalling behavior yourself
|
55
|
-
- Pass one parameter (app) to let Stalin decide which adapter to use based on which server is resident in memory
|
56
|
-
|
57
|
-
Instantiating the Rack middleware with one parameter is deprecated; we'd much rather you be
|
58
|
-
explicit about your application server than rely on our heuristic!
|
59
|
-
|
60
|
-
# Tuning
|
55
|
+
## Tuning
|
61
56
|
|
62
57
|
Consult the documentation for your adapter's `#initialize` to learn how to tune Stalin's behavior.
|
63
58
|
|
59
|
+
# Developer's Guide
|
60
|
+
|
61
|
+
This gem is a work in progress; the docs are okay, but test coverage is
|
62
|
+
nonexistent. Whenever you make changes, please do some smoke tests by yourself.
|
63
|
+
|
64
|
+
## Smoke Tests
|
65
|
+
|
66
|
+
The `fixtures` subdirectory contains rackup files for both supported application
|
67
|
+
servers; you can use these to test the three supported permutations.
|
68
|
+
|
69
|
+
When you run puma or rainbows, it will begin listening on a port of its
|
70
|
+
choosing; use curl or similar to send it Web requests and cause a large
|
71
|
+
memory leak with every request. Each worker process should shutdown after the
|
72
|
+
first request, because the leak is large and the hardcoded limit for puma is
|
73
|
+
very small.
|
74
|
+
|
75
|
+
Verify that stalin is restarting the app servers and that your requests all
|
76
|
+
respond with 200 and not 502, 503 or other funny errors.
|
77
|
+
|
78
|
+
### Unicorn
|
79
|
+
|
80
|
+
bundle exec unicorn fixtures/unicorn.ru
|
81
|
+
### Single-Process Puma
|
82
|
+
|
83
|
+
bundle exec puma fixtures/puma.ru
|
84
|
+
|
85
|
+
### Multi-Process Puma
|
86
|
+
|
87
|
+
bundle exec puma -w 1 fixtures/puma.ru
|
88
|
+
|
64
89
|
# Special Thanks
|
65
90
|
|
66
91
|
- [@kzk](http://github.com/kzk/) for the [unicorn-worker-killer] gem which this is derived from
|
data/Rakefile
CHANGED
@@ -9,6 +9,7 @@ Jeweler::Tasks.new do |gem|
|
|
9
9
|
gem.description = %Q{Kill Web application workers based on arbitrary conditions.}
|
10
10
|
gem.email = "xeger@xeger.net"
|
11
11
|
gem.authors = ["Tony Spataro"]
|
12
|
+
gem.required_ruby_version = '~> 2.0'
|
12
13
|
gem.files.exclude ".rspec"
|
13
14
|
gem.files.exclude "Gemfile*"
|
14
15
|
gem.files.exclude "fixtures/**/*"
|
data/VERSION
CHANGED
@@ -1 +1 @@
|
|
1
|
-
0.
|
1
|
+
0.2.0
|
data/lib/stalin/adapter/rack.rb
CHANGED
@@ -1,43 +1,10 @@
|
|
1
1
|
module Stalin::Adapter
|
2
|
-
#
|
3
|
-
# This is suitable for application srvers that use a master-and-workers
|
4
|
-
# process architecture, wohse workers respond to a graceful shutdown signal,
|
5
|
-
# and whose masters spawn new workers as needed.
|
6
|
-
#
|
7
|
-
# This functions as a base class for server-specific middlewares, and can be used if
|
2
|
+
# Abstract base class for server-specific Rack middlewares.
|
8
3
|
# there is an app server that uses a signalling strategy not explicitly supported by Stalin.
|
9
4
|
class Rack
|
10
5
|
# Conversion constant for human-readable memory amounts in log messages.
|
11
6
|
MB = Float(1024**2)
|
12
7
|
|
13
|
-
# Construct a new middleware. If all six arguments are passed, construct an instance
|
14
|
-
# of this class; otherwise, use a heuristic to construct an instance of a suitable
|
15
|
-
# derived class.
|
16
|
-
#
|
17
|
-
# @raise [ArgumentError] if an incorrect number of arguments is passed
|
18
|
-
# @raise [RuntimeError] if 0..5 arguments and the heuristic can't figure out which signals to use
|
19
|
-
def self.new(*args)
|
20
|
-
if self == Rack && args.length < 3
|
21
|
-
# Warn that this shim will go away in v1
|
22
|
-
warn "Stalin::Adapter::Rack.new with fewer than 3 arguments is deprecated; please instantiate a derived class e.g. Unicorn or Puma"
|
23
|
-
|
24
|
-
# Use a heuristic to decide on the correct adapter and instantiate a derived class.
|
25
|
-
if defined?(::Unicorn)
|
26
|
-
middleware = Unicorn.allocate
|
27
|
-
elsif defined?(::Puma)
|
28
|
-
middleware = Puma.allocate
|
29
|
-
else
|
30
|
-
raise RuntimeError, "Cannot determine a suitable Stalin adapter; please instantiate this class with six arguments"
|
31
|
-
end
|
32
|
-
|
33
|
-
# Initialize our new object (ugh)
|
34
|
-
middleware.instance_eval { initialize(*args) }
|
35
|
-
middleware
|
36
|
-
else
|
37
|
-
super
|
38
|
-
end
|
39
|
-
end
|
40
|
-
|
41
8
|
# Create a middleware instance.
|
42
9
|
#
|
43
10
|
# @param [#call] app inner Rack application
|
@@ -48,7 +15,7 @@ module Stalin::Adapter
|
|
48
15
|
# @param [Integer] cycle how frequently to check memory consumption (# requests)
|
49
16
|
# @param [Boolean] verbose log extra information
|
50
17
|
# @param [Array] signals pair of two Symbol signal-names: one for "graceful shutdown please" and one for "terminate immediately"
|
51
|
-
def initialize(app, graceful, abrupt, min
|
18
|
+
def initialize(app, graceful, abrupt, min, max, cycle, verbose)
|
52
19
|
@app = app
|
53
20
|
@graceful = graceful
|
54
21
|
@abrupt = abrupt
|
@@ -56,6 +23,7 @@ module Stalin::Adapter
|
|
56
23
|
@max = max
|
57
24
|
@cycle = cycle
|
58
25
|
@verbose = verbose
|
26
|
+
@req = 0
|
59
27
|
end
|
60
28
|
|
61
29
|
def call(env)
|
@@ -64,22 +32,26 @@ module Stalin::Adapter
|
|
64
32
|
logger = logger_for(env)
|
65
33
|
|
66
34
|
begin
|
67
|
-
|
68
|
-
|
69
|
-
|
35
|
+
if @req == 0
|
36
|
+
# First-time initialization. Deferred until first request so we can
|
37
|
+
# ensure that init-time log output goes to the right place.
|
38
|
+
@lim = @min + randomize(@max - @min + 1)
|
39
|
+
@req = 0
|
40
|
+
@watcher = ::Stalin::Watcher.new(Process.pid)
|
41
|
+
@killer = ::Stalin::Killer.new(Process.pid, @graceful, @abrupt)
|
42
|
+
logger.info "stalin (pid: %d) startup; limit=%.1f MB, graceful=SIG%s (abrupt=SIG%s after %d tries)" %
|
43
|
+
[Process.pid, @lim / MB, @graceful, @abrupt, Stalin::Killer::MAX_GRACEFUL]
|
44
|
+
end
|
45
|
+
|
46
|
+
@req += 1
|
70
47
|
|
71
48
|
if @req % @cycle == 0
|
72
|
-
@req = 0
|
73
|
-
@watcher ||= ::Stalin::Watcher.new(Process.pid)
|
74
|
-
@killer ||= ::Stalin::Killer.new(Process.pid, @graceful, @abrupt)
|
75
49
|
if (used = @watcher.watch) > @lim
|
76
50
|
sig = @killer.kill
|
77
|
-
|
78
|
-
logger.info "stalin (pid: %d) send SIG%s; memory usage %.1f MB > %.1f MB" %
|
51
|
+
logger.info "stalin (pid: %d) send SIG%s; %.1f MB > %.1f MB" %
|
79
52
|
[Process.pid, sig, used / MB, @lim / MB]
|
80
|
-
@cycle = 2
|
81
53
|
elsif @verbose
|
82
|
-
logger.info "stalin (pid: %d) soldiers on;
|
54
|
+
logger.info "stalin (pid: %d) soldiers on; %.1f MB < %.1f MB" %
|
83
55
|
[Process.pid, used / MB, @lim / MB]
|
84
56
|
end
|
85
57
|
end
|
@@ -94,7 +66,7 @@ module Stalin::Adapter
|
|
94
66
|
private
|
95
67
|
|
96
68
|
def randomize(integer)
|
97
|
-
|
69
|
+
Random.rand(integer.abs)
|
98
70
|
end
|
99
71
|
|
100
72
|
def logger_for(env)
|
data/stalin.gemspec
CHANGED
@@ -2,17 +2,20 @@
|
|
2
2
|
# DO NOT EDIT THIS FILE DIRECTLY
|
3
3
|
# Instead, edit Jeweler::Tasks in Rakefile, and run 'rake gemspec'
|
4
4
|
# -*- encoding: utf-8 -*-
|
5
|
+
# stub: stalin 0.2.0 ruby lib
|
5
6
|
|
6
7
|
Gem::Specification.new do |s|
|
7
8
|
s.name = "stalin"
|
8
|
-
s.version = "0.
|
9
|
+
s.version = "0.2.0"
|
9
10
|
|
10
11
|
s.required_rubygems_version = Gem::Requirement.new(">= 0") if s.respond_to? :required_rubygems_version=
|
12
|
+
s.require_paths = ["lib"]
|
11
13
|
s.authors = ["Tony Spataro"]
|
12
|
-
s.date = "2015-
|
14
|
+
s.date = "2015-08-17"
|
13
15
|
s.description = "Kill Web application workers based on arbitrary conditions."
|
14
16
|
s.email = "xeger@xeger.net"
|
15
17
|
s.extra_rdoc_files = [
|
18
|
+
"CHANGELOG.md",
|
16
19
|
"LICENSE",
|
17
20
|
"README.md"
|
18
21
|
]
|
@@ -36,8 +39,8 @@ Gem::Specification.new do |s|
|
|
36
39
|
]
|
37
40
|
s.homepage = "https://github.com/xeger/stalin"
|
38
41
|
s.licenses = ["MIT"]
|
39
|
-
s.
|
40
|
-
s.rubygems_version = "2.
|
42
|
+
s.required_ruby_version = Gem::Requirement.new("~> 2.0")
|
43
|
+
s.rubygems_version = "2.4.5"
|
41
44
|
s.summary = "Kill rack"
|
42
45
|
|
43
46
|
if s.respond_to? :specification_version then
|
metadata
CHANGED
@@ -1,97 +1,97 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: stalin
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.
|
4
|
+
version: 0.2.0
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Tony Spataro
|
8
8
|
autorequire:
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
|
-
date: 2015-
|
11
|
+
date: 2015-08-31 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: jeweler
|
15
15
|
requirement: !ruby/object:Gem::Requirement
|
16
16
|
requirements:
|
17
|
-
- - ~>
|
17
|
+
- - "~>"
|
18
18
|
- !ruby/object:Gem::Version
|
19
19
|
version: '2.0'
|
20
20
|
type: :development
|
21
21
|
prerelease: false
|
22
22
|
version_requirements: !ruby/object:Gem::Requirement
|
23
23
|
requirements:
|
24
|
-
- - ~>
|
24
|
+
- - "~>"
|
25
25
|
- !ruby/object:Gem::Version
|
26
26
|
version: '2.0'
|
27
27
|
- !ruby/object:Gem::Dependency
|
28
28
|
name: rspec
|
29
29
|
requirement: !ruby/object:Gem::Requirement
|
30
30
|
requirements:
|
31
|
-
- - ~>
|
31
|
+
- - "~>"
|
32
32
|
- !ruby/object:Gem::Version
|
33
33
|
version: '3.0'
|
34
34
|
type: :development
|
35
35
|
prerelease: false
|
36
36
|
version_requirements: !ruby/object:Gem::Requirement
|
37
37
|
requirements:
|
38
|
-
- - ~>
|
38
|
+
- - "~>"
|
39
39
|
- !ruby/object:Gem::Version
|
40
40
|
version: '3.0'
|
41
41
|
- !ruby/object:Gem::Dependency
|
42
42
|
name: sinatra
|
43
43
|
requirement: !ruby/object:Gem::Requirement
|
44
44
|
requirements:
|
45
|
-
- - ~>
|
45
|
+
- - "~>"
|
46
46
|
- !ruby/object:Gem::Version
|
47
47
|
version: '1.4'
|
48
48
|
type: :development
|
49
49
|
prerelease: false
|
50
50
|
version_requirements: !ruby/object:Gem::Requirement
|
51
51
|
requirements:
|
52
|
-
- - ~>
|
52
|
+
- - "~>"
|
53
53
|
- !ruby/object:Gem::Version
|
54
54
|
version: '1.4'
|
55
55
|
- !ruby/object:Gem::Dependency
|
56
56
|
name: unicorn
|
57
57
|
requirement: !ruby/object:Gem::Requirement
|
58
58
|
requirements:
|
59
|
-
- - ~>
|
59
|
+
- - "~>"
|
60
60
|
- !ruby/object:Gem::Version
|
61
61
|
version: '4.8'
|
62
62
|
type: :development
|
63
63
|
prerelease: false
|
64
64
|
version_requirements: !ruby/object:Gem::Requirement
|
65
65
|
requirements:
|
66
|
-
- - ~>
|
66
|
+
- - "~>"
|
67
67
|
- !ruby/object:Gem::Version
|
68
68
|
version: '4.8'
|
69
69
|
- !ruby/object:Gem::Dependency
|
70
70
|
name: thin
|
71
71
|
requirement: !ruby/object:Gem::Requirement
|
72
72
|
requirements:
|
73
|
-
- - ~>
|
73
|
+
- - "~>"
|
74
74
|
- !ruby/object:Gem::Version
|
75
75
|
version: '1.6'
|
76
76
|
type: :development
|
77
77
|
prerelease: false
|
78
78
|
version_requirements: !ruby/object:Gem::Requirement
|
79
79
|
requirements:
|
80
|
-
- - ~>
|
80
|
+
- - "~>"
|
81
81
|
- !ruby/object:Gem::Version
|
82
82
|
version: '1.6'
|
83
83
|
- !ruby/object:Gem::Dependency
|
84
84
|
name: puma
|
85
85
|
requirement: !ruby/object:Gem::Requirement
|
86
86
|
requirements:
|
87
|
-
- - ~>
|
87
|
+
- - "~>"
|
88
88
|
- !ruby/object:Gem::Version
|
89
89
|
version: '2.11'
|
90
90
|
type: :development
|
91
91
|
prerelease: false
|
92
92
|
version_requirements: !ruby/object:Gem::Requirement
|
93
93
|
requirements:
|
94
|
-
- - ~>
|
94
|
+
- - "~>"
|
95
95
|
- !ruby/object:Gem::Version
|
96
96
|
version: '2.11'
|
97
97
|
description: Kill Web application workers based on arbitrary conditions.
|
@@ -99,6 +99,7 @@ email: xeger@xeger.net
|
|
99
99
|
executables: []
|
100
100
|
extensions: []
|
101
101
|
extra_rdoc_files:
|
102
|
+
- CHANGELOG.md
|
102
103
|
- LICENSE
|
103
104
|
- README.md
|
104
105
|
files:
|
@@ -128,17 +129,17 @@ require_paths:
|
|
128
129
|
- lib
|
129
130
|
required_ruby_version: !ruby/object:Gem::Requirement
|
130
131
|
requirements:
|
131
|
-
- -
|
132
|
+
- - "~>"
|
132
133
|
- !ruby/object:Gem::Version
|
133
|
-
version: '0'
|
134
|
+
version: '2.0'
|
134
135
|
required_rubygems_version: !ruby/object:Gem::Requirement
|
135
136
|
requirements:
|
136
|
-
- -
|
137
|
+
- - ">="
|
137
138
|
- !ruby/object:Gem::Version
|
138
139
|
version: '0'
|
139
140
|
requirements: []
|
140
141
|
rubyforge_project:
|
141
|
-
rubygems_version: 2.
|
142
|
+
rubygems_version: 2.4.5
|
142
143
|
signing_key:
|
143
144
|
specification_version: 4
|
144
145
|
summary: Kill rack
|