resque-pause 0.0.2
Sign up to get free protection for your applications and to get access to all the features.
- data/.gitignore +6 -0
- data/Gemfile +14 -0
- data/Gemfile.lock +73 -0
- data/README.md +77 -0
- data/Rakefile +7 -0
- data/lib/resque-pause.rb +3 -0
- data/lib/resque/plugins/pause.rb +15 -0
- data/lib/resque_pause.rb +4 -0
- data/lib/resque_pause/server.rb +56 -0
- data/lib/resque_pause/server/public/pause.js +18 -0
- data/lib/resque_pause/server/views/pause.erb +18 -0
- data/lib/resque_pause_helper.rb +30 -0
- data/lib/version.rb +7 -0
- data/resque-pause.gemspec +34 -0
- data/spec/redis-test.conf +115 -0
- data/spec/resque-web_spec.rb +73 -0
- data/spec/resque/plugins/pause_spec.rb +62 -0
- data/spec/resque_pause_helper_spec.rb +129 -0
- data/spec/spec_helper.rb +65 -0
- metadata +146 -0
data/.gitignore
ADDED
data/Gemfile
ADDED
@@ -0,0 +1,14 @@
|
|
1
|
+
source "http://rubygems.org"
|
2
|
+
|
3
|
+
# Specify your gem's dependencies in resque-pause.gemspec
|
4
|
+
gemspec
|
5
|
+
|
6
|
+
group :test, :development do
|
7
|
+
platforms :mri_18 do
|
8
|
+
gem "ruby-debug"
|
9
|
+
end
|
10
|
+
|
11
|
+
platforms :mri_19 do
|
12
|
+
gem "ruby-debug19", :require => 'ruby-debug' if RUBY_VERSION < "1.9.3"
|
13
|
+
end
|
14
|
+
end
|
data/Gemfile.lock
ADDED
@@ -0,0 +1,73 @@
|
|
1
|
+
PATH
|
2
|
+
remote: .
|
3
|
+
specs:
|
4
|
+
resque-pause (0.0.2)
|
5
|
+
resque (>= 1.9.10)
|
6
|
+
|
7
|
+
GEM
|
8
|
+
remote: http://rubygems.org/
|
9
|
+
specs:
|
10
|
+
archive-tar-minitar (0.5.2)
|
11
|
+
columnize (0.3.3)
|
12
|
+
diff-lcs (1.1.2)
|
13
|
+
json_pure (1.4.6)
|
14
|
+
linecache (0.46)
|
15
|
+
rbx-require-relative (> 0.0.4)
|
16
|
+
linecache19 (0.5.12)
|
17
|
+
ruby_core_source (>= 0.1.4)
|
18
|
+
rack (1.3.0)
|
19
|
+
rack-test (0.6.0)
|
20
|
+
rack (>= 1.0)
|
21
|
+
rbx-require-relative (0.0.5)
|
22
|
+
redis (2.2.1)
|
23
|
+
redis-namespace (0.8.0)
|
24
|
+
redis (< 3.0.0)
|
25
|
+
resque (1.9.10)
|
26
|
+
json_pure (~> 1.4.0)
|
27
|
+
redis-namespace (~> 0.8.0)
|
28
|
+
sinatra (>= 0.9.2)
|
29
|
+
vegas (~> 0.1.2)
|
30
|
+
rspec (2.6.0)
|
31
|
+
rspec-core (~> 2.6.0)
|
32
|
+
rspec-expectations (~> 2.6.0)
|
33
|
+
rspec-mocks (~> 2.6.0)
|
34
|
+
rspec-core (2.6.4)
|
35
|
+
rspec-expectations (2.6.0)
|
36
|
+
diff-lcs (~> 1.1.2)
|
37
|
+
rspec-mocks (2.6.0)
|
38
|
+
ruby-debug (0.10.4)
|
39
|
+
columnize (>= 0.1)
|
40
|
+
ruby-debug-base (~> 0.10.4.0)
|
41
|
+
ruby-debug-base (0.10.4)
|
42
|
+
linecache (>= 0.3)
|
43
|
+
ruby-debug-base19 (0.11.25)
|
44
|
+
columnize (>= 0.3.1)
|
45
|
+
linecache19 (>= 0.5.11)
|
46
|
+
ruby_core_source (>= 0.1.4)
|
47
|
+
ruby-debug19 (0.11.6)
|
48
|
+
columnize (>= 0.3.1)
|
49
|
+
linecache19 (>= 0.5.11)
|
50
|
+
ruby-debug-base19 (>= 0.11.19)
|
51
|
+
ruby_core_source (0.1.5)
|
52
|
+
archive-tar-minitar (>= 0.5.2)
|
53
|
+
simplecov (0.4.2)
|
54
|
+
simplecov-html (~> 0.4.4)
|
55
|
+
simplecov-html (0.4.5)
|
56
|
+
sinatra (1.2.6)
|
57
|
+
rack (~> 1.1)
|
58
|
+
tilt (>= 1.2.2, < 2.0)
|
59
|
+
tilt (1.3.2)
|
60
|
+
vegas (0.1.8)
|
61
|
+
rack (>= 1.0.0)
|
62
|
+
|
63
|
+
PLATFORMS
|
64
|
+
ruby
|
65
|
+
|
66
|
+
DEPENDENCIES
|
67
|
+
rack-test
|
68
|
+
resque (>= 1.9.10)
|
69
|
+
resque-pause!
|
70
|
+
rspec (>= 2.3.0)
|
71
|
+
ruby-debug
|
72
|
+
ruby-debug19
|
73
|
+
simplecov (>= 0.4.2)
|
data/README.md
ADDED
@@ -0,0 +1,77 @@
|
|
1
|
+
Resque Pause
|
2
|
+
============
|
3
|
+
|
4
|
+
A [Resque][rq] plugin. Requires Resque 1.9.10.
|
5
|
+
|
6
|
+
resque-pause adds functionality to pause resque jobs through the web interface.
|
7
|
+
|
8
|
+
Using a `pause` allows you to stop the job for a slice of time.
|
9
|
+
The job finish the process it are doing and don't get a new task to do,
|
10
|
+
until the queue is released.
|
11
|
+
You can use this functionality to do some maintenance whithout kill workers, for example.
|
12
|
+
|
13
|
+
Usage / Examples
|
14
|
+
----------------
|
15
|
+
|
16
|
+
### Single Job Instance
|
17
|
+
|
18
|
+
require 'resque-pause'
|
19
|
+
|
20
|
+
class UpdateNetworkGraph
|
21
|
+
extend Resque::Plugins::Pause
|
22
|
+
@queue = :network_graph
|
23
|
+
|
24
|
+
def self.perform(repo_id)
|
25
|
+
heavy_lifting
|
26
|
+
end
|
27
|
+
end
|
28
|
+
|
29
|
+
Pause is achieved by storing a pause/queue key in Redis.
|
30
|
+
|
31
|
+
Default behaviour...
|
32
|
+
|
33
|
+
* When the job instance try to execute and the queue is paused, the job is paused for a slice of time.
|
34
|
+
* If the queue still paused after this time the job will abort and will be enqueued again with the same arguments.
|
35
|
+
|
36
|
+
|
37
|
+
Resque-Web integration
|
38
|
+
----------------------
|
39
|
+
|
40
|
+
You have to load ResquePause to enable the Pause tab.
|
41
|
+
|
42
|
+
```ruby
|
43
|
+
require 'resque_pause'
|
44
|
+
```
|
45
|
+
|
46
|
+
Customise & Extend
|
47
|
+
==================
|
48
|
+
|
49
|
+
### Job pause check interval
|
50
|
+
|
51
|
+
The slice of time the job will wait for queue be unpaused before abort the job
|
52
|
+
could be changed with attribute @pause_check_interval.
|
53
|
+
|
54
|
+
By default the time is 10 seconds.
|
55
|
+
|
56
|
+
You can define the attribute in your job class in seconds.
|
57
|
+
|
58
|
+
class UpdateNetworkGraph
|
59
|
+
extend Resque::Plugins::Pause
|
60
|
+
@queue = :network_graph
|
61
|
+
@pause_check_interval = 30
|
62
|
+
|
63
|
+
def self.perform(repo_id)
|
64
|
+
heavy_lifting
|
65
|
+
end
|
66
|
+
end
|
67
|
+
|
68
|
+
The above modification will ensure the job will wait for 30 seconds before abort.
|
69
|
+
|
70
|
+
|
71
|
+
Install
|
72
|
+
=======
|
73
|
+
|
74
|
+
$ gem install resque-pause
|
75
|
+
|
76
|
+
[rq]: http://github.com/defunkt/resque
|
77
|
+
[resque-pause]: https://github.com/wandenberg/resque-pause
|
data/Rakefile
ADDED
data/lib/resque-pause.rb
ADDED
@@ -0,0 +1,15 @@
|
|
1
|
+
module Resque
|
2
|
+
module Plugins
|
3
|
+
module Pause
|
4
|
+
include Resque::Helpers
|
5
|
+
PAUSE_CHECK_INTERVAL = 10 #seconds to wait when queue is paused
|
6
|
+
|
7
|
+
def before_perform_pause(*args)
|
8
|
+
if ResquePauseHelper.paused?(@queue)
|
9
|
+
Kernel.sleep(@pause_check_interval || Resque::Plugins::Pause::PAUSE_CHECK_INTERVAL)
|
10
|
+
ResquePauseHelper.check_paused(:queue => @queue, :class => self, :args => args)
|
11
|
+
end
|
12
|
+
end
|
13
|
+
end
|
14
|
+
end
|
15
|
+
end
|
data/lib/resque_pause.rb
ADDED
@@ -0,0 +1,56 @@
|
|
1
|
+
# Extends Resque Web Based UI.
|
2
|
+
# Structure has been borrowed from ResqueScheduler.
|
3
|
+
module ResquePause
|
4
|
+
module Server
|
5
|
+
include Resque::Helpers
|
6
|
+
|
7
|
+
def self.erb_path(filename)
|
8
|
+
File.join(File.dirname(__FILE__), 'server', 'views', filename)
|
9
|
+
end
|
10
|
+
|
11
|
+
def self.public_path(filename)
|
12
|
+
File.join(File.dirname(__FILE__), 'server', 'public', filename)
|
13
|
+
end
|
14
|
+
|
15
|
+
def self.included(base)
|
16
|
+
|
17
|
+
base.class_eval do
|
18
|
+
|
19
|
+
helpers do
|
20
|
+
def paused?(queue)
|
21
|
+
ResquePauseHelper.paused?(queue)
|
22
|
+
end
|
23
|
+
end
|
24
|
+
|
25
|
+
mime_type :json, 'application/json'
|
26
|
+
|
27
|
+
get '/pause' do
|
28
|
+
erb File.read(ResquePause::Server.erb_path('pause.erb'))
|
29
|
+
end
|
30
|
+
|
31
|
+
post '/pause' do
|
32
|
+
ResquePauseHelper.pause(params['queue_name']) unless params['queue_name'].empty?
|
33
|
+
content_type :json
|
34
|
+
encode(:queue_name => params['queue_name'], :paused => true)
|
35
|
+
end
|
36
|
+
|
37
|
+
post '/unpause' do
|
38
|
+
ResquePauseHelper.unpause(params['queue_name']) unless params['queue_name'].empty?
|
39
|
+
content_type :json
|
40
|
+
encode(:queue_name => params['queue_name'], :paused => false)
|
41
|
+
end
|
42
|
+
|
43
|
+
get /pause\/public\/([a-z]+\.[a-z]+)/ do
|
44
|
+
send_file ResquePause::Server.public_path(params[:captures].first)
|
45
|
+
end
|
46
|
+
end
|
47
|
+
end
|
48
|
+
|
49
|
+
Resque::Server.tabs << 'Pause'
|
50
|
+
end
|
51
|
+
end
|
52
|
+
|
53
|
+
Resque.extend ResquePause
|
54
|
+
Resque::Server.class_eval do
|
55
|
+
include ResquePause::Server
|
56
|
+
end
|
@@ -0,0 +1,18 @@
|
|
1
|
+
jQuery(document).ready(function($) {
|
2
|
+
$('input:checkbox.pause').click( function(){
|
3
|
+
var queue = $(this);
|
4
|
+
var data = {'queue_name': queue.val()};
|
5
|
+
var url = queue.is(':checked') ? '/pause' : '/unpause';
|
6
|
+
$.ajax({
|
7
|
+
type: 'POST',
|
8
|
+
url: url,
|
9
|
+
data: data,
|
10
|
+
async: false,
|
11
|
+
cache: false,
|
12
|
+
success: function() { return true; },
|
13
|
+
error: function() { return false; },
|
14
|
+
dataType: 'json'
|
15
|
+
});
|
16
|
+
|
17
|
+
});
|
18
|
+
});
|
@@ -0,0 +1,18 @@
|
|
1
|
+
<script src="<%=u '/pause/public/pause.js' %>" type="text/javascript"></script>
|
2
|
+
|
3
|
+
<h1 class='wi'>Queues</h1>
|
4
|
+
<p class='intro'>The list below contains all the registered queues with the status if is paused or not. Select a queue from above to pause processing jobs.</p>
|
5
|
+
<table class='queues1'>
|
6
|
+
<tr>
|
7
|
+
<th>Name</th>
|
8
|
+
<th>Paused</th>
|
9
|
+
<th>Jobs</th>
|
10
|
+
</tr>
|
11
|
+
<% for queue in resque.queues.sort_by { |q| q.to_s } %>
|
12
|
+
<tr>
|
13
|
+
<td class='queue'><%= queue %></td>
|
14
|
+
<td class='status'><input class="pause" type="checkbox" value="<%= queue%>" <%= "checked" if paused?(queue) %>></input></td>
|
15
|
+
<td class='size'><%= resque.size queue %></td>
|
16
|
+
</tr>
|
17
|
+
<% end %>
|
18
|
+
</table>
|
@@ -0,0 +1,30 @@
|
|
1
|
+
module ResquePauseHelper
|
2
|
+
class << self
|
3
|
+
def paused?(queue)
|
4
|
+
!Resque.redis.get("pause:queue:#{queue}").nil?
|
5
|
+
end
|
6
|
+
|
7
|
+
def pause(queue)
|
8
|
+
Resque.redis.set "pause:queue:#{queue}", true
|
9
|
+
end
|
10
|
+
|
11
|
+
def unpause(queue)
|
12
|
+
Resque.redis.del "pause:queue:#{queue}"
|
13
|
+
end
|
14
|
+
|
15
|
+
def enqueue_job(args)
|
16
|
+
Resque.redis.lpush("queue:#{args[:queue]}", Resque.encode(:class => args[:class], :args => args[:args]))
|
17
|
+
end
|
18
|
+
|
19
|
+
def dequeue_job(args)
|
20
|
+
Resque.redis.lpop("queue:#{args[:queue]}")
|
21
|
+
end
|
22
|
+
|
23
|
+
def check_paused(args)
|
24
|
+
if ResquePauseHelper.paused?(args[:queue])
|
25
|
+
enqueue_job(args)
|
26
|
+
raise Resque::Job::DontPerform.new "Queue #{args[:queue]} is paused!"
|
27
|
+
end
|
28
|
+
end
|
29
|
+
end
|
30
|
+
end
|
data/lib/version.rb
ADDED
@@ -0,0 +1,34 @@
|
|
1
|
+
# -*- encoding: utf-8 -*-
|
2
|
+
$:.push File.expand_path("../lib", __FILE__)
|
3
|
+
require "version"
|
4
|
+
|
5
|
+
Gem::Specification.new do |s|
|
6
|
+
s.name = "resque-pause"
|
7
|
+
s.version = Resque::Plugins::Pause::VERSION
|
8
|
+
s.platform = Gem::Platform::RUBY
|
9
|
+
s.authors = ["Wandenberg Peixoto"]
|
10
|
+
s.email = ["wandenberg@gmail.com"]
|
11
|
+
s.homepage = ""
|
12
|
+
s.summary = %q{A Resque plugin to add functionality to pause resque jobs through the web interface.}
|
13
|
+
s.description = %q{A Resque plugin to add functionality to pause resque jobs through the web interface.
|
14
|
+
|
15
|
+
Using a `pause` allows you to stop the job for a slice of time.
|
16
|
+
The job finish the process it are doing and don't get a new task to do,
|
17
|
+
until the queue is released.
|
18
|
+
You can use this functionality to do some maintenance whithout kill workers, for example.}
|
19
|
+
|
20
|
+
s.rubyforge_project = "resque-pause"
|
21
|
+
|
22
|
+
s.files = `git ls-files`.split("\n")
|
23
|
+
s.test_files = `git ls-files -- {test,spec,features}/*`.split("\n")
|
24
|
+
s.executables = `git ls-files -- bin/*`.split("\n").map{ |f| File.basename(f) }
|
25
|
+
s.require_paths = ["lib"]
|
26
|
+
s.has_rdoc = false
|
27
|
+
|
28
|
+
s.add_dependency('resque', '>= 1.9.10')
|
29
|
+
|
30
|
+
s.add_development_dependency('rspec', '>= 2.3.0')
|
31
|
+
s.add_development_dependency('rack-test')
|
32
|
+
s.add_development_dependency('simplecov', '>= 0.4.2')
|
33
|
+
|
34
|
+
end
|
@@ -0,0 +1,115 @@
|
|
1
|
+
# Redis configuration file example
|
2
|
+
|
3
|
+
# By default Redis does not run as a daemon. Use 'yes' if you need it.
|
4
|
+
# Note that Redis will write a pid file in /var/run/redis.pid when daemonized.
|
5
|
+
daemonize yes
|
6
|
+
|
7
|
+
# When run as a daemon, Redis write a pid file in /var/run/redis.pid by default.
|
8
|
+
# You can specify a custom pid file location here.
|
9
|
+
pidfile ./spec/redis-test.pid
|
10
|
+
|
11
|
+
# Accept connections on the specified port, default is 6379
|
12
|
+
port 9736
|
13
|
+
|
14
|
+
# If you want you can bind a single interface, if the bind option is not
|
15
|
+
# specified all the interfaces will listen for connections.
|
16
|
+
#
|
17
|
+
# bind 127.0.0.1
|
18
|
+
|
19
|
+
# Close the connection after a client is idle for N seconds (0 to disable)
|
20
|
+
timeout 300
|
21
|
+
|
22
|
+
# Save the DB on disk:
|
23
|
+
#
|
24
|
+
# save <seconds> <changes>
|
25
|
+
#
|
26
|
+
# Will save the DB if both the given number of seconds and the given
|
27
|
+
# number of write operations against the DB occurred.
|
28
|
+
#
|
29
|
+
# In the example below the behaviour will be to save:
|
30
|
+
# after 900 sec (15 min) if at least 1 key changed
|
31
|
+
# after 300 sec (5 min) if at least 10 keys changed
|
32
|
+
# after 60 sec if at least 10000 keys changed
|
33
|
+
save 900 1
|
34
|
+
save 300 10
|
35
|
+
save 60 10000
|
36
|
+
|
37
|
+
# The filename where to dump the DB
|
38
|
+
dbfilename dump.rdb
|
39
|
+
|
40
|
+
# For default save/load DB in/from the working directory
|
41
|
+
# Note that you must specify a directory not a file name.
|
42
|
+
dir ./spec/
|
43
|
+
|
44
|
+
# Set server verbosity to 'debug'
|
45
|
+
# it can be one of:
|
46
|
+
# debug (a lot of information, useful for development/testing)
|
47
|
+
# notice (moderately verbose, what you want in production probably)
|
48
|
+
# warning (only very important / critical messages are logged)
|
49
|
+
loglevel debug
|
50
|
+
|
51
|
+
# Specify the log file name. Also 'stdout' can be used to force
|
52
|
+
# the demon to log on the standard output. Note that if you use standard
|
53
|
+
# output for logging but daemonize, logs will be sent to /dev/null
|
54
|
+
logfile stdout
|
55
|
+
|
56
|
+
# Set the number of databases. The default database is DB 0, you can select
|
57
|
+
# a different one on a per-connection basis using SELECT <dbid> where
|
58
|
+
# dbid is a number between 0 and 'databases'-1
|
59
|
+
databases 16
|
60
|
+
|
61
|
+
################################# REPLICATION #################################
|
62
|
+
|
63
|
+
# Master-Slave replication. Use slaveof to make a Redis instance a copy of
|
64
|
+
# another Redis server. Note that the configuration is local to the slave
|
65
|
+
# so for example it is possible to configure the slave to save the DB with a
|
66
|
+
# different interval, or to listen to another port, and so on.
|
67
|
+
|
68
|
+
# slaveof <masterip> <masterport>
|
69
|
+
|
70
|
+
################################## SECURITY ###################################
|
71
|
+
|
72
|
+
# Require clients to issue AUTH <PASSWORD> before processing any other
|
73
|
+
# commands. This might be useful in environments in which you do not trust
|
74
|
+
# others with access to the host running redis-server.
|
75
|
+
#
|
76
|
+
# This should stay commented out for backward compatibility and because most
|
77
|
+
# people do not need auth (e.g. they run their own servers).
|
78
|
+
|
79
|
+
# requirepass foobared
|
80
|
+
|
81
|
+
################################### LIMITS ####################################
|
82
|
+
|
83
|
+
# Set the max number of connected clients at the same time. By default there
|
84
|
+
# is no limit, and it's up to the number of file descriptors the Redis process
|
85
|
+
# is able to open. The special value '0' means no limts.
|
86
|
+
# Once the limit is reached Redis will close all the new connections sending
|
87
|
+
# an error 'max number of clients reached'.
|
88
|
+
|
89
|
+
# maxclients 128
|
90
|
+
|
91
|
+
# Don't use more memory than the specified amount of bytes.
|
92
|
+
# When the memory limit is reached Redis will try to remove keys with an
|
93
|
+
# EXPIRE set. It will try to start freeing keys that are going to expire
|
94
|
+
# in little time and preserve keys with a longer time to live.
|
95
|
+
# Redis will also try to remove objects from free lists if possible.
|
96
|
+
#
|
97
|
+
# If all this fails, Redis will start to reply with errors to commands
|
98
|
+
# that will use more memory, like SET, LPUSH, and so on, and will continue
|
99
|
+
# to reply to most read-only commands like GET.
|
100
|
+
#
|
101
|
+
# WARNING: maxmemory can be a good idea mainly if you want to use Redis as a
|
102
|
+
# 'state' server or cache, not as a real DB. When Redis is used as a real
|
103
|
+
# database the memory usage will grow over the weeks, it will be obvious if
|
104
|
+
# it is going to use too much memory in the long run, and you'll have the time
|
105
|
+
# to upgrade. With maxmemory after the limit is reached you'll start to get
|
106
|
+
# errors for write operations, and this may even lead to DB inconsistency.
|
107
|
+
|
108
|
+
# maxmemory <bytes>
|
109
|
+
|
110
|
+
############################### ADVANCED CONFIG ###############################
|
111
|
+
|
112
|
+
# Glue small output buffers together in order to send small replies in a
|
113
|
+
# single TCP packet. Uses a bit more CPU but most of the times it is a win
|
114
|
+
# in terms of number of queries per second. Use 'yes' if unsure.
|
115
|
+
glueoutputbuf yes
|
@@ -0,0 +1,73 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
|
3
|
+
describe ResquePause::Server do
|
4
|
+
include Rack::Test::Methods
|
5
|
+
def app
|
6
|
+
@app ||= Resque::Server.new
|
7
|
+
end
|
8
|
+
|
9
|
+
let :queues do
|
10
|
+
Resque.redis.sadd(:queues, "queue1")
|
11
|
+
Resque.redis.sadd(:queues, "queue2")
|
12
|
+
Resque.redis.sadd(:queues, "queue3")
|
13
|
+
end
|
14
|
+
|
15
|
+
before do
|
16
|
+
queues
|
17
|
+
end
|
18
|
+
|
19
|
+
it "should respond to /pause" do
|
20
|
+
get '/pause'
|
21
|
+
last_response.should be_ok
|
22
|
+
end
|
23
|
+
|
24
|
+
it "should list all registered queues" do
|
25
|
+
get '/pause'
|
26
|
+
last_response.body.should include("queue1")
|
27
|
+
last_response.body.should include("queue2")
|
28
|
+
last_response.body.should include("queue3")
|
29
|
+
end
|
30
|
+
|
31
|
+
it "should check paused queues" do
|
32
|
+
ResquePauseHelper.pause("queue2")
|
33
|
+
|
34
|
+
get '/pause'
|
35
|
+
last_response.body.should include(%q{<input class="pause" type="checkbox" value="queue1" ></input>})
|
36
|
+
last_response.body.should include(%q{<input class="pause" type="checkbox" value="queue2" checked></input>})
|
37
|
+
last_response.body.should include(%q{<input class="pause" type="checkbox" value="queue3" ></input>})
|
38
|
+
end
|
39
|
+
|
40
|
+
|
41
|
+
it "should pause a queue" do
|
42
|
+
post "/pause", :queue_name => "queue3"
|
43
|
+
|
44
|
+
ResquePauseHelper.paused?("queue3").should be_true
|
45
|
+
end
|
46
|
+
|
47
|
+
it "should return a json when pause a queue" do
|
48
|
+
post "/pause", :queue_name => "queue3"
|
49
|
+
|
50
|
+
last_response.headers["Content-Type"].should == "application/json"
|
51
|
+
last_response.body.should == { :queue_name => "queue3", :paused => true }.to_json
|
52
|
+
end
|
53
|
+
|
54
|
+
it "should unpause a queue" do
|
55
|
+
ResquePauseHelper.pause("queue2")
|
56
|
+
post "/unpause", :queue_name => "queue2"
|
57
|
+
|
58
|
+
ResquePauseHelper.paused?("queue2").should be_false
|
59
|
+
end
|
60
|
+
|
61
|
+
it "should return a json when unpause a queue" do
|
62
|
+
post "/unpause", :queue_name => "queue2"
|
63
|
+
|
64
|
+
last_response.headers["Content-Type"].should == "application/json"
|
65
|
+
last_response.body.should == { :queue_name => "queue2", :paused => false }.to_json
|
66
|
+
end
|
67
|
+
|
68
|
+
it "should return static files" do
|
69
|
+
get "/pause/public/pause.js"
|
70
|
+
last_response.body.should == File.read(File.expand_path('../lib/resque_pause/server/public/pause.js', File.dirname(__FILE__)))
|
71
|
+
end
|
72
|
+
|
73
|
+
end
|
@@ -0,0 +1,62 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
|
3
|
+
class PauseJob
|
4
|
+
extend Resque::Plugins::Pause
|
5
|
+
@queue = :test
|
6
|
+
|
7
|
+
def self.perform(*args)
|
8
|
+
end
|
9
|
+
end
|
10
|
+
|
11
|
+
describe Resque::Plugins::Pause do
|
12
|
+
it "should be compliance with Resqu::Plugin document" do
|
13
|
+
expect { Resque::Plugin.lint(Resque::Plugins::Pause) }.to_not raise_error
|
14
|
+
end
|
15
|
+
|
16
|
+
it "should use at least resque version 1.8.0" do
|
17
|
+
major, minor, patch = Resque::Version.split('.')
|
18
|
+
major.to_i.should == 1
|
19
|
+
minor.to_i.should >= 8
|
20
|
+
end
|
21
|
+
|
22
|
+
it "should execute the job when queue is not paused" do
|
23
|
+
Resque.enqueue(PauseJob)
|
24
|
+
PauseJob.should_receive(:perform)
|
25
|
+
|
26
|
+
Resque.reserve('test').perform
|
27
|
+
end
|
28
|
+
|
29
|
+
it "should not execute the job when queue is paused" do
|
30
|
+
ResquePauseHelper.pause('test')
|
31
|
+
Resque.enqueue(PauseJob)
|
32
|
+
PauseJob.should_not_receive(:perform)
|
33
|
+
|
34
|
+
Resque.reserve('test').perform
|
35
|
+
end
|
36
|
+
|
37
|
+
it "should not change queued jobs when queue is paused" do
|
38
|
+
ResquePauseHelper.pause('test')
|
39
|
+
Resque.enqueue(PauseJob, 1)
|
40
|
+
Resque.enqueue(PauseJob, 2)
|
41
|
+
Resque.enqueue(PauseJob, 3)
|
42
|
+
jobs = Resque.redis.lrange('queue:test', 0, 2)
|
43
|
+
|
44
|
+
Resque.reserve('test').perform
|
45
|
+
|
46
|
+
remaining_jobs = Resque.redis.lrange('queue:test', 0, 2)
|
47
|
+
jobs.should == remaining_jobs
|
48
|
+
end
|
49
|
+
|
50
|
+
it "should back to execute the job when queue is unpaused" do
|
51
|
+
Resque.enqueue(PauseJob)
|
52
|
+
|
53
|
+
ResquePauseHelper.pause('test')
|
54
|
+
Resque.reserve('test').perform
|
55
|
+
Resque.size('test').should == 1
|
56
|
+
|
57
|
+
ResquePauseHelper.unpause('test')
|
58
|
+
Resque.reserve('test').perform
|
59
|
+
Resque.size('test').should == 0
|
60
|
+
end
|
61
|
+
|
62
|
+
end
|
@@ -0,0 +1,129 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
|
3
|
+
class PauseJob
|
4
|
+
@queue = :test
|
5
|
+
|
6
|
+
def self.perform(*args)
|
7
|
+
end
|
8
|
+
end
|
9
|
+
|
10
|
+
describe ResquePauseHelper do
|
11
|
+
|
12
|
+
context "when check queue status" do
|
13
|
+
it "should return return false if don't have register on redis" do
|
14
|
+
Resque.redis.del "pause:queue:queue1"
|
15
|
+
|
16
|
+
subject.paused?("queue1").should be_false
|
17
|
+
end
|
18
|
+
|
19
|
+
it "should return return true if have register on redis" do
|
20
|
+
Resque.redis.set "pause:queue:queue1", "AnyValue"
|
21
|
+
|
22
|
+
subject.paused?("queue1").should be_true
|
23
|
+
end
|
24
|
+
end
|
25
|
+
|
26
|
+
context "when pause a queue" do
|
27
|
+
it "should register a unregistred queue" do
|
28
|
+
Resque.redis.del "pause:queue:queue1"
|
29
|
+
subject.pause("queue1")
|
30
|
+
|
31
|
+
subject.paused?("queue1").should be_true
|
32
|
+
end
|
33
|
+
|
34
|
+
it "should register again a registred queue" do
|
35
|
+
Resque.redis.set "pause:queue:queue1", "AnyValue"
|
36
|
+
expect { subject.pause("queue1") }.to_not raise_error
|
37
|
+
|
38
|
+
Resque.redis.get("pause:queue:queue1").should_not be_nil
|
39
|
+
Resque.redis.get("pause:queue:queue1").should be_true
|
40
|
+
end
|
41
|
+
end
|
42
|
+
|
43
|
+
context "when unpause a queue" do
|
44
|
+
it "should unregister a unregistred queue" do
|
45
|
+
Resque.redis.del "pause:queue:queue1"
|
46
|
+
subject.unpause("queue1")
|
47
|
+
|
48
|
+
subject.paused?("queue1").should be_false
|
49
|
+
end
|
50
|
+
|
51
|
+
it "should unregister a registred queue" do
|
52
|
+
Resque.redis.set "pause:queue:queue1", "AnyValue"
|
53
|
+
expect { subject.unpause("queue1") }.to_not raise_error
|
54
|
+
|
55
|
+
Resque.redis.get("pause:queue:queue1").should be_nil
|
56
|
+
end
|
57
|
+
end
|
58
|
+
|
59
|
+
context "when enqueue a job" do
|
60
|
+
it "should enqueue on a empty queue" do
|
61
|
+
Resque.redis.del "queue:queue1"
|
62
|
+
|
63
|
+
subject.enqueue_job(:queue => "queue1", :class => PauseJob, :args => nil)
|
64
|
+
|
65
|
+
Resque.redis.llen("queue:queue1").to_i.should == 1
|
66
|
+
end
|
67
|
+
|
68
|
+
it "should enqueue on beginning of a queue" do
|
69
|
+
Resque.redis.lpush "queue:queue1", {:class => PauseJob, :args => [1, 2]}.to_json
|
70
|
+
|
71
|
+
subject.enqueue_job(:queue => "queue1", :class => PauseJob, :args => [1])
|
72
|
+
|
73
|
+
jobs = Resque.redis.lrange('queue:queue1', 0, 10)
|
74
|
+
|
75
|
+
jobs.count.should == 2
|
76
|
+
jobs[0].should == {:class => PauseJob, :args => [1]}.to_json
|
77
|
+
jobs[1].should == {:class => PauseJob, :args => [1, 2]}.to_json
|
78
|
+
end
|
79
|
+
end
|
80
|
+
|
81
|
+
context "when dequeue a job" do
|
82
|
+
it "should not get error when queue is empty" do
|
83
|
+
Resque.redis.del "queue:queue1"
|
84
|
+
|
85
|
+
expect { subject.dequeue_job(:queue => "queue1") }.to_not raise_error
|
86
|
+
|
87
|
+
subject.dequeue_job(:queue => "queue1").should be_nil
|
88
|
+
end
|
89
|
+
|
90
|
+
it "should get the job on beginning of a queue" do
|
91
|
+
Resque.redis.lpush "queue:queue1", {:class => PauseJob, :args => [1, 2]}.to_json
|
92
|
+
Resque.redis.lpush "queue:queue1", {:class => PauseJob, :args => [1]}.to_json
|
93
|
+
|
94
|
+
job = subject.dequeue_job(:queue => "queue1")
|
95
|
+
job.should == {:class => PauseJob, :args => [1]}.to_json
|
96
|
+
end
|
97
|
+
end
|
98
|
+
|
99
|
+
context "when checking if queue is paused" do
|
100
|
+
it "should check if queue is paused" do
|
101
|
+
subject.should_receive(:paused?).with("queue1")
|
102
|
+
|
103
|
+
subject.check_paused(:queue => "queue1")
|
104
|
+
end
|
105
|
+
|
106
|
+
it "should not raise error when queue is not paused" do
|
107
|
+
subject.should_receive(:paused?).with("queue1").and_return(false)
|
108
|
+
|
109
|
+
expect { subject.check_paused(:queue => "queue1") }.to_not raise_error
|
110
|
+
end
|
111
|
+
|
112
|
+
it "should raise error when queue is paused" do
|
113
|
+
subject.stub!(:enqueue_job)
|
114
|
+
subject.stub!(:paused?).with("queue1").and_return(true)
|
115
|
+
|
116
|
+
expect { subject.check_paused(:queue => "queue1") }.to raise_error(Resque::Job::DontPerform)
|
117
|
+
end
|
118
|
+
|
119
|
+
it "should enqueue the job again when queue is paused" do
|
120
|
+
subject.stub!(:paused?).with("queue1").and_return(true)
|
121
|
+
|
122
|
+
args = {:queue => "queue1", :class => PauseJob, :args => [1, 2]}
|
123
|
+
subject.should_receive(:enqueue_job).with(args)
|
124
|
+
|
125
|
+
subject.check_paused(args) rescue nil
|
126
|
+
end
|
127
|
+
end
|
128
|
+
|
129
|
+
end
|
data/spec/spec_helper.rb
ADDED
@@ -0,0 +1,65 @@
|
|
1
|
+
require 'rack/test'
|
2
|
+
|
3
|
+
if !system("which redis-server")
|
4
|
+
puts '', "** can't find `redis-server` in your path"
|
5
|
+
abort ''
|
6
|
+
end
|
7
|
+
|
8
|
+
begin
|
9
|
+
require 'simplecov'
|
10
|
+
SimpleCov.start do
|
11
|
+
add_filter '/spec/'
|
12
|
+
end
|
13
|
+
SimpleCov.coverage_dir 'coverage'
|
14
|
+
rescue LoadError
|
15
|
+
# ignore simplecov in ruby < 1.9
|
16
|
+
end
|
17
|
+
|
18
|
+
begin
|
19
|
+
require 'bundler'
|
20
|
+
Bundler.setup
|
21
|
+
Bundler.require(:default, :development)
|
22
|
+
rescue LoadError
|
23
|
+
puts 'Bundler is not installed, you need to gem install it in order to run the specs.'
|
24
|
+
exit 1
|
25
|
+
end
|
26
|
+
|
27
|
+
# Requires supporting files with custom matchers and macros, etc,
|
28
|
+
# in ./support/ and its subdirectories.
|
29
|
+
Dir[File.expand_path('support/**/*.rb', File.dirname(__FILE__))].each { |f| require f }
|
30
|
+
|
31
|
+
# Requires lib.
|
32
|
+
Dir[File.expand_path('../lib/**/*.rb', File.dirname(__FILE__))].each { |f| require f }
|
33
|
+
|
34
|
+
RSpec.configure do |config|
|
35
|
+
# == Mock Framework
|
36
|
+
#
|
37
|
+
# If you prefer to use mocha, flexmock or RR, uncomment the appropriate line:
|
38
|
+
#
|
39
|
+
# config.mock_with :mocha
|
40
|
+
# config.mock_with :flexmock
|
41
|
+
# config.mock_with :rr
|
42
|
+
config.mock_with :rspec
|
43
|
+
|
44
|
+
config.before(:suite) do
|
45
|
+
puts "Starting redis for testing at localhost:9736..."
|
46
|
+
`redis-server #{File.dirname(File.expand_path(__FILE__))}/redis-test.conf`
|
47
|
+
pid = ''
|
48
|
+
while pid.empty? do
|
49
|
+
pid = `ps -e -o pid,command | grep [r]edis-test`.split(" ")[0]
|
50
|
+
end
|
51
|
+
Resque.redis = '127.0.0.1:9736'
|
52
|
+
end
|
53
|
+
|
54
|
+
config.before(:each) do
|
55
|
+
Resque.redis.flushall
|
56
|
+
Kernel.stub!(:sleep)
|
57
|
+
end
|
58
|
+
|
59
|
+
config.after(:suite) do
|
60
|
+
pid = `ps -e -o pid,command | grep [r]edis-test`.split(" ")[0]
|
61
|
+
puts '', "Killing test redis server..."
|
62
|
+
Process.kill("KILL", pid.to_i)
|
63
|
+
`rm -f #{File.dirname(File.expand_path(__FILE__))}/dump.rdb`
|
64
|
+
end
|
65
|
+
end
|
metadata
ADDED
@@ -0,0 +1,146 @@
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
2
|
+
name: resque-pause
|
3
|
+
version: !ruby/object:Gem::Version
|
4
|
+
prerelease: false
|
5
|
+
segments:
|
6
|
+
- 0
|
7
|
+
- 0
|
8
|
+
- 2
|
9
|
+
version: 0.0.2
|
10
|
+
platform: ruby
|
11
|
+
authors:
|
12
|
+
- Wandenberg Peixoto
|
13
|
+
autorequire:
|
14
|
+
bindir: bin
|
15
|
+
cert_chain: []
|
16
|
+
|
17
|
+
date: 2011-06-27 00:00:00 -03:00
|
18
|
+
default_executable:
|
19
|
+
dependencies:
|
20
|
+
- !ruby/object:Gem::Dependency
|
21
|
+
name: resque
|
22
|
+
prerelease: false
|
23
|
+
requirement: &id001 !ruby/object:Gem::Requirement
|
24
|
+
none: false
|
25
|
+
requirements:
|
26
|
+
- - ">="
|
27
|
+
- !ruby/object:Gem::Version
|
28
|
+
segments:
|
29
|
+
- 1
|
30
|
+
- 9
|
31
|
+
- 10
|
32
|
+
version: 1.9.10
|
33
|
+
type: :runtime
|
34
|
+
version_requirements: *id001
|
35
|
+
- !ruby/object:Gem::Dependency
|
36
|
+
name: rspec
|
37
|
+
prerelease: false
|
38
|
+
requirement: &id002 !ruby/object:Gem::Requirement
|
39
|
+
none: false
|
40
|
+
requirements:
|
41
|
+
- - ">="
|
42
|
+
- !ruby/object:Gem::Version
|
43
|
+
segments:
|
44
|
+
- 2
|
45
|
+
- 3
|
46
|
+
- 0
|
47
|
+
version: 2.3.0
|
48
|
+
type: :development
|
49
|
+
version_requirements: *id002
|
50
|
+
- !ruby/object:Gem::Dependency
|
51
|
+
name: rack-test
|
52
|
+
prerelease: false
|
53
|
+
requirement: &id003 !ruby/object:Gem::Requirement
|
54
|
+
none: false
|
55
|
+
requirements:
|
56
|
+
- - ">="
|
57
|
+
- !ruby/object:Gem::Version
|
58
|
+
segments:
|
59
|
+
- 0
|
60
|
+
version: "0"
|
61
|
+
type: :development
|
62
|
+
version_requirements: *id003
|
63
|
+
- !ruby/object:Gem::Dependency
|
64
|
+
name: simplecov
|
65
|
+
prerelease: false
|
66
|
+
requirement: &id004 !ruby/object:Gem::Requirement
|
67
|
+
none: false
|
68
|
+
requirements:
|
69
|
+
- - ">="
|
70
|
+
- !ruby/object:Gem::Version
|
71
|
+
segments:
|
72
|
+
- 0
|
73
|
+
- 4
|
74
|
+
- 2
|
75
|
+
version: 0.4.2
|
76
|
+
type: :development
|
77
|
+
version_requirements: *id004
|
78
|
+
description: |-
|
79
|
+
A Resque plugin to add functionality to pause resque jobs through the web interface.
|
80
|
+
|
81
|
+
Using a `pause` allows you to stop the job for a slice of time.
|
82
|
+
The job finish the process it are doing and don't get a new task to do,
|
83
|
+
until the queue is released.
|
84
|
+
You can use this functionality to do some maintenance whithout kill workers, for example.
|
85
|
+
email:
|
86
|
+
- wandenberg@gmail.com
|
87
|
+
executables: []
|
88
|
+
|
89
|
+
extensions: []
|
90
|
+
|
91
|
+
extra_rdoc_files: []
|
92
|
+
|
93
|
+
files:
|
94
|
+
- .gitignore
|
95
|
+
- Gemfile
|
96
|
+
- Gemfile.lock
|
97
|
+
- README.md
|
98
|
+
- Rakefile
|
99
|
+
- lib/resque-pause.rb
|
100
|
+
- lib/resque/plugins/pause.rb
|
101
|
+
- lib/resque_pause.rb
|
102
|
+
- lib/resque_pause/server.rb
|
103
|
+
- lib/resque_pause/server/public/pause.js
|
104
|
+
- lib/resque_pause/server/views/pause.erb
|
105
|
+
- lib/resque_pause_helper.rb
|
106
|
+
- lib/version.rb
|
107
|
+
- resque-pause.gemspec
|
108
|
+
- spec/redis-test.conf
|
109
|
+
- spec/resque-web_spec.rb
|
110
|
+
- spec/resque/plugins/pause_spec.rb
|
111
|
+
- spec/resque_pause_helper_spec.rb
|
112
|
+
- spec/spec_helper.rb
|
113
|
+
has_rdoc: true
|
114
|
+
homepage: ""
|
115
|
+
licenses: []
|
116
|
+
|
117
|
+
post_install_message:
|
118
|
+
rdoc_options: []
|
119
|
+
|
120
|
+
require_paths:
|
121
|
+
- lib
|
122
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
123
|
+
none: false
|
124
|
+
requirements:
|
125
|
+
- - ">="
|
126
|
+
- !ruby/object:Gem::Version
|
127
|
+
segments:
|
128
|
+
- 0
|
129
|
+
version: "0"
|
130
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
131
|
+
none: false
|
132
|
+
requirements:
|
133
|
+
- - ">="
|
134
|
+
- !ruby/object:Gem::Version
|
135
|
+
segments:
|
136
|
+
- 0
|
137
|
+
version: "0"
|
138
|
+
requirements: []
|
139
|
+
|
140
|
+
rubyforge_project: resque-pause
|
141
|
+
rubygems_version: 1.3.7
|
142
|
+
signing_key:
|
143
|
+
specification_version: 3
|
144
|
+
summary: A Resque plugin to add functionality to pause resque jobs through the web interface.
|
145
|
+
test_files: []
|
146
|
+
|