resque-pause 0.0.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.
- 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
|
+
|