capelinhos 0.3.0 → 0.5.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
  SHA256:
3
- metadata.gz: 7753401a07794ffb5f98ee8d61bb19abc0f9c38b29c3a25f7dfe7eb67ce99867
4
- data.tar.gz: d6fea5b09f8433d7ae368def581eee16eba89e5e1436c8783de6721f33963472
3
+ metadata.gz: 259f8c17e8e1d4907906ad0a5a69bc4c7ff46f284f4492657bdcdd9eb77dc1ed
4
+ data.tar.gz: 16156b9dd200f5ad4add2b66e130044f3bf4c0caf052370ff382b3ef299c89b7
5
5
  SHA512:
6
- metadata.gz: 2c83bd6ad0b19db0ce7552eab09ede1db1b9b8ebb34ce61d3adefb1a8e403349cbe614a1a5851ba0f8454d776c9908ccadf4bb21af78835a4ad8903b419aeadd
7
- data.tar.gz: 5e38b421400e9e4dd07132c46c2546838a15eb7ca6570e481ebd34bef2f5b1ea1e82cf47bc61f2306449a07f934bee7059be7097b9c8cc1c0d64ca9fe0fb8df7
6
+ metadata.gz: 37e66c20f4a62e8965766564aaee96d66e730c36011872cbd62fdb93d8061e4143255fdff603652d62ac542372ac935196d11698d9e49ada9b9152f5afd8bfb3
7
+ data.tar.gz: 99551500dbf149aeea945c4cad61950cf4b36a752381cc2b8791b9af06b1ff2e674d0828bb296b54e6bc4eb9e4f34ad541fb42d446709861735bfb1854c23109
data/CHANGELOG.md ADDED
@@ -0,0 +1,5 @@
1
+ ## [Unreleased]
2
+
3
+ ## [0.1.0] - 2024-03-30
4
+
5
+ - Initial release
data/LICENSE.txt ADDED
@@ -0,0 +1,21 @@
1
+ The MIT License (MIT)
2
+
3
+ Copyright (c) 2024 Adam Hallett
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
13
+ all 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
21
+ THE SOFTWARE.
data/README.md ADDED
@@ -0,0 +1,36 @@
1
+ # Capelinhos
2
+
3
+ This gem gracefully stops Passenger Ruby processes that have exceeded a memory threshold. It is meant to be added to cron and run at an interval of your choosing.
4
+
5
+ If Phusion Passenger is configured with `PassengerMinInstances` and the number of processes is under that number, then a new process should replace the processes that were shutdown.
6
+
7
+ Note: This doesn't skip active long running sessions. This feature be added as a default in the future.
8
+
9
+ ## Installation
10
+
11
+ Install the gem and add to the application's Gemfile by executing:
12
+
13
+ $ bundle add capelinhos
14
+
15
+ If bundler is not being used to manage dependencies, install the gem by executing:
16
+
17
+ $ gem install capelinhos
18
+
19
+ ## Usage
20
+
21
+ # kill up to 3 processes that use more than 400 megabytes
22
+ $ capelinos --max-memory 400 --max-processes 3
23
+
24
+ ## Development
25
+
26
+ After checking out the repo, run `bin/setup` to install dependencies. You can also run `bin/console` for an interactive prompt that will allow you to experiment.
27
+
28
+ 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 the created tag, and push the `.gem` file to [rubygems.org](https://rubygems.org).
29
+
30
+ ## Contributing
31
+
32
+ Bug reports and pull requests are welcome on GitHub at https://github.com/[USERNAME]/capelinhos.
33
+
34
+ ## License
35
+
36
+ The gem is available as open source under the terms of the [MIT License](https://opensource.org/licenses/MIT).
data/Rakefile ADDED
@@ -0,0 +1,4 @@
1
+ # frozen_string_literal: true
2
+
3
+ require "bundler/gem_tasks"
4
+ task default: %i[]
@@ -0,0 +1,15 @@
1
+ {
2
+ "folders":
3
+ [
4
+ {
5
+ "path": ".",
6
+ "folder_exclude_patterns": []
7
+ }
8
+ ],
9
+ "settings": {
10
+ "ensure_newline_at_eof_on_save": true,
11
+ "tab_size": 2,
12
+ "translate_tabs_to_spaces": true,
13
+ "trim_trailing_white_space_on_save": true
14
+ }
15
+ }
data/exe/capelinhos ADDED
@@ -0,0 +1,63 @@
1
+ #!/usr/bin/env ruby
2
+ # frozen_string_literal: true
3
+
4
+ require 'bundler/setup'
5
+ require 'optparse'
6
+ require 'capelinhos'
7
+
8
+ source_root = File.expand_path("..", File.dirname(__FILE__))
9
+ $LOAD_PATH.unshift("#{source_root}/src/ruby_supportlib")
10
+ begin
11
+ require 'rubygems'
12
+ rescue LoadError
13
+ end
14
+ require 'phusion_passenger'
15
+
16
+ PhusionPassenger.locate_directories
17
+ PhusionPassenger.require_passenger_lib 'constants'
18
+ PhusionPassenger.require_passenger_lib 'platform_info'
19
+ PhusionPassenger.require_passenger_lib 'admin_tools/instance_registry'
20
+ PhusionPassenger.require_passenger_lib 'platform_info/ruby'
21
+ PhusionPassenger.require_passenger_lib 'admin_tools/memory_stats'
22
+ PhusionPassenger.require_passenger_lib 'admin_tools/instance_registry'
23
+ PhusionPassenger.require_passenger_lib 'config/utils'
24
+ PhusionPassenger.require_passenger_lib 'utils/ansi_colors'
25
+ include PhusionPassenger
26
+ include PhusionPassenger::SharedConstants
27
+ include PhusionPassenger::AdminTools
28
+ include PhusionPassenger::Utils::AnsiColors
29
+
30
+ options = {}
31
+ OptionParser.new do |opts|
32
+ opts.banner = "Usage: capelinhos --max-memory 320 --max-processes 3"
33
+
34
+ opts.on("--max-memory", "--max-memory MAX_MEMORY", Numeric, "Maximum memory in megabytes to trigger shutdown.") do |n|
35
+ options[:max_memory] = n
36
+ end
37
+
38
+ opts.on("--max-processes", "--max-processes=NUMBER", Numeric, "Maximum number of processes to gracefully shutdown.") do |n|
39
+ options[:max_processes] = n
40
+ end
41
+
42
+ opts.on("-h", "--help", "Prints this help") do
43
+ puts opts
44
+ exit
45
+ end
46
+ end.parse!
47
+
48
+ if !options[:max_memory]
49
+ puts "Version: #{Capelinhos::VERSION}"
50
+ puts "--max-memory is required"
51
+ exit(0)
52
+ end
53
+
54
+ if !options[:max_processes]
55
+ puts "Version: #{Capelinhos::VERSION}"
56
+ puts "--max-processes is required"
57
+ exit(0)
58
+ end
59
+
60
+
61
+ processor = Capelinhos::Processor.new(memory_threshold: options[:max_memory],
62
+ process_limit: options[:max_processes])
63
+ processor.kill_memory_hogs!()
@@ -0,0 +1,62 @@
1
+ require 'json'
2
+ require 'net/http'
3
+ require 'byebug' if ENV['DEBUG']
4
+
5
+ module Capelinhos
6
+ class Processor
7
+ def initialize(memory_threshold:, process_limit:)
8
+ @memory_threshold = memory_threshold
9
+ @process_limit = process_limit
10
+ end
11
+
12
+ def kill_memory_hogs!
13
+ processes_killed = 0
14
+ stats = AdminTools::MemoryStats.new
15
+ processes = stats.passenger_processes
16
+
17
+ processes.each do |process|
18
+ if process.name.include?('RubyApp')
19
+ rss_megabytes = process.rss / 1024
20
+ if rss_megabytes > @memory_threshold
21
+ shutdown_process(process.pid)
22
+ processes_killed += 1
23
+ end
24
+
25
+ if processes_killed >= @process_limit
26
+ break
27
+ end
28
+ end
29
+ end
30
+ end
31
+
32
+ private
33
+
34
+ def shutdown_process(pid)
35
+ _instance = instance
36
+ request = Net::HTTP::Post.new("/pool/detach_process.json")
37
+ request.body = JSON.generate({pid: pid})
38
+ try_performing_ro_admin_basic_auth(request, _instance)
39
+ response = _instance.http_request("agents.s/core_api", request)
40
+
41
+ if response.code.to_i / 100 == 2
42
+ puts "Successfully detached PID: #{pid}"
43
+ else
44
+ puts "Process (#{pid}) could not be shutdown: #{response.body}"
45
+ end
46
+ end
47
+
48
+ def instance
49
+ instances = InstanceRegistry.new.list
50
+ instances.first
51
+ end
52
+
53
+ def try_performing_ro_admin_basic_auth(request, instance)
54
+ begin
55
+ password = instance.read_only_admin_password
56
+ rescue Errno::EACCES
57
+ return
58
+ end
59
+ request.basic_auth("ro_admin", password)
60
+ end
61
+ end
62
+ end
@@ -0,0 +1,5 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Capelinhos
4
+ VERSION = "0.5.0"
5
+ end
data/lib/capelinhos.rb ADDED
@@ -0,0 +1,8 @@
1
+ # frozen_string_literal: true
2
+
3
+ require_relative "capelinhos/version"
4
+ require_relative "capelinhos/processor"
5
+
6
+ module Capelinhos
7
+ class Error < StandardError; end
8
+ end
@@ -0,0 +1,4 @@
1
+ module Capelinhos
2
+ VERSION: String
3
+ # See the writing guide of rbs: https://github.com/ruby/rbs#guides
4
+ end
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: capelinhos
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.3.0
4
+ version: 0.5.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Adam Hallett
@@ -55,10 +55,21 @@ dependencies:
55
55
  description:
56
56
  email:
57
57
  - adam.t.hallett@gmail.com
58
- executables: []
58
+ executables:
59
+ - capelinhos
59
60
  extensions: []
60
61
  extra_rdoc_files: []
61
- files: []
62
+ files:
63
+ - CHANGELOG.md
64
+ - LICENSE.txt
65
+ - README.md
66
+ - Rakefile
67
+ - capelinhos.sublime-project
68
+ - exe/capelinhos
69
+ - lib/capelinhos.rb
70
+ - lib/capelinhos/processor.rb
71
+ - lib/capelinhos/version.rb
72
+ - sig/capelinhos.rbs
62
73
  homepage: https://github.com/atomical/capelinhos
63
74
  licenses:
64
75
  - MIT