resque-mongo 1.3.1

Sign up to get free protection for your applications and to get access to all the features.
Files changed (61) hide show
  1. data/.gitignore +3 -0
  2. data/.kick +26 -0
  3. data/CONTRIBUTORS +14 -0
  4. data/HISTORY.md +53 -0
  5. data/LICENSE +20 -0
  6. data/README.markdown +755 -0
  7. data/Rakefile +65 -0
  8. data/bin/resque +57 -0
  9. data/bin/resque-web +18 -0
  10. data/config.ru +14 -0
  11. data/deps.rip +8 -0
  12. data/examples/async_helper.rb +31 -0
  13. data/examples/demo/README.markdown +71 -0
  14. data/examples/demo/Rakefile +3 -0
  15. data/examples/demo/app.rb +27 -0
  16. data/examples/demo/config.ru +19 -0
  17. data/examples/demo/job.rb +12 -0
  18. data/examples/god/resque.god +52 -0
  19. data/examples/god/stale.god +26 -0
  20. data/examples/instance.rb +11 -0
  21. data/examples/simple.rb +30 -0
  22. data/init.rb +1 -0
  23. data/lib/resque.rb +224 -0
  24. data/lib/resque/errors.rb +7 -0
  25. data/lib/resque/failure.rb +63 -0
  26. data/lib/resque/failure/base.rb +58 -0
  27. data/lib/resque/failure/hoptoad.rb +88 -0
  28. data/lib/resque/failure/mongo.rb +32 -0
  29. data/lib/resque/helpers.rb +65 -0
  30. data/lib/resque/job.rb +103 -0
  31. data/lib/resque/server.rb +182 -0
  32. data/lib/resque/server/public/idle.png +0 -0
  33. data/lib/resque/server/public/jquery-1.3.2.min.js +19 -0
  34. data/lib/resque/server/public/jquery.relatize_date.js +95 -0
  35. data/lib/resque/server/public/poll.png +0 -0
  36. data/lib/resque/server/public/ranger.js +24 -0
  37. data/lib/resque/server/public/reset.css +48 -0
  38. data/lib/resque/server/public/style.css +75 -0
  39. data/lib/resque/server/public/working.png +0 -0
  40. data/lib/resque/server/views/error.erb +1 -0
  41. data/lib/resque/server/views/failed.erb +35 -0
  42. data/lib/resque/server/views/key.erb +17 -0
  43. data/lib/resque/server/views/layout.erb +38 -0
  44. data/lib/resque/server/views/next_more.erb +10 -0
  45. data/lib/resque/server/views/overview.erb +4 -0
  46. data/lib/resque/server/views/queues.erb +46 -0
  47. data/lib/resque/server/views/stats.erb +62 -0
  48. data/lib/resque/server/views/workers.erb +78 -0
  49. data/lib/resque/server/views/working.erb +67 -0
  50. data/lib/resque/stat.rb +55 -0
  51. data/lib/resque/tasks.rb +39 -0
  52. data/lib/resque/version.rb +3 -0
  53. data/lib/resque/worker.rb +415 -0
  54. data/tasks/redis.rake +133 -0
  55. data/tasks/resque.rake +2 -0
  56. data/test/dump.rdb +0 -0
  57. data/test/redis-test.conf +132 -0
  58. data/test/resque_test.rb +191 -0
  59. data/test/test_helper.rb +87 -0
  60. data/test/worker_test.rb +229 -0
  61. metadata +162 -0
