resque-mongo 1.3.1
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.
- data/.gitignore +3 -0
- data/.kick +26 -0
- data/CONTRIBUTORS +14 -0
- data/HISTORY.md +53 -0
- data/LICENSE +20 -0
- data/README.markdown +755 -0
- data/Rakefile +65 -0
- data/bin/resque +57 -0
- data/bin/resque-web +18 -0
- data/config.ru +14 -0
- data/deps.rip +8 -0
- data/examples/async_helper.rb +31 -0
- data/examples/demo/README.markdown +71 -0
- data/examples/demo/Rakefile +3 -0
- data/examples/demo/app.rb +27 -0
- data/examples/demo/config.ru +19 -0
- data/examples/demo/job.rb +12 -0
- data/examples/god/resque.god +52 -0
- data/examples/god/stale.god +26 -0
- data/examples/instance.rb +11 -0
- data/examples/simple.rb +30 -0
- data/init.rb +1 -0
- data/lib/resque.rb +224 -0
- data/lib/resque/errors.rb +7 -0
- data/lib/resque/failure.rb +63 -0
- data/lib/resque/failure/base.rb +58 -0
- data/lib/resque/failure/hoptoad.rb +88 -0
- data/lib/resque/failure/mongo.rb +32 -0
- data/lib/resque/helpers.rb +65 -0
- data/lib/resque/job.rb +103 -0
- data/lib/resque/server.rb +182 -0
- data/lib/resque/server/public/idle.png +0 -0
- data/lib/resque/server/public/jquery-1.3.2.min.js +19 -0
- data/lib/resque/server/public/jquery.relatize_date.js +95 -0
- data/lib/resque/server/public/poll.png +0 -0
- data/lib/resque/server/public/ranger.js +24 -0
- data/lib/resque/server/public/reset.css +48 -0
- data/lib/resque/server/public/style.css +75 -0
- data/lib/resque/server/public/working.png +0 -0
- data/lib/resque/server/views/error.erb +1 -0
- data/lib/resque/server/views/failed.erb +35 -0
- data/lib/resque/server/views/key.erb +17 -0
- data/lib/resque/server/views/layout.erb +38 -0
- data/lib/resque/server/views/next_more.erb +10 -0
- data/lib/resque/server/views/overview.erb +4 -0
- data/lib/resque/server/views/queues.erb +46 -0
- data/lib/resque/server/views/stats.erb +62 -0
- data/lib/resque/server/views/workers.erb +78 -0
- data/lib/resque/server/views/working.erb +67 -0
- data/lib/resque/stat.rb +55 -0
- data/lib/resque/tasks.rb +39 -0
- data/lib/resque/version.rb +3 -0
- data/lib/resque/worker.rb +415 -0
- data/tasks/redis.rake +133 -0
- data/tasks/resque.rake +2 -0
- data/test/dump.rdb +0 -0
- data/test/redis-test.conf +132 -0
- data/test/resque_test.rb +191 -0
- data/test/test_helper.rb +87 -0
- data/test/worker_test.rb +229 -0
- metadata +162 -0
data/Rakefile
ADDED
@@ -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
|
data/bin/resque
ADDED
@@ -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
|
data/bin/resque-web
ADDED
@@ -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
|
+
})
|
data/config.ru
ADDED
@@ -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
|
data/deps.rip
ADDED
@@ -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,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 << ' <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,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
|
data/examples/simple.rb
ADDED
@@ -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')
|