sidekiq-recycler 0.1.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 +7 -0
- data/Gemfile +17 -0
- data/Gemfile.lock +107 -0
- data/README.md +34 -0
- data/Rakefile +33 -0
- data/VERSION +1 -0
- data/lib/sidekiq/recycler.rb +78 -0
- data/sidekiq-recycler.gemspec +69 -0
- data/test/helper.rb +22 -0
- data/test/support/create_jobs.rb +9 -0
- data/test/support/sidekiq_mock_fetcher.rb +91 -0
- data/test/support/workers.rb +40 -0
- data/test/test_recycler.rb +62 -0
- metadata +154 -0
checksums.yaml
ADDED
@@ -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
|
data/Gemfile.lock
ADDED
@@ -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
|
data/README.md
ADDED
@@ -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
|
data/Rakefile
ADDED
@@ -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
|
+
|
data/test/helper.rb
ADDED
@@ -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,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: []
|