whacamole 0.2.0 → 1.0.0

Sign up to get free protection for your applications and to get access to all the features.
@@ -0,0 +1,15 @@
1
+ ---
2
+ !binary "U0hBMQ==":
3
+ metadata.gz: !binary |-
4
+ Njk4YWU0NWQyMzZjMjg4OWJhZGRlNTczYzIzNTllZmIyMmZkNDVmNQ==
5
+ data.tar.gz: !binary |-
6
+ NWU5OTM2Zjg0ZTY3ZDJkNzczMDg4MWMxODYzZTk5YzRlN2FiMTg3OA==
7
+ !binary "U0hBNTEy":
8
+ metadata.gz: !binary |-
9
+ ZGY2MDllNzU4ZDg0Y2E5YTY4ODlhMTE3NTJmZDE5NjY0ZmJlZWY2OTVlZDgx
10
+ ZmUyZGU1ZTBhMWQ3MWVkZmMxZGU1OTEyZTIwZGVkMTdjYjM2M2IxZGRiNTgz
11
+ ZjBlOTM5MjVhNzQ0NzRlMTg2MGVhYTI5MzYxNzk1ZTg5MDA4YWQ=
12
+ data.tar.gz: !binary |-
13
+ OTY4MTM5NTU5NWJmMTQzOWQ5NzY1N2VlMWY2MDcyNjk2YjlkMWJmY2QyMGU4
14
+ MDNjYjkxYzZmNzcwMGJjMTk1ZjcxNjUzMzdiMjliNGQ2OGIzZWVlYjA1NTJh
15
+ NmQwNDRjZTRmOGZmMTA5ODVjN2EwM2FmYzMxODA1MmE4MzE0YjI=
@@ -1,7 +1,7 @@
1
1
  PATH
2
2
  remote: .
3
3
  specs:
4
- whacamole (0.1.0)
4
+ whacamole (0.2.0)
5
5
 
6
6
  GEM
7
7
  remote: https://rubygems.org/
data/README.md CHANGED
@@ -8,15 +8,15 @@ swapping to disk (aka get super slow).
8
8
 
9
9
  Here’s what Heroku says about dyno memory usage:
10
10
 
11
- > Dynos are available in 1X or 2X sizes and are allocated 512MB or 1024MB respectively.
11
+ > Dynos are available in a few different sizes. The maximum amount of RAM available to your application depends on the dyno size you use.
12
12
  >
13
13
  > Dynos whose processes exceed their memory quota are identified by an R14 error in the logs. This doesn’t terminate the process, but it does warn of deteriorating application conditions: memory used above quota will swap out to disk, which substantially degrades dyno performance.
14
+ >
15
+ > If the memory size of your dyno keeps growing until it reaches five times its quota (for a 1X dyno, 512MB x 5 = 2.5GB), the dyno manager will restart your dyno with an R15 error.
14
16
  >
15
- > If the memory size keeps growing until it reaches three times its quota, the dyno manager will restart your dyno with an R15 error.
16
- >
17
- > - From https://devcenter.heroku.com/articles/dynos on 8/8/13
17
+ > - From https://devcenter.heroku.com/articles/dynos on 3/12/14
18
18
 
19
- Heroku dynos swap to disk for up to 3GB. That is not good and that is the problem whacamole addresses.
19
+ Heroku dynos swap to disk for up to 5GB (2X dynos) or up to THIRTY GIGABYTES (PX dynos). That is not good and that is the problem whacamole addresses.
20
20
 
21
21
  # Usage
22
22
 
@@ -45,6 +45,12 @@ end
45
45
  Whacamole.configure("ANOTHER HEROKU APP") do |config|
46
46
  config.api_token = ENV['HEROKU_API_TOKEN'] # you could also paste your token in here as a string
47
47
  end
48
+
49
+ # you can specify which dynos to watch for each app (default: `web`):
50
+ Whacamole.configure("HEROKU APP WITH MULTIPLE DYNO TYPES") do |config|
51
+ config.api_token = ENV['HEROKU_API_TOKEN'] # you could also paste your token in here as a string
52
+ config.dynos = %w{web worker}
53
+ end
48
54
  ```
49
55
 
50
56
  Add whacamole to your Procfile, specifying the config file you created:
@@ -62,3 +68,31 @@ $ foreman start whacamole
62
68
  # on heroku
63
69
  $ heroku ps:scale whacamole=1 --app YOUR_APP_NAME
64
70
  ```
