sidekiq-recycler 0.1.0

Sign up to get free protection for your applications and to get access to all the features.
@@ -0,0 +1,7 @@
1
+ ---
2
+ SHA1:
3
+ metadata.gz: eb953e946bdabfda52012df96add214084291736
4
+ data.tar.gz: 74e8809c6ae424ba44927c0c84509a7784bd1066
5
+ SHA512:
6
+ metadata.gz: 558a89279d337b8f4d9fea71c9e561b49e24a509bf35500e64f26ae54144e9e5e062757e9e331e67732d4097e8a82de8a6338a304b2ef685fd8885b5b4312385
7
+ data.tar.gz: e86bb903e9188e6ce52e1df1706841d96d27491a4433977ef20b3a8d45d48c9299c9e783a4e794ba2655124db90e7be42176579b152d713829256d40c2865891
data/Gemfile ADDED
@@ -0,0 +1,17 @@
1
+
2
+ source "https://rubygems.org"
3
+
4
+ gem "sidekiq"
5
+
6
+ group :local do
7
+ gem "sidekiq-recycler", :path => "."
8
+ end
9
+
10
+ group :development do
11
+ gem "rake"
12
+ gem "jeweler"
13
+ gem "yard"
14
+ gem "logging"
15
+ gem "easycov"
16
+ gem "micron", :github => "chetan/micron"
17
+ end
@@ -0,0 +1,107 @@
1
+ GIT
2
+ remote: git://github.com/chetan/micron.git
3
+ revision: d722ad58ca390cdaf01d27d77aea1fbe951d0bca
4
+ specs:
5
+ micron (0.1.0)
6
+ colorize
7
+ easycov
8
+ hitimes
9
+
10
+ PATH
11
+ remote: .
12
+ specs:
13
+ sidekiq-recycler (0.1.0)
14
+ sidekiq
15
+
16
+ GEM
17
+ remote: https://rubygems.org/
18
+ specs:
19
+ addressable (2.3.5)
20
+ builder (3.2.2)
21
+ celluloid (0.15.2)
22
+ timers (~> 1.1.0)
23
+ colorize (0.6.0)
24
+ connection_pool (1.1.0)
25
+ easycov (0.3.1)
26
+ multi_json
27
+ simplecov
28
+ simplecov-console
29
+ simplecov-html
30
+ faraday (0.8.8)
31
+ multipart-post (~> 1.2.0)
32
+ git (1.2.6)
33
+ github_api (0.10.1)
34
+ addressable
35
+ faraday (~> 0.8.1)
36
+ hashie (>= 1.2)
37
+ multi_json (~> 1.4)
38
+ nokogiri (~> 1.5.2)
39
+ oauth2
40
+ hashie (2.0.5)
41
+ highline (1.6.19)
42
+ hirb (0.7.1)
43
+ hitimes (1.2.1)
44
+ httpauth (0.2.0)
45
+ jeweler (1.8.8)
46
+ builder
47
+ bundler (~> 1.0)
48
+ git (>= 1.2.5)
49
+ github_api (= 0.10.1)
50
+ highline (>= 1.6.15)
51
+ nokogiri (= 1.5.10)
52
+ rake
53
+ rdoc
54
+ json (1.8.0)
55
+ jwt (0.1.8)
56
+ multi_json (>= 1.5)
57
+ little-plugger (1.1.3)
58
+ logging (1.8.1)
59
+ little-plugger (>= 1.1.3)
60
+ multi_json (>= 1.3.6)
61
+ multi_json (1.8.1)
62
+ multi_xml (0.5.5)
63
+ multipart-post (1.2.0)
64
+ nokogiri (1.5.10)
65
+ oauth2 (0.9.2)
66
+ faraday (~> 0.8)
67
+ httpauth (~> 0.2)
68
+ jwt (~> 0.1.4)
69
+ multi_json (~> 1.0)
70
+ multi_xml (~> 0.5)
71
+ rack (~> 1.2)
72
+ rack (1.5.2)
73
+ rake (10.1.0)
74
+ rdoc (4.0.1)
75
+ json (~> 1.4)
76
+ redis (3.0.5)
77
+ redis-namespace (1.3.1)
78
+ redis (~> 3.0.0)
79
+ sidekiq (2.15.1)
80
+ celluloid (>= 0.15.1)
81
+ connection_pool (>= 1.0.0)
82
+ json
83
+ redis (>= 3.0.4)
84
+ redis-namespace (>= 1.3.1)
85
+ simplecov (0.7.1)
86
+ multi_json (~> 1.0)
87
+ simplecov-html (~> 0.7.1)
88
+ simplecov-console (0.1.3)
89
+ colorize
90
+ hirb
91
+ simplecov
92
+ simplecov-html (0.7.1)
93
+ timers (1.1.0)
94
+ yard (0.8.7.2)
95
+
96
+ PLATFORMS
97
+ ruby
98
+
99
+ DEPENDENCIES
100
+ easycov
101
+ jeweler
102
+ logging
103
+ micron!
104
+ rake
105
+ sidekiq
106
+ sidekiq-recycler!
107
+ yard
@@ -0,0 +1,34 @@
1
+ # Sidekiq Recycler
2
+ Gracefully recycle sidekiq processes that use too much memory
3
+
4
+ sidekiq-recycler is a simple middleware which checks the process's RSS usage on
5
+ the completion of each job. When the usage surpasses a predefined limit, the process
6
+ will gracefully terminate. If any jobs are still running beyond a further time threshold,
7
+ they will be killed and requeued.
8
+
9
+
10
+ ## Quickstart
11
+
12
+ ```
13
+ $ gem install sidekiq-recycler
14
+ ```
15
+
16
+ ```ruby
17
+ # Add the middleware
18
+ require "sidekiq"
19
+ require "sidekiq/recycler"
20
+
21
+ Sidekiq.configure_server do |config|
22
+ config.server_middleware do |chain|
23
+ chain.add Sidekiq::Recycler, :mem_limit => 300_000, :hard_limit_sec => 300
24
+ end
25
+ end
26
+ ```
27
+
28
+
29
+ ## Configuration
30
+
31
+ Two options are exposed by the middleware:
32
+
33
+ * mem_limit: RSS usage limit, in megabytes
34
+ * hard_limit_sec: time in seconds to wait for jobs to finish, after graceful shutdown initiated
@@ -0,0 +1,33 @@
1
+ # encoding: utf-8
2
+
3
+ require 'rubygems'
4
+ require 'bundler'
5
+ begin
6
+ Bundler.setup(:default, :development)
7
+ rescue Bundler::BundlerError => e
8
+ $stderr.puts e.message
9
+ $stderr.puts "Run `bundle install` to install missing gems"
10
+ exit e.status_code
11
+ end
12
+ require 'rake'
13
+ require 'jeweler'
14
+
15
+ Jeweler::Tasks.new do |gemspec|
16
+ gemspec.name = "sidekiq-recycler"
17
+ gemspec.summary = "Recycle large sidekiq processes"
18
+ gemspec.description = "Gracefully recycle sidekiq processes that use too much memory"
19
+ gemspec.email = "chetan@pixelcop.net"
20
+ gemspec.homepage = "http://github.com/chetan/sidekiq-recycler"
21
+ gemspec.authors = ["Chetan Sarva"]
22
+ gemspec.license = "MIT"
23
+ end
24
+ Jeweler::RubygemsDotOrgTasks.new
25
+
26
+ Dir['tasks/**/*.rake'].each { |rake| load rake }
27
+
28
+ task :default => :test
29
+
30
+ require 'yard'
31
+ YARD::Rake::YardocTask.new
32
+
33
+ require "easycov/rake"
data/VERSION ADDED
@@ -0,0 +1 @@
1
+ 0.1.0
@@ -0,0 +1,78 @@
1
+
2
+ module Sidekiq
3
+ class Recycler
4
+
5
+ # used to avoid race conditions when recycling
6
+ @@mutex = Mutex.new
7
+
8
+ # avoid extra spam after hard limit reached
9
+ @@recycled = false
10
+
11
+ def initialize(opts={})
12
+ @mem_limit = opts[:mem_limit] || 300_000 # default is 300mb
13
+ @hard_limit_sec = opts[:hard_limit_sec] || 300 # default to 300 sec
14
+ end
15
+
16
+ def call(worker, job, queue)
17
+ begin
18
+ yield
19
+
20
+ ensure
21
+ # check mem usage here
22
+ rss = `ps -o rss= -p #{$$}`.to_i
23
+ if rss > @mem_limit then
24
+
25
+ # handle race conditions with many jobs/threads completing
26
+ # at the same time
27
+ return if !@@mutex.try_lock or @@recycled
28
+ @@recycled = true
29
+
30
+ Sidekiq.logger.warn "Recycler threshold reached: #{rss} > #{@mem_limit}"
31
+ Sidekiq.logger.warn "Attempting to stop gracefully"
32
+
33
+ # soft_limit_sec = @soft_limit_sec
34
+ hard_limit_sec = @hard_limit_sec
35
+ launcher = nil
36
+
37
+ Thread.new do
38
+ Celluloid::Actor.all.each do |actor|
39
+ # tell sidekiq to exit gracefully
40
+ # stops accepting new work and kills all waiting ("ready") threads
41
+ if actor.kind_of? Sidekiq::Launcher then
42
+ launcher = actor
43
+ Thread.new do
44
+ actor.manager.async.stop
45
+ end
46
+ end
47
+ end
48
+ end
49
+
50
+ Thread.new do
51
+ # wait until all threads have exited
52
+ while true do
53
+ sleep 1
54
+ next if launcher.nil?
55
+ if launcher.manager.ready.empty? and launcher.manager.busy.empty? then
56
+ Sidekiq.logger.info "All threads stopped; exiting now!"
57
+ exit
58
+ end
59
+ end
60
+ end
61
+
62
+ Thread.new do
63
+ # wait for hard limit sec then kill
64
+ sleep hard_limit_sec
65
+ Sidekiq.logger.warn "Hard limit of #{hard_limit_sec}sec reached; sending TERM signal"
66
+ if !launcher.nil? then
67
+ launcher.stop
68
+ else
69
+ Process.kill("TERM", $$)
70
+ end
71
+ end
72
+
73
+ end
74
+ end
75
+ end
76
+
77
+ end
78
+ end
@@ -0,0 +1,69 @@
1
+ # Generated by jeweler
2
+ # DO NOT EDIT THIS FILE DIRECTLY
3
+ # Instead, edit Jeweler::Tasks in Rakefile, and run 'rake gemspec'
4
+ # -*- encoding: utf-8 -*-
5
+ # stub: sidekiq-recycler 0.1.0 ruby lib
6
+
7
+ Gem::Specification.new do |s|
8
+ s.name = "sidekiq-recycler"
9
+ s.version = "0.1.0"
10
+
11
+ s.required_rubygems_version = Gem::Requirement.new(">= 0") if s.respond_to? :required_rubygems_version=
12
+ s.authors = ["Chetan Sarva"]
13
+ s.date = "2013-10-14"
14
+ s.description = "Gracefully recycle sidekiq processes that use too much memory"
15
+ s.email = "chetan@pixelcop.net"
16
+ s.extra_rdoc_files = [
17
+ "README.md"
18
+ ]
19
+ s.files = [
20
+ "Gemfile",
21
+ "Gemfile.lock",
22
+ "README.md",
23
+ "Rakefile",
24
+ "VERSION",
25
+ "lib/sidekiq/recycler.rb",
26
+ "sidekiq-recycler.gemspec",
27
+ "test/helper.rb",
28
+ "test/support/create_jobs.rb",
29
+ "test/support/sidekiq_mock_fetcher.rb",
30
+ "test/support/workers.rb",
31
+ "test/test_recycler.rb"
32
+ ]
33
+ s.homepage = "http://github.com/chetan/sidekiq-recycler"
34
+ s.licenses = ["MIT"]
35
+ s.require_paths = ["lib"]
36
+ s.rubygems_version = "2.1.5"
37
+ s.summary = "Recycle large sidekiq processes"
38
+
39
+ if s.respond_to? :specification_version then
40
+ s.specification_version = 4
41
+
42
+ if Gem::Version.new(Gem::VERSION) >= Gem::Version.new('1.2.0') then
43
+ s.add_runtime_dependency(%q<sidekiq>, [">= 0"])
44
+ s.add_development_dependency(%q<rake>, [">= 0"])
45
+ s.add_development_dependency(%q<jeweler>, [">= 0"])
46
+ s.add_development_dependency(%q<yard>, [">= 0"])
47
+ s.add_development_dependency(%q<logging>, [">= 0"])
48
+ s.add_development_dependency(%q<easycov>, [">= 0"])
49
+ s.add_development_dependency(%q<micron>, [">= 0"])
50
+ else
51
+ s.add_dependency(%q<sidekiq>, [">= 0"])
52
+ s.add_dependency(%q<rake>, [">= 0"])
53
+ s.add_dependency(%q<jeweler>, [">= 0"])
54
+ s.add_dependency(%q<yard>, [">= 0"])
55
+ s.add_dependency(%q<logging>, [">= 0"])
56
+ s.add_dependency(%q<easycov>, [">= 0"])
57
+ s.add_dependency(%q<micron>, [">= 0"])
58
+ end
59
+ else
60
+ s.add_dependency(%q<sidekiq>, [">= 0"])
61
+ s.add_dependency(%q<rake>, [">= 0"])
62
+ s.add_dependency(%q<jeweler>, [">= 0"])
63
+ s.add_dependency(%q<yard>, [">= 0"])
64
+ s.add_dependency(%q<logging>, [">= 0"])
65
+ s.add_dependency(%q<easycov>, [">= 0"])
66
+ s.add_dependency(%q<micron>, [">= 0"])
67
+ end
68
+ end
69
+
@@ -0,0 +1,22 @@
1
+
2
+ require 'rubygems'
3
+ require 'bundler'
4
+ begin
5
+ Bundler.setup(:default, :development)
6
+ rescue Bundler::BundlerError => e
7
+ $stderr.puts e.message
8
+ $stderr.puts "Run `bundle install` to install missing gems"
9
+ exit e.status_code
10
+ end
11
+
12
+ require "logging"
13
+ require "micron"
14
+
15
+ $LOAD_PATH.unshift(File.dirname(__FILE__))
16
+
17
+ EasyCov.path = "coverage"
18
+ EasyCov.filters << EasyCov::IGNORE_GEMS << EasyCov::IGNORE_STDLIB
19
+ EasyCov.filters << lambda { |filename|
20
+ filename =~ %r(#{EasyCov.root}/test/)
21
+ }
22
+ EasyCov.start
@@ -0,0 +1,9 @@
1
+ #!/usr/bin/env ruby
2
+
3
+ require File.expand_path("../workers", __FILE__)
4
+
5
+ ForeverWorker.perform_async()
6
+
7
+ 10.times do
8
+ HardWorker.perform_async(Time.now.to_f.to_s)
9
+ end
@@ -0,0 +1,91 @@
1
+
2
+ require "thread"
3
+ require "securerandom"
4
+
5
+ class MockFetcher
6
+
7
+ UnitOfWork = Struct.new(:queue, :message) do
8
+ def acknowledge
9
+ end
10
+ def queue_name
11
+ "jobs"
12
+ end
13
+ def requeue
14
+ end
15
+ end
16
+
17
+ attr_accessor :reader, :writer
18
+
19
+ def self.instance(opts=nil)
20
+ if @inst.nil? then
21
+ @inst = self.allocate
22
+ @inst.setup
23
+ end
24
+ @inst
25
+ end
26
+
27
+ class << self
28
+ alias_method :new, :instance
29
+ end
30
+
31
+ def setup
32
+ @reader, @writer = IO.pipe
33
+ @mutex = Mutex.new
34
+ end
35
+
36
+ def retrieve_work
37
+ @mutex.synchronize {
38
+ begin
39
+ return internal_fetch()
40
+ rescue Exception => ex
41
+ $stderr.puts ex
42
+ end
43
+ }
44
+ end
45
+
46
+ def self.bulk_requeue(*args)
47
+ # noop
48
+ end
49
+
50
+
51
+ private
52
+
53
+ def internal_fetch
54
+
55
+ data = case reader.readline.strip
56
+ when "forever"
57
+ {:jid => SecureRandom.hex(4),
58
+ :class => ForeverWorker.name, :args => []}
59
+
60
+ when "hard"
61
+ {:jid => SecureRandom.hex(4),
62
+ :class => HardWorker.name, :args => ["test"]}
63
+ end
64
+
65
+ return UnitOfWork.new("foobar", MultiJson.dump(data))
66
+ end
67
+
68
+ end
69
+
70
+ module Sidekiq
71
+ class Fetcher
72
+ def self.strategy
73
+ MockFetcher
74
+ end
75
+ end
76
+ end
77
+
78
+ Sidekiq::Logging.logger = Logging.logger[Sidekiq]
79
+
80
+ module Sidekiq
81
+ module Logging
82
+ def self.with_context(msg)
83
+ begin
84
+ ::Logging.mdc["sidekiq"] = msg
85
+ yield
86
+ ensure
87
+ ::Logging.mdc["sidekiq"] = nil
88
+ end
89
+ end
90
+ end
91
+ end
@@ -0,0 +1,40 @@
1
+
2
+ require "sidekiq"
3
+ require "sidekiq/recycler"
4
+
5
+ Sidekiq.configure_server do |config|
6
+ config.server_middleware do |chain|
7
+ chain.add Sidekiq::Recycler, :mem_limit => 100_000, :hard_limit_sec => 30
8
+ end
9
+ end
10
+
11
+ class ForeverWorker
12
+ @@worked = 0
13
+ include Sidekiq::Worker
14
+ def perform()
15
+ @@worked += 1
16
+ puts "working forever!"
17
+ while true
18
+ sleep 1
19
+ end
20
+ end
21
+
22
+ def self.times_worked
23
+ @@worked
24
+ end
25
+ end
26
+
27
+ class HardWorker
28
+ @@worked = 0
29
+ @@foo = []
30
+ include Sidekiq::Worker
31
+ def perform(msg)
32
+ @@foo << "hello world" * (4**10)
33
+ puts "perform.."
34
+ @@worked += 1
35
+ end
36
+
37
+ def self.times_worked
38
+ @@worked
39
+ end
40
+ end
@@ -0,0 +1,62 @@
1
+
2
+ require "helper"
3
+
4
+ require 'celluloid'
5
+ require 'sidekiq'
6
+ require 'sidekiq'
7
+ require 'sidekiq/cli'
8
+ require 'sidekiq/launcher'
9
+ require 'support/sidekiq_mock_fetcher'
10
+ require 'support/workers'
11
+
12
+ require 'micron/test_case/redir_logging'
13
+
14
+ class TestRecycler < Micron::TestCase
15
+
16
+ include Micron::TestCase::RedirLogging
17
+ @@redir_logger = Logging.logger.root
18
+
19
+ def setup
20
+ end
21
+
22
+ def teardown
23
+ @launcher.stop
24
+ Celluloid.shutdown
25
+ end
26
+
27
+ def test_recycler
28
+
29
+ opts = {
30
+ :timeout => 0,
31
+ }
32
+ @launcher = Sidekiq::Launcher.new(opts)
33
+ @launcher.run
34
+
35
+ # do something..
36
+ MockFetcher.instance.writer.puts "forever"
37
+
38
+ sleep 1
39
+ assert_equal 1, ForeverWorker.times_worked
40
+
41
+ 2.times do
42
+ MockFetcher.instance.writer.puts "hard"
43
+ end
44
+ sleep 1
45
+ assert_equal 2, HardWorker.times_worked
46
+
47
+ 5.times do
48
+ MockFetcher.instance.writer.puts "hard"
49
+ end
50
+
51
+ while HardWorker.times_worked < 7 do
52
+ sleep 0.1
53
+ Thread.pass
54
+ end
55
+
56
+ puts "over limit?!"
57
+ sleep 1
58
+ assert_equal 0, @launcher.manager.ready.size, "waiting threads should have been stopped"
59
+ assert_equal 1, @launcher.manager.busy.size, "only one thread still busy (sleeping forever)"
60
+ end
61
+
62
+ end
metadata ADDED
@@ -0,0 +1,154 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: sidekiq-recycler
3
+ version: !ruby/object:Gem::Version
4
+ version: 0.1.0
5
+ platform: ruby
6
+ authors:
7
+ - Chetan Sarva
8
+ autorequire:
9
+ bindir: bin
10
+ cert_chain: []
11
+ date: 2013-10-14 00:00:00.000000000 Z
12
+ dependencies:
13
+ - !ruby/object:Gem::Dependency
14
+ name: sidekiq
15
+ requirement: !ruby/object:Gem::Requirement
16
+ requirements:
17
+ - - '>='
18
+ - !ruby/object:Gem::Version
19
+ version: '0'
20
+ type: :runtime
21
+ prerelease: false
22
+ version_requirements: !ruby/object:Gem::Requirement
23
+ requirements:
24
+ - - '>='
25
+ - !ruby/object:Gem::Version
26
+ version: '0'
27
+ - !ruby/object:Gem::Dependency
28
+ name: rake
29
+ requirement: !ruby/object:Gem::Requirement
30
+ requirements:
31
+ - - '>='
32
+ - !ruby/object:Gem::Version
33
+ version: '0'
34
+ type: :development
35
+ prerelease: false
36
+ version_requirements: !ruby/object:Gem::Requirement
37
+ requirements:
38
+ - - '>='
39
+ - !ruby/object:Gem::Version
40
+ version: '0'
41
+ - !ruby/object:Gem::Dependency
42
+ name: jeweler
43
+ requirement: !ruby/object:Gem::Requirement
44
+ requirements:
45
+ - - '>='
46
+ - !ruby/object:Gem::Version
47
+ version: '0'
48
+ type: :development
49
+ prerelease: false
50
+ version_requirements: !ruby/object:Gem::Requirement
51
+ requirements:
52
+ - - '>='
53
+ - !ruby/object:Gem::Version
54
+ version: '0'
55
+ - !ruby/object:Gem::Dependency
56
+ name: yard
57
+ requirement: !ruby/object:Gem::Requirement
58
+ requirements:
59
+ - - '>='
60
+ - !ruby/object:Gem::Version
61
+ version: '0'
62
+ type: :development
63
+ prerelease: false
64
+ version_requirements: !ruby/object:Gem::Requirement
65
+ requirements:
66
+ - - '>='
67
+ - !ruby/object:Gem::Version
68
+ version: '0'
69
+ - !ruby/object:Gem::Dependency
70
+ name: logging
71
+ requirement: !ruby/object:Gem::Requirement
72
+ requirements:
73
+ - - '>='
74
+ - !ruby/object:Gem::Version
75
+ version: '0'
76
+ type: :development
77
+ prerelease: false
78
+ version_requirements: !ruby/object:Gem::Requirement
79
+ requirements:
80
+ - - '>='
81
+ - !ruby/object:Gem::Version
82
+ version: '0'
83
+ - !ruby/object:Gem::Dependency
84
+ name: easycov
85
+ requirement: !ruby/object:Gem::Requirement
86
+ requirements:
87
+ - - '>='
88
+ - !ruby/object:Gem::Version
89
+ version: '0'
90
+ type: :development
91
+ prerelease: false
92
+ version_requirements: !ruby/object:Gem::Requirement
93
+ requirements:
94
+ - - '>='
95
+ - !ruby/object:Gem::Version
96
+ version: '0'
97
+ - !ruby/object:Gem::Dependency
98
+ name: micron
99
+ requirement: !ruby/object:Gem::Requirement
100
+ requirements:
101
+ - - '>='
102
+ - !ruby/object:Gem::Version
103
+ version: '0'
104
+ type: :development
105
+ prerelease: false
106
+ version_requirements: !ruby/object:Gem::Requirement
107
+ requirements:
108
+ - - '>='
109
+ - !ruby/object:Gem::Version
110
+ version: '0'
111
+ description: Gracefully recycle sidekiq processes that use too much memory
112
+ email: chetan@pixelcop.net
113
+ executables: []
114
+ extensions: []
115
+ extra_rdoc_files:
116
+ - README.md
117
+ files:
118
+ - Gemfile
119
+ - Gemfile.lock
120
+ - README.md
121
+ - Rakefile
122
+ - VERSION
123
+ - lib/sidekiq/recycler.rb
124
+ - sidekiq-recycler.gemspec
125
+ - test/helper.rb
126
+ - test/support/create_jobs.rb
127
+ - test/support/sidekiq_mock_fetcher.rb
128
+ - test/support/workers.rb
129
+ - test/test_recycler.rb
130
+ homepage: http://github.com/chetan/sidekiq-recycler
131
+ licenses:
132
+ - MIT
133
+ metadata: {}
134
+ post_install_message:
135
+ rdoc_options: []
136
+ require_paths:
137
+ - lib
138
+ required_ruby_version: !ruby/object:Gem::Requirement
139
+ requirements:
140
+ - - '>='
141
+ - !ruby/object:Gem::Version
142
+ version: '0'
143
+ required_rubygems_version: !ruby/object:Gem::Requirement
144
+ requirements:
145
+ - - '>='
146
+ - !ruby/object:Gem::Version
147
+ version: '0'
148
+ requirements: []
149
+ rubyforge_project:
150
+ rubygems_version: 2.1.5
151
+ signing_key:
152
+ specification_version: 4
153
+ summary: Recycle large sidekiq processes
154
+ test_files: []