@@ -0,0 +1,65 @@
1
+ load 'tasks/redis.rake'
2
+
3
+ $LOAD_PATH.unshift 'lib'
4
+ require 'resque/tasks'
5
+
6
+ task :default => :test
7
+
8
+ desc "Run tests"
9
+ task :test do
10
+ # Don't use the rake/testtask because it loads a new
11
+ # Ruby interpreter - we want to run tests with the current
12
+ # `rake` so our library manager still works
13
+ Dir['test/*_test.rb'].each do |f|
14
+ require f
15
+ end
16
+ end
17
+
18
+ desc "Activate kicker - gem install kicker"
19
+ task :kick do
20
+ exec "kicker -e rake lib test"
21
+ end
22
+
23
+ task :install => [ 'redis:install', 'dtach:install' ]
24
+
25
+ desc "Build a gem"
26
+ task :gem => [ :test, :gemspec, :build ]
27
+
28
+ begin
29
+ require 'jeweler'
30
+ require 'resque/version'
31
+
32
+ Jeweler::Tasks.new do |gemspec|
33
+ gemspec.name = "resque-mongo"
34
+ gemspec.summary = ""
35
+ gemspec.description = ""
36
+ gemspec.email = "yatiohi@ideopolis.gr"
37
+ gemspec.homepage = "http://github.com/ctrochalakis/resque-mongo"
38
+ gemspec.authors = ["Christos Trochalakis"]
39
+ gemspec.version = Resque::Version
40
+
41
+ gemspec.add_dependency "mongo"
42
+ gemspec.add_dependency "vegas", ">=0.1.2"
43
+ gemspec.add_dependency "sinatra", ">=0.9.2"
44
+ gemspec.add_development_dependency "jeweler"
45
+ end
46
+ rescue LoadError
47
+ puts "Jeweler not available. Install it with: "
48
+ puts "gem install jeweler"
49
+ end
50
+
51
+ begin
52
+ require 'sdoc_helpers'
53
+ rescue LoadError
54
+ puts "sdoc support not enabled. Please gem install sdoc-helpers."
55
+ end
56
+
57
+ desc "Push a new version to Gemcutter"
58
+ task :publish => [ :test, :gemspec, :build ] do
59
+ system "git tag v#{Resque::Version}"
60
+ system "git push origin v#{Resque::Version}"
61
+ system "git push origin master"
62
+ system "gem push pkg/resque-mongo-#{Resque::Version}.gem"
63
+ system "git clean -fd"
64
+ exec "rake pages"
65
+ 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,18 @@
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
+ })
@@ -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,8 @@
1
+ git://github.com/ctrochalakis/mongo-ruby-driver find_replace
2
+ mongo
3
+ mongo_ext
4
+ git://github.com/brianmario/yajl-ruby.git 0.6.3
5
+ git://github.com/sinatra/sinatra.git 0.9.4
6
+ git://github.com/rack/rack.git 1.0
7
+ git://github.com/quirkey/vegas.git v0.1.2
8
+ rake
@@ -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)
@@ -0,0 +1,71 @@
1
+ Resque Demo
2
+ -----------
3
+
4
+ This is a dirt simple Resque setup for you to play with.
5
+
6
+
7
+ ### Starting the Demo App
8
+
9
+ Here's how to run the Sinatra app:
10
+
11
+ $ git clone git://github.com/defunkt/resque.git
12
+ $ cd resque/examples/demo
13
+ $ rackup config.ru
14
+ $ open http://localhost:9292/
15
+
16
+ Click 'Create New Job' a few times. You should see the number of
17
+ pending jobs rising.
18
+
19
+
20
+ ### Starting the Demo Worker
21
+
22
+ Now in another shell terminal start the worker:
23
+
24
+ $ cd resque/examples/demo
25
+ $ VERBOSE=true QUEUE=default rake resque:work
26
+
27
+ You should see the following output:
28
+
29
+ *** Starting worker hostname:90185:default
30
+ *** got: (Job{default} | Demo::Job | [{}])
31
+ Processed a job!
32
+ *** done: (Job{default} | Demo::Job | [{}])
33
+
34
+ You can also use `VVERBOSE` (very verbose) if you want to see more:
35
+
36
+ $ VERBOSE=true QUEUE=default rake resque:work
37
+ *** Starting worker hostname:90399:default
38
+ ** [05:55:09 2009-09-16] 90399: Registered signals
39
+ ** [05:55:09 2009-09-16] 90399: Checking default
40
+ ** [05:55:09 2009-09-16] 90399: Found job on default
41
+ ** [05:55:09 2009-09-16] 90399: got: (Job{default} | Demo::Job | [{}])
42
+ ** [05:55:09 2009-09-16] 90399: resque: Forked 90401 at 1253141709
43
+ ** [05:55:09 2009-09-16] 90401: resque: Processing default since 1253141709
44
+ Processed a job!
45
+ ** [05:55:10 2009-09-16] 90401: done: (Job{default} | Demo::Job | [{}])
46
+
47
+ Notice that our workers `require 'job'` in our `Rakefile`. This
48
+ ensures they have our app loaded and can access the job classes.
49
+
50
+
51
+ ### Starting the Resque frontend
52
+
53
+ Great, now let's check out the Resque frontend. Either click on 'View
54
+ Resque' in your web browser or run:
55
+
56
+ $ open http://localhost:9292/resque/
57
+
58
+ You should see the Resque web frontend. 404 page? Don't forget the
59
+ trailing slash!
60
+
61
+
62
+ ### config.ru
63
+
64
+ The `config.ru` shows you how to mount multiple Rack apps. Resque
65
+ should work fine on a subpath - feel free to load it up in your
66
+ Passenger app and protect it with some basic auth.
67
+
68
+
69
+ ### That's it!
70
+
71
+ Click around, add some more queues, add more jobs, do whatever, have fun.
@@ -0,0 +1,3 @@
1
+ $LOAD_PATH.unshift File.dirname(__FILE__) + '/../../lib'
2
+ require 'resque/tasks'
3
+ require 'job'
@@ -0,0 +1,27 @@
1
+ require 'sinatra/base'
2
+ require 'resque'
3
+ require 'job'
4
+
5
+ module Demo
6
+ class App < Sinatra::Base
7
+ get '/' do
8
+ info = Resque.info
9
+ out = "<html><head><title>Resque Demo</title></head><body>"
10
+ out << "<p>"
11
+ out << "There are #{info[:pending]} pending and "
12
+ out << "#{info[:processed]} processed jobs across #{info[:queues]} queues."
13
+ out << "</p>"
14
+ out << '<form method="POST">'
15
+ out << '<input type="submit" value="Create New Job"/>'
16
+ out << '&nbsp;&nbsp;<a href="/resque/">View Resque</a>'
17
+ out << '</form>'
18
+ out << "</body></html>"
19
+ out
20
+ end
21
+
22
+ post '/' do
23
+ Resque.enqueue(Job, params)
24
+ redirect "/"
25
+ end
26
+ end
27
+ end
@@ -0,0 +1,19 @@
1
+ #!/usr/bin/env ruby
2
+ require 'logger'
3
+ $LOAD_PATH.unshift File.dirname(__FILE__) + '/../../lib'
4
+ require 'app'
5
+ require 'resque/server'
6
+
7
+ use Rack::ShowExceptions
8
+
9
+ # Set the AUTH env variable to your basic auth password to protect Resque.
10
+ AUTH_PASSWORD = ENV['AUTH']
11
+ if AUTH_PASSWORD
12
+ Resque::Server.use Rack::Auth::Basic do |username, password|
13
+ password == AUTH_PASSWORD
14
+ end
15
+ end
16
+
17
+ run Rack::URLMap.new \
18
+ "/" => Demo::App.new,
19
+ "/resque" => Resque::Server.new
@@ -0,0 +1,12 @@
1
+ require 'resque'
2
+
3
+ module Demo
4
+ module Job
5
+ @queue = :default
6
+
7
+ def self.perform(params)
8
+ sleep 1
9
+ puts "Processed a job!"
10
+ end
11
+ end
12
+ end
@@ -0,0 +1,52 @@
1
+ rails_env = ENV['RAILS_ENV'] || "production"
2
+ rails_root = ENV['RAILS_ROOT'] || "/data/github/current"
3
+ num_workers = rails_env == 'production' ? 5 : 2
4
+
5
+ num_workers.times do |num|
6
+ God.watch do |w|
7
+ w.name = "resque-#{num}"
8
+ w.group = 'resque'
9
+ w.interval = 30.seconds
10
+ w.start = "env QUEUE=critical,high,low /usr/bin/rake -f #{rails_root}/Rakefile #{rails_env} resque:work"
11
+
12
+ w.uid = 'git'
13
+ w.gid = 'git'
14
+
15
+ # retart if memory gets too high
16
+ w.transition(:up, :restart) do |on|
17
+ on.condition(:memory_usage) do |c|
18
+ c.above = 350.megabytes
19
+ c.times = 2
20
+ end
21
+ end
22
+
23
+ # determine the state on startup
24
+ w.transition(:init, { true => :up, false => :start }) do |on|
25
+ on.condition(:process_running) do |c|
26
+ c.running = true
27
+ end
28
+ end
29
+
30
+ # determine when process has finished starting
31
+ w.transition([:start, :restart], :up) do |on|
32
+ on.condition(:process_running) do |c|
33
+ c.running = true
34
+ c.interval = 5.seconds
35
+ end
36
+
37
+ # failsafe
38
+ on.condition(:tries) do |c|
39
+ c.times = 5
40
+ c.transition = :start
41
+ c.interval = 5.seconds
42
+ end
43
+ end
44
+
45
+ # start if process is not running
46
+ w.transition(:up, :start) do |on|
47
+ on.condition(:process_running) do |c|
48
+ c.running = false
49
+ end
50
+ end
51
+ end
52
+ end
@@ -0,0 +1,26 @@
1
+ # This will ride alongside god and kill any rogue stale worker
2
+ # processes. Their sacrifice is for the greater good.
3
+
4
+ WORKER_TIMEOUT = 60 * 10 # 10 minutes
5
+
6
+ Thread.new do
7
+ loop do
8
+ begin
9
+ `ps -e -o pid,command | grep [r]esque`.split("\n").each do |line|
10
+ parts = line.split(' ')
11
+ next if parts[-2] != "at"
12
+ started = parts[-1].to_i
13
+ elapsed = Time.now - Time.at(started)
14
+
15
+ if elapsed >= WORKER_TIMEOUT
16
+ ::Process.kill('USR1', parts[0].to_i)
17
+ end
18
+ end
19
+ rescue
20
+ # don't die because of stupid exceptions
21
+ nil
22
+ end
23
+
24
+ sleep 30
25
+ end
26
+ end
@@ -0,0 +1,11 @@
1
+ # DelayedJob wants you to create instances. No problem.
2
+
3
+ class Archive < Struct.new(:repo_id, :branch)
4
+ def self.perform(*args)
5
+ new(*args).perform
6
+ end
7
+
8
+ def perform
9
+ # do work!
10
+ end
11
+ end
@@ -0,0 +1,30 @@
1
+ # This is a simple Resque job.
2
+ class Archive
3
+ @queue = :file_serve
4
+
5
+ def self.perform(repo_id, branch = 'master')
6
+ repo = Repository.find(repo_id)
7
+ repo.create_archive(branch)
8
+ end
9
+ end
10
+
11
+ # This is in our app code
12
+ class Repository < Model
13
+ # ... stuff ...
14
+
15
+ def async_create_archive(branch)
16
+ Resque.enqueue(Archive, self.id, branch)
17
+ end
18
+
19
+ # ... more stuff ...
20
+ end
21
+
22
+ # Calling this code:
23
+ repo = Repository.find(22)
24
+ repo.async_create_archive('homebrew')
25
+
26
+ # Will return immediately and create a Resque job which is later
27
+ # processed.
28
+
29
+ # Essentially, this code is run by the worker when processing:
30
+ Archive.perform(22, 'homebrew')