71
+
72
+ # Events
73
+
74
+ Each ping and restart is available to you, for example in case you want to see with your own eyes that it's working.
75
+
76
+ Methods on DynoSize events
77
+ * event.process (the heroku process, eg "web.1")
78
+ * event.size (dyno size, eg 444.06)
79
+ * event.units (units for the size, eg "MB")
80
+
81
+ Methods on DynoRestart events
82
+ * event.process (the heroku process, eg "web.1")
83
+
84
+ To access the events, add a handler in your config. Event handlers take a single argument, the event. This handler will log the event in your Heroku logs:
85
+
86
+ ```ruby
87
+ Whacamole.configure("HEROKU APP NAME") do |config|
88
+ config.event_handler = lambda do |e|
89
+ puts e.inspect.to_s
90
+ end
91
+ end
92
+ ```
93
+
94
+ ## Self Promotion
95
+
96
+ If you like Whacamole, help spread the word! Tell your friends, or at the very least star the repo on github.
97
+
98
+ For more heroku goodness, check out http://github.com/arches/table_print and http://github.com/arches/marco-polo
@@ -16,7 +16,7 @@ module Whacamole
16
16
  threads = []
17
17
  @@config.each do |app_name, config|
18
18
  threads << Thread.new do
19
- heroku = HerokuWrapper.new(app_name, config.api_token)
19
+ heroku = HerokuWrapper.new(app_name, config.api_token, config.dynos)
20
20
 
21
21
  while true
22
22
  stream_url = heroku.create_log_session
@@ -27,4 +27,3 @@ module Whacamole
27
27
  threads.collect(&:join)
28
28
  end
29
29
  end
30
-
@@ -1,11 +1,11 @@
1
1
  module Whacamole
2
2
  class Config
3
- attr_accessor :app_name, :api_token, :event_handler
3
+ attr_accessor :app_name, :api_token, :event_handler, :dynos
4
4
 
5
5
  def initialize(app_name)
6
6
  self.app_name = app_name
7
7
  self.event_handler ||= lambda { |e| puts e.inspect.to_s }
8
+ self.dynos ||= %w{web}
8
9
  end
9
10
  end
10
11
  end
11
-
@@ -4,13 +4,14 @@ require 'json'
4
4
 
5
5
  module Whacamole
6
6
  class HerokuWrapper
7
- attr_accessor :api_token, :app_name
7
+ attr_accessor :api_token, :app_name, :dynos
8
8
 
9
9
  RESTART_RATE_LIMIT = 30*60
10
10
 
11
- def initialize(app_name, api_token)
11
+ def initialize(app_name, api_token, dynos)
12
12
  self.app_name = app_name
13
13
  self.api_token = api_token
14
+ self.dynos = dynos
14
15
  end
15
16
 
16
17
  def create_log_session
@@ -69,4 +70,3 @@ module Whacamole
69
70
  end
70
71
  end
71
72
  end
72
-
@@ -9,6 +9,7 @@ module Whacamole
9
9
  def initialize(url, restart_handler, &blk)
10
10
  @url = url
11
11
  @restart_handler = restart_handler
12
+ @dynos = restart_handler.dynos
12
13
  @event_handler = blk
13
14
  end
14
15
 
@@ -50,21 +51,22 @@ module Whacamole
50
51
 
51
52
  def memory_size_from_chunk(chunk)
52
53
  sizes = []
54
+ dynos_regexp = Regexp.new('(' + @dynos.join('|') + ')\.\d+')
53
55
 
54
56
  # new log format
55
57
  chunk.split("\n").select{|line| line.include? "sample#memory_total"}.each do |line|
56
- dyno = line.match(/web\.\d+/)
58
+ dyno = line.match(dynos_regexp)
57
59
  next unless dyno
