misha-resque-cleaner 0.3.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.
@@ -0,0 +1,206 @@
1
+ require File.expand_path(File.dirname(__FILE__) + '/test_helper')
2
+ require 'time'
3
+ describe "ResqueCleaner" do
4
+ before do
5
+ Resque.redis.flushall
6
+
7
+ @worker = Resque::Worker.new(:jobs,:jobs2)
8
+
9
+ # 3 BadJob at 2009-03-13
10
+ create_and_process_jobs :jobs, @worker, 3, Time.parse('2009-03-13'), BadJob
11
+ # 2 BadJob by Jason at 2009-03-13
12
+ create_and_process_jobs :jobs2, @worker, 2, Time.parse('2009-03-13'), BadJob, "Jason"
13
+
14
+ # 1 BadJob by Johnson at 2009-03-13
15
+ create_and_process_jobs :jobs, @worker, 1, Time.parse('2009-03-13'), BadJob, "Johnson"
16
+
17
+ # 7 BadJob at 2009-11-13
18
+ create_and_process_jobs :jobs, @worker, 7, Time.parse('2009-11-13'), BadJobWithSyntaxError
19
+ # 7 BadJob by Freddy at 2009-11-13
20
+ create_and_process_jobs :jobs2, @worker, 7, Time.parse('2009-11-13'), BadJob, "Freddy"
21
+
22
+ # 11 BadJob at 2010-08-13
23
+ create_and_process_jobs :jobs, @worker, 11, Time.parse('2010-08-13'), BadJob
24
+ # 11 BadJob by Jason at 2010-08-13
25
+ create_and_process_jobs :jobs2, @worker, 11, Time.parse('2010-08-13'), BadJob, "Jason"
26
+
27
+ @cleaner = Resque::Plugins::ResqueCleaner.new
28
+ @cleaner.print_message = false
29
+ end
30
+
31
+ it "#select_by_regex returns only Jason jobs" do
32
+ ret = @cleaner.select_by_regex(/Jason/)
33
+ assert_equal 13, ret.size
34
+ end
35
+
36
+ it "#select_by_regex returns an empty array if passed a non-regex" do
37
+ ['string', nil, 13, Class.new].each do |non_regex|
38
+ ret = @cleaner.select_by_regex(nil)
39
+ assert_equal 0, ret.size
40
+ end
41
+ end
42
+
43
+ it "#select returns failure jobs" do
44
+ ret = @cleaner.select
45
+ assert_equal 42, ret.size
46
+ end
47
+
48
+ it "#select works with a limit" do
49
+ @cleaner.limiter.maximum = 10
50
+ ret = @cleaner.select
51
+
52
+ # only maximum number
53
+ assert_equal 10, ret.size
54
+
55
+ # lait one
56
+ assert_equal Time.parse(ret[0]['failed_at']), Time.parse('2010-08-13')
57
+ end
58
+
59
+ it "#select with a block returns failure jobs which the block evaluates true" do
60
+ ret = @cleaner.select {|job| job["payload"]["args"][0]=="Jason"}
61
+ assert_equal 13, ret.size
62
+ end
63
+
64
+ it "#clear deletes failure jobs" do
65
+ cleared = @cleaner.clear
66
+ assert_equal 42, cleared
67
+ assert_equal 0, @cleaner.select.size
68
+ end
69
+
70
+ it "#clear with a block deletes failure jobs which the block evaluates true" do
71
+ cleared = @cleaner.clear{|job| job["payload"]["args"][0]=="Jason"}
72
+ assert_equal 13, cleared
73
+ assert_equal 42-13, @cleaner.select.size
74
+ assert_equal 0, @cleaner.select{|job| job["payload"]["args"][0]=="Jason"}.size
75
+ end
76
+
77
+ it "#requeue retries failure jobs" do
78
+ assert_equal 0, queue_size(:jobs,:jobs2)
79
+ requeued = @cleaner.requeue
80
+ assert_equal 42, requeued
81
+ assert_equal 42, @cleaner.select.size # it doesn't clear jobs
82
+ assert_equal 42, queue_size(:jobs,:jobs2)
83
+ end
84
+
85
+ it "#requeue with a block retries failure jobs which the block evaluates true" do
86
+ requeued = @cleaner.requeue{|job| job["payload"]["args"][0]=="Jason"}
87
+ assert_equal 13, requeued
88
+ assert_equal 13, queue_size(:jobs,:jobs2)
89
+ end
90
+
91
+ it "#requeue with clear option requeues and deletes failure jobs" do
92
+ assert_equal 0, queue_size(:jobs,:jobs2)
93
+ requeued = @cleaner.requeue(true)
94
+ assert_equal 42, requeued
95
+ assert_equal 42, queue_size(:jobs,:jobs2)
96
+ assert_equal 0, @cleaner.select.size
97
+ end
98
+
99
+ it "#requeue with :queue option requeues the jobs to the queue" do
100
+ assert_equal 0, queue_size(:jobs,:jobs2,:retry)
101
+ requeued = @cleaner.requeue false, :queue => :retry
102
+ assert_equal 42, requeued
103
+ assert_equal 42, @cleaner.select.size # it doesn't clear jobs
104
+ assert_equal 0, queue_size(:jobs,:jobs2)
105
+ assert_equal 42, queue_size(:retry)
106
+ end
107
+
108
+ it "#clear_stale deletes failure jobs which is queued before the last x enqueued" do
109
+ @cleaner.limiter.maximum = 10
110
+ @cleaner.clear_stale
111
+ assert_equal 10, @cleaner.failure.count
112
+ assert_equal Time.parse(@cleaner.failure_jobs[0]['failed_at']), Time.parse('2010-08-13')
113
+ end
114
+
115
+ it "FailedJobEx module extends job and provides some useful methods" do
116
+ # before 2009-04-01
117
+ ret = @cleaner.select {|j| j.before?('2009-04-01')}
118
+ assert_equal 6, ret.size
119
+
120
+ # after 2010-01-01
121
+ ret = @cleaner.select {|j| j.after?('2010-01-01')}
122
+ assert_equal 22, ret.size
123
+
124
+ # filter by class
125
+ ret = @cleaner.select {|j| j.klass?(BadJobWithSyntaxError)}
126
+ assert_equal 7, ret.size
127
+
128
+ # filter by exception
129
+ ret = @cleaner.select {|j| j.exception?(SyntaxError)}
130
+ assert_equal 7, ret.size
131
+
132
+ # filter by queue
133
+ ret = @cleaner.select {|j| j.queue?(:jobs2)}
134
+ assert_equal 20, ret.size
135
+
136
+ # combination
137
+ ret = @cleaner.select {|j| j.queue?(:jobs2) && j.before?('2009-12-01')}
138
+ assert_equal 9, ret.size
139
+
140
+ # combination 2
141
+ ret = @cleaner.select {|j| j['payload']['args']==['Jason'] && j.queue?(:jobs2)}
142
+ assert_equal 13, ret.size
143
+
144
+ # retried?
145
+ requeued = @cleaner.requeue{|j| j["payload"]["args"][0]=="Johnson"}
146
+ ret = @cleaner.select {|j| j.retried?}
147
+ assert_equal 1, ret.size
148
+ end
149
+
150
+ it "#stats_by_date returns stats grouped by date" do
151
+ ret = @cleaner.stats_by_date
152
+ assert_equal 6, ret['2009/03/13']
153
+ assert_equal 14, ret['2009/11/13']
154
+
155
+ # with block
156
+ ret = @cleaner.stats_by_date{|j| j['payload']['args']==['Jason']}
157
+ assert_equal 2, ret['2009/03/13']
158
+ assert_equal nil, ret['2009/11/13']
159
+ assert_equal 11, ret['2010/08/13']
160
+ end
161
+
162
+ it "#stats_by_class returns stats grouped by class" do
163
+ ret = @cleaner.stats_by_class
164
+ assert_equal 35, ret['BadJob']
165
+ assert_equal 7, ret['BadJobWithSyntaxError']
166
+ end
167
+
168
+ it "#stats_by_class works with broken log" do
169
+ add_empty_payload_failure
170
+ ret = @cleaner.stats_by_class
171
+ assert_equal 1, ret['UNKNOWN']
172
+ end
173
+
174
+ it "#stats_by_exception returns stats grouped by exception" do
175
+ ret = @cleaner.stats_by_exception
176
+ assert_equal 35, ret['RuntimeError']
177
+ assert_equal 7, ret['SyntaxError']
178
+ end
179
+
180
+ it "#lock ensures that a new failure job doesn't affect in a limit mode" do
181
+ @cleaner.limiter.maximum = 23
182
+ @cleaner.limiter.lock do
183
+ first = @cleaner.select[0]
184
+ assert_equal "Freddy", first["payload"]["args"][0]
185
+
186
+ create_and_process_jobs :jobs, @worker, 30, Time.parse('2010-10-10'), BadJob, "Jack"
187
+
188
+ first = @cleaner.select[0]
189
+ assert_equal "Freddy", first["payload"]["args"][0]
190
+ end
191
+ first = @cleaner.select[0]
192
+ assert_equal "Jack", first["payload"]["args"][0]
193
+ end
194
+
195
+ it "allows you to configure limiter" do
196
+ c = Resque::Plugins::ResqueCleaner.new
197
+ refute_equal c.limiter.maximum, 10_000
198
+
199
+ module Resque::Plugins
200
+ ResqueCleaner::Limiter.default_maximum = 10_000
201
+ end
202
+
203
+ c = Resque::Plugins::ResqueCleaner.new
204
+ assert_equal c.limiter.maximum, 10_000
205
+ end
206
+ end
@@ -0,0 +1,66 @@
1
+ require File.expand_path(File.dirname(__FILE__) + '/test_helper')
2
+
3
+ require 'digest/sha1'
4
+ require 'json'
5
+ require 'rack/test'
6
+
7
+ class Minitest::Spec
8
+ include Rack::Test::Methods
9
+ def app
10
+ Resque::Server.new
11
+ end
12
+ end
13
+
14
+ def setup_some_failed_jobs
15
+ Resque.redis.flushall
16
+
17
+ @worker = Resque::Worker.new(:jobs,:jobs2)
18
+
19
+ create_and_process_jobs :jobs, @worker, 1, Time.now, BadJobWithSyntaxError, "great_args"
20
+
21
+ 10.times {|i|
22
+ create_and_process_jobs :jobs, @worker, 1, Time.now, BadJob, "test_#{i}"
23
+ }
24
+
25
+ @cleaner = Resque::Plugins::ResqueCleaner.new
26
+ @cleaner.print_message = false
27
+ end
28
+
29
+ describe "resque-web" do
30
+ before do
31
+ setup_some_failed_jobs
32
+ end
33
+
34
+ it "#cleaner should respond with success" do
35
+ get "/cleaner"
36
+ assert last_response.body.include?('BadJob')
37
+ assert last_response.body =~ /\bException\b/
38
+ end
39
+
40
+ it "#cleaner_list should respond with success" do
41
+ get "/cleaner_list"
42
+ assert last_response.ok?, last_response.errors
43
+ end
44
+
45
+ it '#cleaner_list shows the failed jobs' do
46
+ get "/cleaner_list"
47
+ assert last_response.body.include?('BadJob')
48
+ end
49
+
50
+ it "#cleaner_list shows the failed jobs when we use a select_by_regex" do
51
+ get "/cleaner_list", :regex => "BadJob*"
52
+ assert last_response.body.include?('"BadJobWithSyntaxError"')
53
+ assert last_response.body.include?('"BadJob"')
54
+ end
55
+
56
+
57
+ it '#cleaner_exec clears job' do
58
+ post "/cleaner_exec", :action => "clear", :sha1 => Digest::SHA1.hexdigest(@cleaner.select[0].to_json)
59
+ assert_equal 10, @cleaner.select.size
60
+ end
61
+ it "#cleaner_dump should respond with success" do
62
+ get "/cleaner_dump"
63
+ assert last_response.ok?, last_response.errors
64
+ end
65
+ end
66
+
@@ -0,0 +1,131 @@
1
+ # Mostly copied from Resque in order to have similar test environment.
2
+ # https://github.com/defunkt/resque/blob/master/test/test_helper.rb
3
+
4
+ dir = File.dirname(File.expand_path(__FILE__))
5
+ $LOAD_PATH.unshift dir + '/../lib'
6
+ $TESTING = true
7
+ require 'rubygems'
8
+ require 'minitest'
9
+ require 'minitest/spec'
10
+ require 'minitest/autorun'
11
+ require 'resque'
12
+ require 'timecop'
13
+
14
+ begin
15
+ require 'leftright'
16
+ rescue LoadError
17
+ end
18
+ require 'resque'
19
+ require 'resque_cleaner'
20
+
21
+ $TEST_PID = Process.pid
22
+
23
+ #
24
+ # make sure we can run redis
25
+ #
26
+
27
+ if !system("which redis-server")
28
+ puts '', "** can't find `redis-server` in your path"
29
+ puts "** try running `sudo rake install`"
30
+ abort ''
31
+ end
32
+
33
+
34
+ #
35
+ # start our own redis when the tests start,
36
+ # kill it when they end
37
+ #
38
+ MiniTest.after_run {
39
+ if Process.pid == $TEST_PID
40
+ processes = `ps -A -o pid,command | grep [r]edis-test`.split($/)
41
+ pids = processes.map { |process| process.split(" ")[0] }
42
+ puts "Killing test redis server..."
43
+ pids.each { |pid| Process.kill("TERM", pid.to_i) }
44
+ dump = "test/dump.rdb"
45
+ File.delete(dump) if File.exist?(dump)
46
+ end
47
+ }
48
+
49
+ puts "Starting redis for testing at localhost:9736..."
50
+ `redis-server #{dir}/redis-test.conf`
51
+ Resque.redis = 'localhost:9736'
52
+
53
+
54
+ ##
55
+ # Helper to perform job classes
56
+ #
57
+ module PerformJob
58
+ def perform_job(klass, *args)
59
+ resque_job = Resque::Job.new(:testqueue, 'class' => klass, 'args' => args)
60
+ resque_job.perform
61
+ end
62
+ end
63
+
64
+ #
65
+ # fixture classes
66
+ #
67
+
68
+ class SomeJob
69
+ def self.perform(repo_id, path)
70
+ end
71
+ end
72
+
73
+ class SomeIvarJob < SomeJob
74
+ @queue = :ivar
75
+ end
76
+
77
+ class SomeMethodJob < SomeJob
78
+ def self.queue
79
+ :method
80
+ end
81
+ end
82
+
83
+ class BadJob
84
+ def self.perform(name=nil)
85
+ msg = name ? "Bad job, #{name}" : "Bad job!"
86
+ raise msg
87
+ end
88
+ end
89
+
90
+ class GoodJob
91
+ def self.perform(name)
92
+ "Good job, #{name}"
93
+ end
94
+ end
95
+
96
+ class BadJobWithSyntaxError
97
+ def self.perform
98
+ raise SyntaxError, "Extra Bad job!"
99
+ end
100
+ end
101
+
102
+ #
103
+ # helper methods
104
+ #
105
+
106
+ def create_and_process_jobs(queue,worker,num,date,job,*args)
107
+ Timecop.freeze(date) do
108
+ num.times do
109
+ Resque::Job.create(queue, job, *args)
110
+ end
111
+ worker.work(0)
112
+ end
113
+ end
114
+
115
+ def queue_size(*queues)
116
+ queues.inject(0){|sum,queue| sum + Resque.size(queue).to_i}
117
+ end
118
+
119
+ def add_empty_payload_failure
120
+ data = {
121
+ :failed_at => Time.now.strftime("%Y/%m/%d %H:%M:%S %Z"),
122
+ :payload => nil,
123
+ :exception => "Resque::DirtyExit",
124
+ :error => "Resque::DirtyExit",
125
+ :backtrace => [],
126
+ :worker => "worker",
127
+ :queue => "queue"
128
+ }
129
+ data = Resque.encode(data)
130
+ Resque.redis.rpush(:failed, data)
131
+ end
metadata ADDED
@@ -0,0 +1,109 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: misha-resque-cleaner
3
+ version: !ruby/object:Gem::Version
4
+ version: 0.3.0
5
+ platform: ruby
6
+ authors:
7
+ - Tatsuya Ono
8
+ autorequire:
9
+ bindir: bin
10
+ cert_chain: []
11
+ date: 2015-12-22 00:00:00.000000000 Z
12
+ dependencies:
13
+ - !ruby/object:Gem::Dependency
14
+ name: resque
15
+ requirement: !ruby/object:Gem::Requirement
16
+ requirements:
17
+ - - "~>"
18
+ - !ruby/object:Gem::Version
19
+ version: '1.0'
20
+ type: :runtime
21
+ prerelease: false
22
+ version_requirements: !ruby/object:Gem::Requirement
23
+ requirements:
24
+ - - "~>"
25
+ - !ruby/object:Gem::Version
26
+ version: '1.0'
27
+ - !ruby/object:Gem::Dependency
28
+ name: minitest
29
+ requirement: !ruby/object:Gem::Requirement
30
+ requirements:
31
+ - - "~>"
32
+ - !ruby/object:Gem::Version
33
+ version: '5.0'
34
+ type: :development
35
+ prerelease: false
36
+ version_requirements: !ruby/object:Gem::Requirement
37
+ requirements:
38
+ - - "~>"
39
+ - !ruby/object:Gem::Version
40
+ version: '5.0'
41
+ - !ruby/object:Gem::Dependency
42
+ name: rack-test
43
+ requirement: !ruby/object:Gem::Requirement
44
+ requirements:
45
+ - - "~>"
46
+ - !ruby/object:Gem::Version
47
+ version: 0.6.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.6.0
55
+ description: |2
56
+ resque-cleaner maintains the cleanliness of failed jobs on Resque.
57
+ email: ononoma@gmail.com
58
+ executables: []
59
+ extensions: []
60
+ extra_rdoc_files:
61
+ - LICENSE
62
+ - README.md
63
+ - CHANGELOG.md
64
+ files:
65
+ - CHANGELOG.md
66
+ - LICENSE
67
+ - README.md
68
+ - Rakefile
69
+ - lib/resque-cleaner.rb
70
+ - lib/resque_cleaner.rb
71
+ - lib/resque_cleaner/server.rb
72
+ - lib/resque_cleaner/server/public/cleaner.css
73
+ - lib/resque_cleaner/server/views/_limiter.erb
74
+ - lib/resque_cleaner/server/views/_paginate.erb
75
+ - lib/resque_cleaner/server/views/_stats.erb
76
+ - lib/resque_cleaner/server/views/cleaner.erb
77
+ - lib/resque_cleaner/server/views/cleaner_exec.erb
78
+ - lib/resque_cleaner/server/views/cleaner_list.erb
79
+ - test/redis-test.conf
80
+ - test/resque_cleaner_test.rb
81
+ - test/resque_web_test.rb
82
+ - test/test_helper.rb
83
+ homepage: https://github.com/ono/resque-cleaner
84
+ licenses:
85
+ - MIT
86
+ metadata: {}
87
+ post_install_message:
88
+ rdoc_options:
89
+ - "--charset=UTF-8"
90
+ require_paths:
91
+ - lib
92
+ required_ruby_version: !ruby/object:Gem::Requirement
93
+ requirements:
94
+ - - ">="
95
+ - !ruby/object:Gem::Version
96
+ version: 1.9.3
97
+ required_rubygems_version: !ruby/object:Gem::Requirement
98
+ requirements:
99
+ - - ">="
100
+ - !ruby/object:Gem::Version
101
+ version: '0'
102
+ requirements: []
103
+ rubyforge_project:
104
+ rubygems_version: 2.4.5
105
+ signing_key:
106
+ specification_version: 4
107
+ summary: Resque plugin cleaning up failed jobs.
108
+ test_files: []
109
+ has_rdoc: