resque-insist 0.1.0

Sign up to get free protection for your applications and to get access to all the features.
data/Gemfile ADDED
@@ -0,0 +1,4 @@
1
+ source "http://rubygems.org"
2
+
3
+ # Specify your gem's dependencies in resque-insist.gemspec
4
+ gemspec
@@ -0,0 +1,42 @@
1
+ PATH
2
+ remote: .
3
+ specs:
4
+ resque-insist (0.1.0)
5
+ resque (~> 1.10.0)
6
+
7
+ GEM
8
+ remote: http://rubygems.org/
9
+ specs:
10
+ diff-lcs (1.1.2)
11
+ json (1.4.6)
12
+ rack (1.2.1)
13
+ redis (2.1.1)
14
+ redis-namespace (0.8.0)
15
+ redis (< 3.0.0)
16
+ resque (1.10.0)
17
+ json (~> 1.4.6)
18
+ redis-namespace (~> 0.8.0)
19
+ sinatra (>= 0.9.2)
20
+ vegas (~> 0.1.2)
21
+ rspec (2.2.0)
22
+ rspec-core (~> 2.2)
23
+ rspec-expectations (~> 2.2)
24
+ rspec-mocks (~> 2.2)
25
+ rspec-core (2.2.1)
26
+ rspec-expectations (2.2.0)
27
+ diff-lcs (~> 1.1.2)
28
+ rspec-mocks (2.2.0)
29
+ sinatra (1.1.0)
30
+ rack (~> 1.1)
31
+ tilt (~> 1.1)
32
+ tilt (1.1)
33
+ vegas (0.1.8)
34
+ rack (>= 1.0.0)
35
+
36
+ PLATFORMS
37
+ ruby
38
+
39
+ DEPENDENCIES
40
+ resque (~> 1.10.0)
41
+ resque-insist!
42
+ rspec (~> 2.2.0)
@@ -0,0 +1,48 @@
1
+ # Resque::Plugins::Insist
2
+ ## Give your Resque jobs a second chance
3
+
4
+ <http://github.com/jrom/resque-insist> by Jordi Romero
5
+
6
+ If you want to give your jobs a second chance (or more)
7
+ extend them with this plugin and let the job fail
8
+ some times before considering it failed.
9
+
10
+ By default a job will be run 3 times before marking it
11
+ as failed, but you can configure that with @insist = N
12
+ in your job.
13
+
14
+ ## Usage
15
+
16
+ require 'resque/plugins/insist'
17
+ class HardJob
18
+ extend Resque::Plugins::Insist
19
+ @queue = :hard_job
20
+ @insist = 5
21
+ def self.perform(something)
22
+ do_work
23
+ end
24
+ end
25
+
26
+ When your job fails for the first time, it will be queued
27
+ again, but will be locked for 8 seconds before the worker
28
+ performs it again. If it fails again, the wait time will be
29
+ 16 seconds, then 32, 64, ... until your job reaches the
30
+ maximum number of attempts or just succeeds (not raising an
31
+ exception).
32
+
33
+ ## Contributing
34
+
35
+ If you want to improve resque-insist
36
+
37
+ 1. Fork the repo
38
+ 2. Create a topic branch `git checkout -b my_feature`
39
+ 3. Push it! `git push origin my_feature`
40
+ 4. Open a pull request
41
+
42
+ Make sure you add specs for your changes and document them.
43
+ Any contribution will be appreciated, both fixing some typo or
44
+ adding the coolest feature ever.
45
+
46
+ ## Issues
47
+
48
+ <http://github.com/jrom/resque-insist/issues>
@@ -0,0 +1,2 @@
1
+ require 'bundler'
2
+ Bundler::GemHelper.install_tasks
@@ -0,0 +1,77 @@
1
+ module Resque # :nodoc:
2
+ module Plugins # :nodoc:
3
+ # If you want to give your jobs a second chance (or more)
4
+ # extend them with this plugin and let the job fail
5
+ # some times before considering it failed.
6
+ #
7
+ # By default a job will be run 3 times before marking it
8
+ # as failed, but you can configure that with @insist = N
9
+ # in your job.
10
+ #
11
+ # Example:
12
+ #
13
+ # require 'resque/plugins/insist'
14
+ # class HardJob
15
+ # extend Resque::Plugins::Insist
16
+ # @queue = :hard_job
17
+ # @insist = 5
18
+ # def self.perform(something)
19
+ # do_work
20
+ # end
21
+ # end
22
+ #
23
+ # When your job fails for the first time, it will be queued
24
+ # again, but will be locked for 8 seconds before the worker
25
+ # performs it again. If it fails again, the wait time will be
26
+ # 16 seconds, then 32, 64, ... until your job reaches the
27
+ # maximum number of attempts or just succeeds (not raising an
28
+ # exception).
29
+ module Insist
30
+ include Resque::Helpers
31
+ # Intercept the execution of a job to add the extra security
32
+ # layer.
33
+ def around_perform_insist(*args)
34
+ if redis.get "plugin:insist:wait:#{insist_key(args)}"
35
+ Resque.enqueue constantize(self.to_s), *args
36
+ else
37
+ begin
38
+ yield
39
+ redis.del "plugin:insist:attempts:#{insist_key(args)}"
40
+ rescue => e
41
+ attempts = redis.incr "plugin:insist:attempts:#{insist_key(args)}"
42
+ if attempts.to_i >= insist_times
43
+ redis.del "plugin:insist:wait:#{insist_key(args)}"
44
+ redis.del "plugin:insist:attempts:#{insist_key(args)}"
45
+ raise e
46
+ else
47
+ redis.set "plugin:insist:wait:#{insist_key(args)}", 1
48
+ redis.expire "plugin:insist:wait:#{insist_key(args)}", wait_time(attempts)
49
+ Resque.enqueue constantize(self.to_s), *args
50
+ end
51
+ end
52
+ end
53
+ end
54
+
55
+ # Number of times a job will be executed before considering
56
+ # it failed. By default it's 3. To specify it, set the ivar
57
+ # @insist to an integer. Any value under 1 will make the job
58
+ # perform just once as if the plugin was never there.
59
+ def insist_times
60
+ @insist || 3
61
+ end
62
+
63
+ # Calculates the amount of seconds a job is locked between
64
+ # the last failure and the next attempt.
65
+ def wait_time(attempts)
66
+ 2 ** (attempts.to_i + 2)
67
+ end
68
+
69
+ private
70
+ # Calculates a key to identify the job according to
71
+ # its arguments.
72
+ def insist_key(*args)
73
+ self.to_s + ':' + Digest::SHA1.hexdigest(args.join(','))
74
+ end
75
+ end
76
+ end
77
+ end
@@ -0,0 +1,21 @@
1
+ $:.push File.expand_path("../lib", __FILE__)
2
+
3
+ Gem::Specification.new do |s|
4
+ s.name = "resque-insist"
5
+ s.version = "0.1.0"
6
+ s.platform = Gem::Platform::RUBY
7
+ s.authors = ["Jordi Romero"]
8
+ s.email = ["jordi@jrom.net"]
9
+ s.homepage = "http://github.com/jrom/resque-insist"
10
+ s.summary = %q{Give your Resque jobs a second chance}
11
+ s.description = %q{If you want to give your jobs a second change (or more) extend them with this plugin and let the job fail some times before considering it failed.}
12
+
13
+ s.files = `git ls-files`.split("\n") - %w(.gitignore .rspec) - ['autotest/discover.rb']
14
+ s.test_files = `git ls-files -- {test,spec,features}/*`.split("\n")
15
+ s.executables = `git ls-files -- bin/*`.split("\n").map{ |f| File.basename(f) }
16
+ s.require_paths = ["lib"]
17
+
18
+ s.add_dependency "resque", "~> 1.10.0"
19
+ s.add_development_dependency "rspec", "~> 2.2.0"
20
+
21
+ end
@@ -0,0 +1,30 @@
1
+ daemonize yes
2
+ pidfile ./spec/redis.pid
3
+ port 6378
4
+
5
+ timeout 300
6
+ loglevel debug
7
+ logfile stdout
8
+ databases 16
9
+
10
+ save 900 1
11
+ save 300 10
12
+ save 60 10000
13
+ rdbcompression yes
14
+
15
+ dbfilename dump.rdb
16
+ dir ./spec/
17
+
18
+ appendonly no
19
+ appendfsync everysec
20
+
21
+ vm-enabled no
22
+ vm-swap-file /tmp/redis.swap
23
+ vm-max-memory 0
24
+ vm-page-size 32
25
+ vm-pages 134217728
26
+ vm-max-threads 4
27
+ glueoutputbuf yes
28
+ hash-max-zipmap-entries 64
29
+ hash-max-zipmap-value 512
30
+ activerehashing yes
@@ -0,0 +1,79 @@
1
+ require File.dirname(__FILE__) + '/spec_helper'
2
+
3
+ class Job
4
+ extend Resque::Plugins::Insist
5
+ @queue = :job
6
+ @insist = 2
7
+ def self.perform(success)
8
+ raise 'Not gonna work' unless success
9
+ end
10
+ end
11
+
12
+ describe Resque::Plugins::Insist do
13
+ describe "compliance of Resque Plugins guidelines" do
14
+ it "should be valid" do
15
+ lambda{ Resque::Plugin.lint(Resque::Plugins::Insist) }.should_not raise_error
16
+ end
17
+ end
18
+
19
+ describe "config" do
20
+ it "should take the insist_times value from the @insist ivar" do
21
+ Job.insist_times.should == 2
22
+ end
23
+
24
+ it "shoult default insist_times to 3" do
25
+ class JobWithoutCustomInsist
26
+ extend Resque::Plugins::Insist
27
+ @queue = :job
28
+ def self.perform; end
29
+ end
30
+ JobWithoutCustomInsist.insist_times.should == 3
31
+ end
32
+ end
33
+
34
+ describe "a succeeding Job" do
35
+ it "should be executed on the first attempt and not be enqueued again" do
36
+ Resque.enqueue Job, true
37
+ pending.should == 1
38
+ processed.should == 0
39
+ failed.should == 0
40
+ work_jobs
41
+ pending.should == 0
42
+ processed.should == 1
43
+ failed.should == 0
44
+ end
45
+ end
46
+
47
+ describe "a failing Job" do
48
+ it "should should quietly die and be enqueued back the first time it's executed" do
49
+ Resque.enqueue Job, false # enqueue a failing job
50
+ work_job # try to work it for the first time
51
+ pending.should == 1
52
+ failed.should == 0
53
+ time_before = Time.now
54
+ work_jobs # try to work it for the second and last time
55
+ elapsed_time = Time.now - time_before
56
+ elapsed_time.should > 7 # We wait aprox 8 seconds
57
+ elapsed_time.should < 9
58
+ pending.should == 0
59
+ failed.should == 1 # the job is marked as failed after 2 attempts
60
+ Resque::Failure.all['error'].should == 'Not gonna work' # we get the original error
61
+ end
62
+ end
63
+
64
+ # Defines pending, failed, processed, queues, environment, workers and servers
65
+ Resque.info.keys.each do |key|
66
+ define_method(key) { Resque.info[key] }
67
+ end
68
+
69
+ # Starts a worker to work off queue
70
+ def work_jobs(queue = :job)
71
+ Resque::Worker.new(queue).work(0)
72
+ end
73
+
74
+ # Performs the first job available from queue
75
+ def work_job(queue = :job)
76
+ worker = Resque::Worker.new(queue)
77
+ worker.perform(worker.reserve)
78
+ end
79
+ end
@@ -0,0 +1,25 @@
1
+ Bundler.require(:default, :development)
2
+ require 'lib/resque/plugins/insist'
3
+
4
+ RSpec.configure do |config|
5
+ config.before(:all) do
6
+ if !system('which redis-server')
7
+ puts "\ncan't find `redis-server` in your path"
8
+ abort
9
+ end
10
+ `redis-server #{File.dirname(File.expand_path(__FILE__))}/redis-test.conf` # run Redis with local config
11
+ puts "Starting test redis server: redis-server #{File.dirname(File.expand_path(__FILE__))}/redis-test.conf"
12
+ Resque.redis = 'localhost:6378' # port specified in redis-test.conf
13
+ end
14
+
15
+ config.before(:each) do
16
+ Resque.redis.flushall # Drop all keys between examples
17
+ end
18
+
19
+ config.after(:all) do
20
+ pid = `ps -e -o pid,command | grep [r]edis-test`.split(" ")[0]
21
+ puts "\nKilling test redis server PID #{pid}..."
22
+ `rm -f #{File.dirname(File.expand_path(__FILE__))}/dump.rdb` # file specified in redis-test.conf
23
+ Process.kill("KILL", pid.to_i)
24
+ end
25
+ end
metadata ADDED
@@ -0,0 +1,109 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: resque-insist
3
+ version: !ruby/object:Gem::Version
4
+ hash: 27
5
+ prerelease: false
6
+ segments:
7
+ - 0
8
+ - 1
9
+ - 0
10
+ version: 0.1.0
11
+ platform: ruby
12
+ authors:
13
+ - Jordi Romero
14
+ autorequire:
15
+ bindir: bin
16
+ cert_chain: []
17
+
18
+ date: 2010-12-19 00:00:00 +01:00
19
+ default_executable:
20
+ dependencies:
21
+ - !ruby/object:Gem::Dependency
22
+ name: resque
23
+ prerelease: false
24
+ requirement: &id001 !ruby/object:Gem::Requirement
25
+ none: false
26
+ requirements:
27
+ - - ~>
28
+ - !ruby/object:Gem::Version
29
+ hash: 63
30
+ segments:
31
+ - 1
32
+ - 10
33
+ - 0
34
+ version: 1.10.0
35
+ type: :runtime
36
+ version_requirements: *id001
37
+ - !ruby/object:Gem::Dependency
38
+ name: rspec
39
+ prerelease: false
40
+ requirement: &id002 !ruby/object:Gem::Requirement
41
+ none: false
42
+ requirements:
43
+ - - ~>
44
+ - !ruby/object:Gem::Version
45
+ hash: 7
46
+ segments:
47
+ - 2
48
+ - 2
49
+ - 0
50
+ version: 2.2.0
51
+ type: :development
52
+ version_requirements: *id002
53
+ description: If you want to give your jobs a second change (or more) extend them with this plugin and let the job fail some times before considering it failed.
54
+ email:
55
+ - jordi@jrom.net
56
+ executables: []
57
+
58
+ extensions: []
59
+
60
+ extra_rdoc_files: []
61
+
62
+ files:
63
+ - Gemfile
64
+ - Gemfile.lock
65
+ - README.md
66
+ - Rakefile
67
+ - lib/resque/plugins/insist.rb
68
+ - resque-insist.gemspec
69
+ - spec/redis-test.conf
70
+ - spec/resque_insist_spec.rb
71
+ - spec/spec_helper.rb
72
+ has_rdoc: true
73
+ homepage: http://github.com/jrom/resque-insist
74
+ licenses: []
75
+
76
+ post_install_message:
77
+ rdoc_options: []
78
+
79
+ require_paths:
80
+ - lib
81
+ required_ruby_version: !ruby/object:Gem::Requirement
82
+ none: false
83
+ requirements:
84
+ - - ">="
85
+ - !ruby/object:Gem::Version
86
+ hash: 3
87
+ segments:
88
+ - 0
89
+ version: "0"
90
+ required_rubygems_version: !ruby/object:Gem::Requirement
91
+ none: false
92
+ requirements:
93
+ - - ">="
94
+ - !ruby/object:Gem::Version
95
+ hash: 3
96
+ segments:
97
+ - 0
98
+ version: "0"
99
+ requirements: []
100
+
101
+ rubyforge_project:
102
+ rubygems_version: 1.3.7
103
+ signing_key:
104
+ specification_version: 3
105
+ summary: Give your Resque jobs a second chance
106
+ test_files:
107
+ - spec/redis-test.conf
108
+ - spec/resque_insist_spec.rb
109
+ - spec/spec_helper.rb