58
60
  size = line.match(/sample#memory_total=([\d\.]+)/)
59
- sizes << [dyno[0], size[1]]
61
+ sizes << [dyno[0], size[1]] unless size.nil?
60
62
  end
61
63
 
62
64
  # old log format
63
65
  chunk.split("\n").select{|line| line.include? "measure=memory_total"}.each do |line|
64
- dyno = line.match(/web\.\d+/)
66
+ dyno = line.match(dynos_regexp)
65
67
  next unless dyno
66
68
  size = line.match(/val=([\d\.]+)/)
67
- sizes << [dyno[0], size[1]]
69
+ sizes << [dyno[0], size[1]] unless size.nil?
68
70
  end
69
71
 
70
72
  sizes
@@ -87,6 +89,3 @@ module Whacamole
87
89
  end
88
90
  end
89
91
  end
90
-
91
-
92
-
@@ -1,4 +1,4 @@
1
1
  module Whacamole
2
- VERSION = "0.2.0"
2
+ VERSION = "1.0.0"
3
3
  end
4
4
 
@@ -6,6 +6,10 @@ describe Whacamole::Config do
6
6
  c = Whacamole::Config.new("production")
7
7
  c.app_name.should == "production"
8
8
  end
9
+
10
+ it "sets default dyno to watch to web" do
11
+ c = Whacamole::Config.new("production")
12
+ c.dynos.should == %w{web}
13
+ end
9
14
  end
10
15
  end
11
-
@@ -2,7 +2,13 @@ require 'spec_helper'
2
2
 
3
3
  # TODO: use VCR instead of these method expectations
4
4
  describe Whacamole::HerokuWrapper do
5
- let(:h) { Whacamole::HerokuWrapper.new("staging", "foobar") }
5
+ let(:h) { Whacamole::HerokuWrapper.new("staging", "foobar", %w{web worker}) }
6
+
7
+ describe "dynos" do
8
+ it "returns dyno types to monitor as given to initialize" do
9
+ h.dynos.should == %w{web worker}
10
+ end
11
+ end
6
12
 
7
13
  describe "authorization" do
8
14
  it "base64-encodes the api token and a preceding colon" do
@@ -16,6 +16,10 @@ class RestartHandler
16
16
  def restart(process)
17
17
  true
18
18
  end
19
+
20
+ def dynos
21
+ %w{web worker}
22
+ end
19
23
  end
20
24
 
21
25
  describe Whacamole::Stream do
@@ -67,6 +71,19 @@ describe Whacamole::Stream do
67
71
  end
68
72
  end
69
73
 
74
+ it "handles dyno types specified in restart handler" do
75
+ stream.dispatch_handlers <<-CHUNK
76
+ 2013-08-22T16:39:22.919536+00:00 heroku[web.2]: source=web.2 dyno=heroku.772639.a334caa8-736c-48b3-bac2-d366f75d7fa0 sample#memory_total=101MB sample#memory_rss=581.75MB sample#memory_cache=0.16MB sample#memory_swap=0.03MB sample#memory_pgpgin=0pages sample#memory_pgpgout=179329pages
77
+ 2013-08-22T16:39:22.919536+00:00 heroku[worker.3]: source=worker.3 dyno=heroku.772639.a334caa8-736c-48b3-bac2-d366f75d7fa0 sample#memory_total=101MB sample#memory_rss=581.75MB sample#memory_cache=0.16MB sample#memory_swap=0.03MB sample#memory_pgpgin=0pages sample#memory_pgpgout=179329pages
78
+ 2013-08-22T16:39:22.919536+00:00 heroku[whacamole.1]: source=whacamole.1 dyno=heroku.772639.a334caa8-736c-48b3-bac2-d366f75d7fa0 sample#memory_total=1001MB sample#memory_rss=581.75MB sample#memory_cache=0.16MB sample#memory_swap=0.03MB sample#memory_pgpgin=0pages sample#memory_pgpgout=179329pages
79
+ CHUNK
80
+
81
+ eh.events.length.should == 2
82
+
83
+ eh.events.first.process.should == "web.2"
84
+ eh.events.last.process.should == "worker.3"
85
+ end
86
+
70
87
  context "when memory usages is over the threshold" do
71
88
  it "kicks off a restart" do
72
89
  restart_handler.should_receive(:restart).with("web.2")
metadata CHANGED
@@ -1,20 +1,18 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: whacamole
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.2.0
5
- prerelease:
4
+ version: 1.0.0
6
5
  platform: ruby
7
6
  authors:
8
7
  - Chris Doyle
9
8
  autorequire:
10
9
  bindir: bin
11
10
  cert_chain: []
12
- date: 2013-08-30 00:00:00.000000000Z
11
+ date: 2014-10-27 00:00:00.000000000 Z
13
12
  dependencies:
14
13
  - !ruby/object:Gem::Dependency
15
14
  name: rspec
16
15
  requirement: !ruby/object:Gem::Requirement
17
- none: false
18
16
  requirements:
19
17
  - - ~>
20
18
  - !ruby/object:Gem::Version
@@ -22,7 +20,6 @@ dependencies:
22
20
  type: :development
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
@@ -30,7 +27,6 @@ dependencies:
30
27
  - !ruby/object:Gem::Dependency
31
28
  name: rake
32
29
  requirement: !ruby/object:Gem::Requirement
33
- none: false
34
30
  requirements:
35
31
  - - ~>
36
32
  - !ruby/object:Gem::Version
@@ -38,7 +34,6 @@ dependencies:
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
@@ -73,27 +68,26 @@ files:
73
68
  homepage: http://github.com/arches/whacamole
74
69
  licenses:
75
70
  - MIT
71
+ metadata: {}
76
72
  post_install_message:
77
73
  rdoc_options: []
78
74
  require_paths:
79
75
  - lib
80
76
  required_ruby_version: !ruby/object:Gem::Requirement
81
- none: false
82
77
  requirements:
83
78
  - - ! '>='
84
79
  - !ruby/object:Gem::Version
85
80
  version: '0'
86
81
  required_rubygems_version: !ruby/object:Gem::Requirement
87
- none: false
88
82
  requirements:
89
83
  - - ! '>='
90
84
  - !ruby/object:Gem::Version
91
85
  version: '0'
92
86
  requirements: []
93
87
  rubyforge_project:
94
- rubygems_version: 1.8.19
88
+ rubygems_version: 2.0.7
95
89
  signing_key:
96
- specification_version: 3
90
+ specification_version: 4
97
91
  summary: restart heroku dynos that run out of RAM instead of swapping to disk
98
92
  test_files:
99
93
  - spec/config_spec.rb