stalin 0.1.2 → 0.2.0

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: d3aba1948f1211ea981734cb7eb62d1326536b0b
4
- data.tar.gz: 694df9a4c8732561d328a26ce17f64fa12eec669
3
+ metadata.gz: 76e53770ae0769f7bd129d9e29d33b614dd01376
4
+ data.tar.gz: 963fad2ce29f887865a71872c9cd41e64e629fd7
5
5
  SHA512:
6
- metadata.gz: 6b922bd545a388a1457220caa2fe3d308d82401b59a25e01b667db3810263a8019fb304a80c3031cb66a298928e57b33aa07c2d147ce64cfc77d5cb668d9085b
7
- data.tar.gz: fc6067a0ada40c95060d978c6615b9d0054ea2abc37a0062a54b91be2367f3ac6bae06c073166b1c2715f59e8e0200ab23b03d30836bb35170b04e3461791b0a
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
- # Installation
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
- # Usage
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 a base class (Stalin::Adapter::Rack)
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
- If you instantiate Stalin::Adapter::Rack directly, you have two choices:
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.2
1
+ 0.2.0
@@ -1,43 +1,10 @@
1
1
  module Stalin::Adapter
2
- # A low-tech but reliable solution that invokes stalin using Rack middleware.
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=1024**3, max=2*1024**3, cycle=16, verbose=false)
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
- @lim ||= @min + randomize(@max - @min + 1)
68
- @req ||= 0
69
- @req += 1
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
- @watcher.watch
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; memory usage %.1f MB < %.1f MB" %
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
- RUBY_VERSION > "1.9" ? Random.rand(integer.abs) : rand(integer)
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.1.2"
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-04-21"
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.require_paths = ["lib"]
40
- s.rubygems_version = "2.0.14"
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.1.2
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-04-21 00:00:00.000000000 Z
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.0.14
142
+ rubygems_version: 2.4.5
142
143
  signing_key:
143
144
  specification_version: 4
144
145
  summary: Kill rack