opengotham_resque 1.8.2

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.
Files changed (70) hide show
  1. data/.gitignore +2 -0
  2. data/.kick +26 -0
  3. data/HISTORY.md +142 -0
  4. data/LICENSE +20 -0
  5. data/README.markdown +794 -0
  6. data/Rakefile +112 -0
  7. data/bin/resque +57 -0
  8. data/bin/resque-web +23 -0
  9. data/config.ru +14 -0
  10. data/deps.rip +7 -0
  11. data/docs/HOOKS.md +121 -0
  12. data/docs/PLUGINS.md +93 -0
  13. data/examples/async_helper.rb +31 -0
  14. data/examples/demo/README.markdown +71 -0
  15. data/examples/demo/Rakefile +8 -0
  16. data/examples/demo/app.rb +38 -0
  17. data/examples/demo/config.ru +19 -0
  18. data/examples/demo/job.rb +22 -0
  19. data/examples/god/resque.god +53 -0
  20. data/examples/god/stale.god +26 -0
  21. data/examples/instance.rb +11 -0
  22. data/examples/monit/resque.monit +6 -0
  23. data/examples/simple.rb +30 -0
  24. data/init.rb +1 -0
  25. data/lib/resque.rb +287 -0
  26. data/lib/resque/errors.rb +10 -0
  27. data/lib/resque/failure.rb +66 -0
  28. data/lib/resque/failure/base.rb +61 -0
  29. data/lib/resque/failure/hoptoad.rb +132 -0
  30. data/lib/resque/failure/multiple.rb +48 -0
  31. data/lib/resque/failure/redis.rb +40 -0
  32. data/lib/resque/helpers.rb +63 -0
  33. data/lib/resque/job.rb +207 -0
  34. data/lib/resque/plugin.rb +46 -0
  35. data/lib/resque/server.rb +201 -0
  36. data/lib/resque/server/public/idle.png +0 -0
  37. data/lib/resque/server/public/jquery-1.3.2.min.js +19 -0
  38. data/lib/resque/server/public/jquery.relatize_date.js +95 -0
  39. data/lib/resque/server/public/poll.png +0 -0
  40. data/lib/resque/server/public/ranger.js +67 -0
  41. data/lib/resque/server/public/reset.css +48 -0
  42. data/lib/resque/server/public/style.css +81 -0
  43. data/lib/resque/server/public/working.png +0 -0
  44. data/lib/resque/server/test_helper.rb +19 -0
  45. data/lib/resque/server/views/error.erb +1 -0
  46. data/lib/resque/server/views/failed.erb +53 -0
  47. data/lib/resque/server/views/key_sets.erb +20 -0
  48. data/lib/resque/server/views/key_string.erb +11 -0
  49. data/lib/resque/server/views/layout.erb +44 -0
  50. data/lib/resque/server/views/next_more.erb +10 -0
  51. data/lib/resque/server/views/overview.erb +4 -0
  52. data/lib/resque/server/views/queues.erb +49 -0
  53. data/lib/resque/server/views/stats.erb +62 -0
  54. data/lib/resque/server/views/workers.erb +78 -0
  55. data/lib/resque/server/views/working.erb +69 -0
  56. data/lib/resque/stat.rb +53 -0
  57. data/lib/resque/tasks.rb +39 -0
  58. data/lib/resque/version.rb +3 -0
  59. data/lib/resque/worker.rb +478 -0
  60. data/tasks/redis.rake +159 -0
  61. data/tasks/resque.rake +2 -0
  62. data/test/job_hooks_test.rb +302 -0
  63. data/test/job_plugins_test.rb +209 -0
  64. data/test/plugin_test.rb +116 -0
  65. data/test/redis-test.conf +132 -0
  66. data/test/resque-web_test.rb +54 -0
  67. data/test/resque_test.rb +225 -0
  68. data/test/test_helper.rb +111 -0
  69. data/test/worker_test.rb +302 -0
  70. metadata +199 -0
@@ -0,0 +1,112 @@
1
+ #
2
+ # Setup
3
+ #
4
+
5
+ load 'tasks/redis.rake'
6
+ require 'rake/testtask'
7
+
8
+ $LOAD_PATH.unshift 'lib'
9
+ require 'resque/tasks'
10
+
11
+ def command?(command)
12
+ system("type #{command} > /dev/null")
13
+ end
14
+
15
+ begin
16
+ require 'jeweler'
17
+ Jeweler::Tasks.new do |gemspec|
18
+ gemspec.name = "opengotham_resque"
19
+ gemspec.summary = "resque is a Redis-backed queueing system."
20
+ gemspec.email = "mjording@opengotham.com"
21
+ gemspec.homepage = "http://github.com/opengotham/resque"
22
+ gemspec.authors = ["Matthew Jording"]
23
+ gemspec.version = '1.8.2'
24
+ gemspec.add_dependency 'redis', ">= 2.0.0.rc2"
25
+ gemspec.add_dependency "opengotham_redis-namespace", ">= 0.4.4"
26
+ gemspec.add_dependency "vegas", ">= 0.1.2"
27
+ gemspec.add_dependency "sinatra", ">= 0.9.2"
28
+ gemspec.description = <<description
29
+ Resque is a Redis-backed Ruby library for creating background jobs,
30
+ placing those jobs on multiple queues, and processing them later.
31
+
32
+ Background jobs can be any Ruby class or module that responds to
33
+ perform. Your existing classes can easily be converted to background
34
+ jobs or you can create new classes specifically to do work. Or, you
35
+ can do both.
36
+
37
+ Resque is heavily inspired by DelayedJob (which rocks) and is
38
+ comprised of three parts:
39
+
40
+ * A Ruby library for creating, querying, and processing jobs
41
+ * A Rake task for starting a worker which processes jobs
42
+ * A Sinatra app for monitoring queues, jobs, and workers.
43
+ description
44
+ end
45
+ Jeweler::GemcutterTasks.new
46
+ rescue LoadError
47
+ warn "Jeweler not available. Install it with:"
48
+ warn "gem install jeweler"
49
+ end
50
+ #
51
+ # Tests
52
+ #
53
+
54
+ task :default => :test
55
+
56
+ desc "Run the test suite"
57
+ task :test do
58
+ rg = command?(:rg)
59
+ Dir['test/**/*_test.rb'].each do |f|
60
+ rg ? sh("rg #{f}") : ruby(f)
61
+ end
62
+ end
63
+
64
+ if command? :kicker
65
+ desc "Launch Kicker (like autotest)"
66
+ task :kicker do
67
+ puts "Kicking... (ctrl+c to cancel)"
68
+ exec "kicker -e rake test lib examples"
69
+ end
70
+ end
71
+
72
+
73
+ #
74
+ # Gem
75
+ #
76
+
77
+ task :install => [ 'redis:install', 'dtach:install' ]
78
+
79
+ # begin
80
+ # require 'mg'
81
+ # MG.new("resque.gemspec")
82
+ # rescue LoadError
83
+ # warn "mg not available."
84
+ # warn "Install it with: gem i mg"
85
+ # end
86
+
87
+
88
+ #
89
+ # Documentation
90
+ #
91
+ #
92
+ # begin
93
+ # require 'sdoc_helpers'
94
+ # rescue LoadError
95
+ # puts "sdoc support not enabled. Please gem install sdoc-helpers."
96
+ # end
97
+
98
+
99
+ #
100
+ # Publishing
101
+ #
102
+ #
103
+ # desc "Push a new version to Gemcutter"
104
+ # task :publish => "gem:publish" do
105
+ # require 'resque/version'
106
+ #
107
+ # sh "git tag v#{Resque::Version}"
108
+ # sh "git push origin v#{Resque::Version}"
109
+ # sh "git push origin master"
110
+ # sh "git clean -fd"
111
+ # exec "rake pages"
112
+ # end
@@ -0,0 +1,57 @@
1
+ #!/usr/bin/env ruby
2
+
3
+ $LOAD_PATH.unshift File.dirname(__FILE__) + '/../lib'
4
+ require 'resque'
5
+
6
+ def kill(worker)
7
+ abort "** resque kill WORKER_ID" if worker.nil?
8
+ pid = worker.split(':')[1].to_i
9
+
10
+ begin
11
+ Process.kill("KILL", pid)
12
+ puts "** killed #{worker}"
13
+ rescue Errno::ESRCH
14
+ puts "** worker #{worker} not running"
15
+ end
16
+
17
+ remove worker
18
+ end
19
+
20
+ def remove(worker)
21
+ abort "** resque remove WORKER_ID" if worker.nil?
22
+
23
+ Resque.remove_worker(worker)
24
+ puts "** removed #{worker}"
25
+ end
26
+
27
+ def list
28
+ if Resque.workers.any?
29
+ Resque.workers.each do |worker|
30
+ puts "#{worker} (#{worker.state})"
31
+ end
32
+ else
33
+ puts "None"
34
+ end
35
+ end
36
+
37
+ if (i = ARGV.index('-r')) && ARGV[i+1]
38
+ Resque.redis = ARGV[i+1]
39
+ ARGV.delete_at(i)
40
+ ARGV.delete_at(i+1)
41
+ end
42
+
43
+ case ARGV[0]
44
+ when 'kill'
45
+ kill ARGV[1]
46
+ when 'remove'
47
+ remove ARGV[1]
48
+ when 'list'
49
+ list
50
+ else
51
+ puts "Usage: resque [-r redis_host:redis_port] COMMAND [option]"
52
+ puts
53
+ puts "Commands:"
54
+ puts " remove WORKER Removes a worker"
55
+ puts " kill WORKER Kills a worker"
56
+ puts " list Lists known workers"
57
+ end
@@ -0,0 +1,23 @@
1
+ #!/usr/bin/env ruby
2
+
3
+ $LOAD_PATH.unshift File.expand_path(File.dirname(__FILE__) + '/../lib')
4
+ begin
5
+ require 'vegas'
6
+ rescue LoadError
7
+ require 'rubygems'
8
+ require 'vegas'
9
+ end
10
+ require 'resque/server'
11
+
12
+
13
+ Vegas::Runner.new(Resque::Server, 'resque-web', {
14
+ :before_run => lambda {|v|
15
+ path = (ENV['RESQUECONFIG'] || v.args.first)
16
+ load path.to_s.strip if path
17
+ }
18
+ }) do |runner, opts, app|
19
+ opts.on('-N NAMESPACE', "--namespace NAMESPACE", "set the Redis namespace") {|namespace|
20
+ runner.logger.info "Using Redis namespace '#{namespace}'"
21
+ Resque.redis.namespace = namespace
22
+ }
23
+ end
@@ -0,0 +1,14 @@
1
+ #!/usr/bin/env ruby
2
+ require 'logger'
3
+
4
+ $LOAD_PATH.unshift ::File.expand_path(::File.dirname(__FILE__) + '/lib')
5
+ require 'resque/server'
6
+
7
+ # Set the RESQUECONFIG env variable if you've a `resque.rb` or similar
8
+ # config file you want loaded on boot.
9
+ if ENV['RESQUECONFIG'] && ::File.exists?(::File.expand_path(ENV['RESQUECONFIG']))
10
+ load ::File.expand_path(ENV['RESQUECONFIG'])
11
+ end
12
+
13
+ use Rack::ShowExceptions
14
+ run Resque::Server.new
@@ -0,0 +1,7 @@
1
+ git://github.com/ezmobius/redis-rb.git 2.0.0.rc2
2
+ git://github.com/brianmario/yajl-ruby.git 0.6.3
3
+ git://github.com/sinatra/sinatra.git 0.9.4
4
+ git://github.com/rack/rack.git 1.0
5
+ git://github.com/quirkey/vegas.git v0.1.2
6
+ git://github.com/brynary/rack-test.git v0.5.3
7
+ rake
@@ -0,0 +1,121 @@
1
+ Resque Hooks
2
+ ============
3
+
4
+ You can customize Resque or write plugins using its hook API. In many
5
+ cases you can use a hook rather than mess with Resque's internals.
6
+
7
+ For a list of available plugins see
8
+ <http://wiki.github.com/defunkt/resque/plugins>.
9
+
10
+
11
+ Worker Hooks
12
+ ------------
13
+
14
+ If you wish to have a Proc called before the worker forks for the
15
+ first time, you can add it in the initializer like so:
16
+
17
+ Resque.before_first_fork do
18
+ puts "Call me once before the worker forks the first time"
19
+ end
20
+
21
+ You can also run a hook before _every_ fork:
22
+
23
+ Resque.before_fork do |job|
24
+ puts "Call me before the worker forks"
25
+ end
26
+
27
+ The `before_fork` hook will be run in the **parent** process. So, be
28
+ careful - any changes you make will be permanent for the lifespan of
29
+ the worker.
30
+
31
+ And after forking:
32
+
33
+ Resque.after_fork do |job|
34
+ puts "Call me after the worker forks"
35
+ end
36
+
37
+ The `after_fork` hook will be run in the child process and is passed
38
+ the current job. Any changes you make, therefor, will only live as
39
+ long as the job currently being processes.
40
+
41
+ All worker hooks can also be set using a setter, e.g.
42
+
43
+ Resque.after_fork = proc { puts "called" }
44
+
45
+
46
+ Job Hooks
47
+ ---------
48
+
49
+ Plugins can utilize job hooks to provide additional behavior. A job
50
+ hook is a method name in the following format:
51
+
52
+ HOOKNAME_IDENTIFIER
53
+
54
+ For example, a `before_perform` hook which adds locking may be defined
55
+ like this:
56
+
57
+ def before_perform_with_lock(*args)
58
+ set_lock!
59
+ end
60
+
61
+ Once this hook is made available to your job (either by way of
62
+ inheritence or `extend`), it will be run before the job's `perform`
63
+ method is called. Hooks of each type are executed in alphabetical order,
64
+ so `before_perform_a` will always be executed before `before_perform_b`.
65
+ An unnamed hook (`before_perform`) will be executed first.
66
+
67
+ The available hooks are:
68
+
69
+ * `before_perform`: Called with the job args before perform. If it raises
70
+ `Resque::Job::DontPerform`, the job is aborted. If other exceptions
71
+ are raised, they will be propagated up the the `Resque::Failure`
72
+ backend.
73
+
74
+ * `after_perform`: Called with the job args after it performs. Uncaught
75
+ exceptions will propagate up to the `Resque::Failure` backend.
76
+
77
+ * `around_perform`: Called with the job args. It is expected to yield in order
78
+ to perform the job (but is not required to do so). It may handle exceptions
79
+ thrown by `perform`, but any that are not caught will propagate up to the
80
+ `Resque::Failure` backend.
81
+
82
+ * `on_failure`: Called with the exception and job args if any exception occurs
83
+ while performing the job (or hooks).
84
+
85
+ Hooks are easily implemented with superclasses or modules. A superclass could
86
+ look something like this.
87
+
88
+ class LoggedJob
89
+ def self.before_perform_log_job(*args)
90
+ Logger.info "About to perform #{self} with #{args.inspect}"
91
+ end
92
+ end
93
+
94
+ class MyJob < LoggedJob
95
+ def self.perform(*args)
96
+ ...
97
+ end
98
+ end
99
+
100
+ Modules are even better because jobs can use many of them.
101
+
102
+ module LoggedJob
103
+ def before_perform_log_job(*args)
104
+ Logger.info "About to perform #{self} with #{args.inspect}"
105
+ end
106
+ end
107
+
108
+ module RetriedJob
109
+ def on_failure_retry(e, *args)
110
+ Logger.info "Performing #{self} caused an exception (#{e}). Retrying..."
111
+ Resque.enqueue self, *args
112
+ end
113
+ end
114
+
115
+ class MyJob
116
+ extend LoggedJob
117
+ extend RetriedJob
118
+ def self.perform(*args)
119
+ ...
120
+ end
121
+ end
@@ -0,0 +1,93 @@
1
+ Resque Plugins
2
+ ==============
3
+
4
+ Resque encourages plugin development. For a list of available plugins,
5
+ please see <http://wiki.github.com/defunkt/resque/plugins>.
6
+
7
+ The `docs/HOOKS.md` file included with Resque documents the available
8
+ hooks you can use to add or change Resque functionality. This document
9
+ describes best practice for plugins themselves.
10
+
11
+
12
+ Version
13
+ -------
14
+
15
+ Plugins should declare the major.minor version of Resque they are
16
+ known to work with explicitly in their README.
17
+
18
+ For example, if your plugin depends on features in Resque 2.1, please
19
+ list "Depends on Resque 2.1" very prominently near the beginning of
20
+ your README.
21
+
22
+ Because Resque uses [Semantic Versioning][sv], you can safely make the
23
+ following assumptions:
24
+
25
+ * Your plugin will work with 2.2, 2.3, etc - no methods will be
26
+ removed or changed, only added.
27
+ * Your plugin might not work with 3.0+, as APIs may change or be
28
+ removed.
29
+
30
+
31
+ Namespace
32
+ ---------
33
+
34
+ All plugins should live under the `Resque::Plugins` module to avoid
35
+ clashing with first class Resque constants or other Ruby libraries.
36
+
37
+ Good:
38
+
39
+ * Resque::Plugins::Lock
40
+ * Resque::Plugins::FastRetry
41
+
42
+ Bad:
43
+
44
+ * Resque::Lock
45
+ * ResqueQueue
46
+
47
+
48
+ Gem Name
49
+ --------
50
+
51
+ Gem names should be in the format of `resque-FEATURE`, where `FEATURE`
52
+ succinctly describes the feature your plugin adds to Resque.
53
+
54
+ Good:
55
+
56
+ * resque-status
57
+ * resque-scheduler
58
+
59
+ Bad:
60
+
61
+ * multi-queue
62
+ * defunkt-resque-lock
63
+
64
+
65
+ Hooks
66
+ -----
67
+
68
+ Job hook names should be namespaced to work properly.
69
+
70
+ Good:
71
+
72
+ * before_perform_lock
73
+ * around_perform_check_status
74
+
75
+ Bad:
76
+
77
+ * before_perform
78
+ * on_failure
79
+
80
+
81
+ Lint
82
+ ----
83
+
84
+ Plugins should test compliance to this document using the
85
+ `Resque::Plugin.lint` method.
86
+
87
+ For example:
88
+
89
+ assert_nothing_raised do
90
+ Resque::Plugin.lint(Resque::Plugins::Lock)
91
+ end
92
+
93
+ [sv]: http://semver.org/
@@ -0,0 +1,31 @@
1
+ # If you want to just call a method on an object in the background,
2
+ # we can easily add that functionality to Resque.
3
+ #
4
+ # This is similar to DelayedJob's `send_later`.
5
+ #
6
+ # Keep in mind that, unlike DelayedJob, only simple Ruby objects
7
+ # can be persisted.
8
+ #
9
+ # If it can be represented in JSON, it can be stored in a job.
10
+
11
+ # Here's our ActiveRecord class
12
+ class Repository < ActiveRecord::Base
13
+ # This will be called by a worker when a job needs to be processed
14
+ def self.perform(id, method, *args)
15
+ find(id).send(method, *args)
16
+ end
17
+
18
+ # We can pass this any Repository instance method that we want to
19
+ # run later.
20
+ def async(method, *args)
21
+ Resque.enqueue(Repository, id, method, *args)
22
+ end
23
+ end
24
+
25
+ # Now we can call any method and have it execute later:
26
+
27
+ @repo.async(:update_disk_usage)
28
+
29
+ # or
30
+
31
+ @repo.async(:update_network_source_id, 34)