resque 1.15.0 → 1.16.0

Sign up to get free protection for your applications and to get access to all the features.

Potentially problematic release.


This version of resque might be problematic. Click here for more details.

data/HISTORY.md CHANGED
@@ -1,3 +1,18 @@
1
+ ## 1.16.0 (2011-05-16)
2
+
3
+ * Optional Hoptoad backend extracted into hoptoad_notifier. Install the gem to use it.
4
+ * Added `Worker#paused?` method
5
+ * Bugfix: Properly reseed random number generator after forking.
6
+ * Bugfix: Resque.redis=(<a Redis::Namespace>)
7
+ * Bugfix: Monit example stdout/stderr redirection
8
+ * Bugfix: Removing single failure now works with multiple failure backends
9
+ * Web: 'Remove Queue' now requires confirmation
10
+ * Web: Favicon!
11
+ * Web Bugfix: Dates display in Safari
12
+ * Web Bugfix: Dates display timezone
13
+ * Web Bugfix: Race condition querying working workers
14
+ * Web Bugfix: Fix polling /workers/all in resque-web
15
+
1
16
  ## 1.15.0 (2011-03-18)
2
17
 
3
18
  * Fallback to Redis.connect. Makes ENV variables and whatnot work.
@@ -47,14 +47,17 @@ later, pull those jobs off the queue and process them.
47
47
  Resque jobs are Ruby classes (or modules) which respond to the
48
48
  `perform` method. Here's an example:
49
49
 
50
- class Archive
51
- @queue = :file_serve
52
50
 
53
- def self.perform(repo_id, branch = 'master')
54
- repo = Repository.find(repo_id)
55
- repo.create_archive(branch)
56
- end
57
- end
51
+ ``` ruby
52
+ class Archive
53
+ @queue = :file_serve
54
+
55
+ def self.perform(repo_id, branch = 'master')
56
+ repo = Repository.find(repo_id)
57
+ repo.create_archive(branch)
58
+ end
59
+ end
60
+ ```
58
61
 
59
62
  The `@queue` class instance variable determines which queue `Archive`
60
63
  jobs will be placed in. Queues are arbitrary and created on the fly -
@@ -63,11 +66,13 @@ you can name them whatever you want and have as many as you want.
63
66
  To place an `Archive` job on the `file_serve` queue, we might add this
64
67
  to our application's pre-existing `Repository` class:
65
68
 
66
- class Repository
67
- def async_create_archive(branch)
68
- Resque.enqueue(Archive, self.id, branch)
69
- end
70
- end
69
+ ``` ruby
70
+ class Repository
71
+ def async_create_archive(branch)
72
+ Resque.enqueue(Archive, self.id, branch)
73
+ end
74
+ end
75
+ ```
71
76
 
72
77
  Now when we call `repo.async_create_archive('masterbrew')` in our
73
78
  application, a job will be created and placed on the `file_serve`
@@ -75,12 +80,16 @@ queue.
75
80
 
76
81
  Later, a worker will run something like this code to process the job:
77
82
 
78
- klass, args = Resque.reserve(:file_serve)
79
- klass.perform(*args) if klass.respond_to? :perform
83
+ ``` ruby
84
+ klass, args = Resque.reserve(:file_serve)
85
+ klass.perform(*args) if klass.respond_to? :perform
86
+ ```
80
87
 
81
88
  Which translates to:
82
89
 
83
- Archive.perform(44, 'masterbrew')
90
+ ``` ruby
91
+ Archive.perform(44, 'masterbrew')
92
+ ```
84
93
 
85
94
  Let's start a worker to run `file_serve` jobs:
86
95
 
@@ -129,25 +138,33 @@ needs to be crunched later into a queue.
129
138
  Jobs are persisted to queues as JSON objects. Let's take our `Archive`
130
139
  example from above. We'll run the following code to create a job:
131
140
 
132
- repo = Repository.find(44)
133
- repo.async_create_archive('masterbrew')
141
+ ``` ruby
142
+ repo = Repository.find(44)
143
+ repo.async_create_archive('masterbrew')
144
+ ```
134
145
 
135
146
  The following JSON will be stored in the `file_serve` queue:
136
147
 
137
- {
138
- 'class': 'Archive',
139
- 'args': [ 44, 'masterbrew' ]
140
- }
148
+ ``` javascript
149
+ {
150
+ 'class': 'Archive',
151
+ 'args': [ 44, 'masterbrew' ]
152
+ }
153
+ ```
141
154
 
142
155
  Because of this your jobs must only accept arguments that can be JSON encoded.
143
156
 
144
157
  So instead of doing this:
145
158
 
146
- Resque.enqueue(Archive, self, branch)
159
+ ``` ruby
160
+ Resque.enqueue(Archive, self, branch)
161
+ ```
147
162
 
148
163
  do this:
149
164
 
150
- Resque.enqueue(Archive, self.id, branch)
165
+ ``` ruby
166
+ Resque.enqueue(Archive, self.id, branch)
167
+ ```
151
168
 
152
169
  This is why our above example (and all the examples in `examples/`)
153
170
  uses object IDs instead of passing around the objects.
@@ -187,15 +204,17 @@ Workers
187
204
 
188
205
  Resque workers are rake tasks that run forever. They basically do this:
189
206
 
190
- start
191
- loop do
192
- if job = reserve
193
- job.process
194
- else
195
- sleep 5
196
- end
197
- end
198
- shutdown
207
+ ``` ruby
208
+ start
209
+ loop do
210
+ if job = reserve
211
+ job.process
212
+ else
213
+ sleep 5
214
+ end
215
+ end
216
+ shutdown
217
+ ```
199
218
 
200
219
  Starting a worker is simple. Here's our example from earlier:
201
220
 
@@ -214,13 +233,17 @@ This will load the environment before starting a worker. Alternately
214
233
  we can define a `resque:setup` task with a dependency on the
215
234
  `environment` rake task:
216
235
 
217
- task "resque:setup" => :environment
236
+ ``` ruby
237
+ task "resque:setup" => :environment
238
+ ```
218
239
 
219
240
  GitHub's setup task looks like this:
220
241
 
221
- task "resque:setup" => :environment do
222
- Grit::Git.git_timeout = 10.minutes
223
- end
242
+ ``` ruby
243
+ task "resque:setup" => :environment do
244
+ Grit::Git.git_timeout = 10.minutes
245
+ end
246
+ ```
224
247
 
225
248
  We don't want the `git_timeout` as high as 10 minutes in our web app,
226
249
  but in the Resque workers it's fine.
@@ -435,11 +458,13 @@ Nginx: <http://www.modrails.com/documentation/Users%20guide%20Nginx.html#deployi
435
458
  If you want to load Resque on a subpath, possibly alongside other
436
459
  apps, it's easy to do with Rack's `URLMap`:
437
460
 
438
- require 'resque/server'
461
+ ``` ruby
462
+ require 'resque/server'
439
463
 
440
- run Rack::URLMap.new \
441
- "/" => Your::App.new,
442
- "/resque" => Resque::Server.new
464
+ run Rack::URLMap.new \
465
+ "/" => Your::App.new,
466
+ "/resque" => Resque::Server.new
467
+ ```
443
468
 
444
469
  Check `examples/demo/config.ru` for a functional example (including
445
470
  HTTP basic auth).
@@ -555,7 +580,9 @@ First install the gem.
555
580
 
556
581
  Next include it in your application.
557
582
 
558
- require 'resque'
583
+ ``` ruby
584
+ require 'resque'
585
+ ```
559
586
 
560
587
  Now start your application:
561
588
 
@@ -566,8 +593,10 @@ That's it! You can now create Resque jobs from within your app.
566
593
  To start a worker, create a Rakefile in your app's root (or add this
567
594
  to an existing Rakefile):
568
595
 
569
- require 'your/app'
570
- require 'resque/tasks'
596
+ ``` ruby
597
+ require 'your/app'
598
+ require 'resque/tasks'
599
+ ```
571
600
 
572
601
  Now:
573
602
 
@@ -596,7 +625,9 @@ That's it! You can now create Resque jobs from within your app.
596
625
 
597
626
  To start a worker, add this to your Rakefile in `RAILS_ROOT`:
598
627
 
599
- require 'resque/tasks'
628
+ ``` ruby
629
+ require 'resque/tasks'
630
+ ```
600
631
 
601
632
  Now:
602
633
 
@@ -649,11 +680,13 @@ Here's our `config/resque.yml`:
649
680
 
650
681
  And our initializer:
651
682
 
652
- rails_root = ENV['RAILS_ROOT'] || File.dirname(__FILE__) + '/../..'
653
- rails_env = ENV['RAILS_ENV'] || 'development'
683
+ ``` ruby
684
+ rails_root = ENV['RAILS_ROOT'] || File.dirname(__FILE__) + '/../..'
685
+ rails_env = ENV['RAILS_ENV'] || 'development'
654
686
 
655
- resque_config = YAML.load_file(rails_root + '/config/resque.yml')
656
- Resque.redis = resque_config[rails_env]
687
+ resque_config = YAML.load_file(rails_root + '/config/resque.yml')
688
+ Resque.redis = resque_config[rails_env]
689
+ ```
657
690
 
658
691
  Easy peasy! Why not just use `RAILS_ROOT` and `RAILS_ENV`? Because
659
692
  this way we can tell our Sinatra app about the config file:
@@ -665,7 +698,9 @@ Now everyone is on the same page.
665
698
  Also, you could disable jobs queueing by setting 'inline' attribute.
666
699
  For example, if you want to run all jobs in the same process for cucumber, try:
667
700
 
668
- Resque.inline = ENV['RAILS_ENV'] == "cucumber"
701
+ ``` ruby
702
+ Resque.inline = ENV['RAILS_ENV'] == "cucumber"
703
+ ```
669
704
 
670
705
 
671
706
  Plugins and Hooks
@@ -692,7 +727,9 @@ in your Redis server.
692
727
 
693
728
  Simply use the `Resque.redis.namespace` accessor:
694
729
 
695
- Resque.redis.namespace = "resque:GitHub"
730
+ ``` ruby
731
+ Resque.redis.namespace = "resque:GitHub"
732
+ ```
696
733
 
697
734
  We recommend sticking this in your initializer somewhere after Redis
698
735
  is configured.
@@ -723,6 +760,13 @@ of charge. This is **not** used by GitHub in production, so please
723
760
  send patches for any tweaks or improvements you can make to it.
724
761
 
725
762
 
763
+ Questions
764
+ ---------
765
+
766
+ Please add them to the [FAQ](https://github.com/defunkt/resque/wiki/FAQ) or
767
+ ask on the Mailing List. The Mailing List is explained further below
768
+
769
+
726
770
  Development
727
771
  -----------
728
772
 
@@ -24,14 +24,15 @@ module Resque
24
24
  extend self
25
25
 
26
26
  # Accepts:
27
- # 1. A 'hostname:port' string
28
- # 2. A 'hostname:port:db' string (to select the Redis db)
29
- # 3. A 'hostname:port/namespace' string (to set the Redis namespace)
30
- # 4. A redis URL string 'redis://host:port'
27
+ # 1. A 'hostname:port' String
28
+ # 2. A 'hostname:port:db' String (to select the Redis db)
29
+ # 3. A 'hostname:port/namespace' String (to set the Redis namespace)
30
+ # 4. A Redis URL String 'redis://host:port'
31
31
  # 5. An instance of `Redis`, `Redis::Client`, `Redis::DistRedis`,
32
32
  # or `Redis::Namespace`.
33
33
  def redis=(server)
34
- if server.respond_to? :split
34
+ case server
35
+ when String
35
36
  if server =~ /redis\:\/\//
36
37
  redis = Redis.connect(:url => server, :thread_safe => true)
37
38
  else
@@ -43,8 +44,8 @@ module Resque
43
44
  namespace ||= :resque
44
45
 
45
46
  @redis = Redis::Namespace.new(namespace, :redis => redis)
46
- elsif server.respond_to? :namespace=
47
- @redis = server
47
+ when Redis::Namespace
48
+ @redis = server
48
49
  else
49
50
  @redis = Redis::Namespace.new(:resque, :redis => server)
50
51
  end
@@ -136,6 +137,19 @@ module Resque
136
137
 
137
138
  # Pushes a job onto a queue. Queue name should be a string and the
138
139
  # item should be any JSON-able Ruby object.
140
+ #
141
+ # Resque works generally expect the `item` to be a hash with the following
142
+ # keys:
143
+ #
144
+ # class - The String name of the job to run.
145
+ # args - An Array of arguments to pass the job. Usually passed
146
+ # via `class.to_class.perform(*args)`.
147
+ #
148
+ # Example
149
+ #
150
+ # Resque.push('archive', :class => 'Archive', :args => [ 35, 'tar' ])
151
+ #
152
+ # Returns nothing
139
153
  def push(queue, item)
140
154
  watch_queue(queue)
141
155
  redis.rpush "queue:#{queue}", encode(item)
@@ -333,3 +347,4 @@ module Resque
333
347
  end
334
348
  end
335
349
  end
350
+
@@ -1,6 +1,8 @@
1
- require 'net/https'
2
- require 'builder'
3
- require 'uri'
1
+ begin
2
+ require 'hoptoad_notifier'
3
+ rescue LoadError
4
+ raise "Can't find 'hoptoad_notifier' gem. Please add it to your Gemfile or install it."
5
+ end
4
6
 
5
7
  module Resque
6
8
  module Failure
@@ -10,28 +12,17 @@ module Resque
10
12
  #
11
13
  # require 'resque/failure/hoptoad'
12
14
  #
13
- # Resque::Failure::Hoptoad.configure do |config|
14
- # config.api_key = 'blah'
15
- # config.secure = true
15
+ # Resque::Failure::Multiple.classes = [Resque::Failure::Redis, Resque::Failure::Hoptoad]
16
+ # Resque::Failure.backend = Resque::Failure::Multiple
16
17
  #
17
- # # optional proxy support
18
- # config.proxy_host = 'x.y.z.t'
19
- # config.proxy_port = 8080
18
+ # Once you've configured resque to use the Hoptoad failure backend,
19
+ # you'll want to setup an initializer to configure the Hoptoad.
20
20
  #
21
- # # server env support, defaults to RAILS_ENV or RACK_ENV
22
- # config.server_environment = "test"
23
- # end
21
+ # HoptoadNotifier.configure do |config|
22
+ # config.api_key = 'your_key_here'
23
+ # end
24
+ # For more information see https://github.com/thoughtbot/hoptoad_notifier
24
25
  class Hoptoad < Base
25
- # From the hoptoad plugin
26
- INPUT_FORMAT = /^([^:]+):(\d+)(?::in `([^']+)')?$/
27
-
28
- class << self
29
- attr_accessor :secure, :api_key
30
- attr_accessor :proxy_host, :proxy_port, :proxy_user, :proxy_pass
31
- attr_accessor :server_environment
32
- attr_accessor :host, :port
33
- attr_accessor :http_read_timeout, :http_open_timeout
34
- end
35
26
 
36
27
  def self.count
37
28
  # We can't get the total # of errors from Hoptoad so we fake it
@@ -39,101 +30,15 @@ module Resque
39
30
  Stat[:failed]
40
31
  end
41
32
 
42
- def self.configure
43
- yield self
44
- Resque::Failure.backend = self
45
- end
46
-
47
33
  def save
48
- http = use_ssl? ? :https : :http
49
- host = self.class.host || 'hoptoadapp.com'
50
- port = self.class.port
51
- url = URI.parse("#{http}://#{host}:#{port}/notifier_api/v2/notices/")
52
-
53
- request = Net::HTTP::Proxy self.class.proxy_host, self.class.proxy_port,
54
- self.class.proxy_user, self.class.proxy_pass
55
- http = request.new(url.host, url.port)
56
- headers = {
57
- 'Content-type' => 'text/xml',
58
- 'Accept' => 'text/xml, application/xml'
59
- }
60
-
61
- http.read_timeout = self.class.http_read_timeout || 5 # seconds
62
- http.open_timeout = self.class.http_open_timeout || 2 # seconds
63
-
64
- http.use_ssl = use_ssl?
65
-
66
- begin
67
- response = http.post(url.path, xml, headers)
68
- rescue TimeoutError => e
69
- log "Timeout while contacting the Hoptoad server."
70
- end
71
-
72
- case response
73
- when Net::HTTPSuccess then
74
- log "Hoptoad Success: #{response.class}"
75
- else
76
- body = response.body if response.respond_to? :body
77
- log "Hoptoad Failure: #{response.class}\n#{body}"
78
- end
34
+ HoptoadNotifier.notify_or_ignore(exception,
35
+ :parameters => {
36
+ :payload_class => payload['class'].to_s,
37
+ :payload_args => payload['args'].inspect
38
+ }
39
+ )
79
40
  end
80
41
 
81
- def xml
82
- x = Builder::XmlMarkup.new
83
- x.instruct!
84
- x.notice :version=>"2.0" do
85
- x.tag! "api-key", api_key
86
- x.notifier do
87
- x.name "Resqueue"
88
- x.version "0.1"
89
- x.url "http://github.com/defunkt/resque"
90
- end
91
- x.error do
92
- x.tag! "class", exception.class.name
93
- x.message "#{exception.class.name}: #{exception.message}"
94
- x.backtrace do
95
- fill_in_backtrace_lines(x)
96
- end
97
- end
98
- x.request do
99
- x.url queue.to_s
100
- x.component worker.to_s
101
- x.params do
102
- x.var :key=>"payload_class" do
103
- x.text! payload["class"].to_s
104
- end
105
- x.var :key=>"payload_args" do
106
- x.text! payload["args"].to_s
107
- end
108
- end
109
- end
110
- x.tag!("server-environment") do
111
- x.tag!("environment-name",server_environment)
112
- x.tag!("project-root", "RAILS_ROOT")
113
- end
114
-
115
- end
116
- end
117
-
118
- def fill_in_backtrace_lines(x)
119
- Array(exception.backtrace).each do |unparsed_line|
120
- _, file, number, method = unparsed_line.match(INPUT_FORMAT).to_a
121
- x.line :file => file,:number => number
122
- end
123
- end
124
-
125
- def use_ssl?
126
- self.class.secure
127
- end
128
-
129
- def api_key
130
- self.class.api_key
131
- end
132
-
133
- def server_environment
134
- return self.class.server_environment if self.class.server_environment
135
- defined?(RAILS_ENV) ? RAILS_ENV : (ENV['RACK_ENV'] || 'development')
136
- end
137
42
  end
138
43
  end
139
44
  end
@@ -45,6 +45,10 @@ module Resque
45
45
  def self.requeue(*args)
46
46
  classes.first.requeue(*args)
47
47
  end
48
+
49
+ def self.remove(index)
50
+ classes.each { |klass| klass.remove(index) }
51
+ end
48
52
  end
49
53
  end
50
- end
54
+ end
@@ -2,6 +2,7 @@ require 'sinatra/base'
2
2
  require 'erb'
3
3
  require 'resque'
4
4
  require 'resque/version'
5
+ require 'time'
5
6
 
6
7
  module Resque
7
8
  class Server < Sinatra::Base
@@ -124,11 +125,27 @@ module Resque
124
125
  erb :error, {:layout => false}, :error => "Can't connect to Redis! (#{Resque.redis_id})"
125
126
  end
126
127
  end
128
+
129
+ def show_for_polling(page)
130
+ content_type "text/html"
131
+ @polling = true
132
+ show(page.to_sym, false).gsub(/\s{1,}/, ' ')
133
+ end
127
134
 
128
135
  # to make things easier on ourselves
129
136
  get "/?" do
130
137
  redirect url_path(:overview)
131
138
  end
139
+
140
+ %w( overview workers ).each do |page|
141
+ get "/#{page}.poll" do
142
+ show_for_polling(page)
143
+ end
144
+
145
+ get "/#{page}/:id.poll" do
146
+ show_for_polling(page)
147
+ end
148
+ end
132
149
 
133
150
  %w( overview queues working workers key ).each do |page|
134
151
  get "/#{page}" do
@@ -145,14 +162,6 @@ module Resque
145
162
  redirect u('queues')
146
163
  end
147
164
 
148
- %w( overview workers ).each do |page|
149
- get "/#{page}.poll" do
150
- content_type "text/html"
151
- @polling = true
152
- show(page.to_sym, false).gsub(/\s{1,}/, ' ')
153
- end
154
- end
155
-
156
165
  get "/failed" do
157
166
  if Resque::Failure.url
158
167
  redirect Resque::Failure.url
@@ -22,10 +22,10 @@
22
22
  <% else %>
23
23
  <dt>Worker</dt>
24
24
  <dd>
25
- <a href="<%= u(:workers, job['worker']) %>"><%= job['worker'].split(':')[0...2].join(':') %></a> on <b class='queue-tag'><%= job['queue'] %></b > at <b><span class="time"><%= job['failed_at'] %></span></b>
25
+ <a href="<%= u(:workers, job['worker']) %>"><%= job['worker'].split(':')[0...2].join(':') %></a> on <b class='queue-tag'><%= job['queue'] %></b > at <b><span class="time"><%= Time.parse(job['failed_at']).strftime("%D %T %z") %></span></b>
26
26
  <% if job['retried_at'] %>
27
27
  <div class='retried'>
28
- Retried <b><span class="time"><%= job['retried_at'] %></span></b>
28
+ Retried <b><span class="time"><%= Time.parse(job['retried_at']).strftime("%D %T %z") %></span></b>
29
29
  <a href="<%= u "failed/remove/#{start + index - 1}" %>" class="remove" rel="remove">Remove</a>
30
30
  </div>
31
31
  <% else %>
@@ -4,7 +4,7 @@
4
4
 
5
5
  <h1>Pending jobs on <span class='hl'><%= queue %></span></h1>
6
6
  <form method="POST" action="<%=u "/queues/#{queue}/remove" %>" class='remove-queue'>
7
- <input type='submit' name='' value='Remove Queue' />
7
+ <input type='submit' name='' value='Remove Queue' onclick='return confirm("Are you absolutely sure? This cannot be undone.");' />
8
8
  </form>
9
9
  <p class='sub'>Showing <%= start = params[:start].to_i %> to <%= start + 20 %> of <b><%=size = resque.size(queue)%></b> jobs</p>
10
10
  <table class='jobs'>
@@ -27,8 +27,14 @@
27
27
 
28
28
  <% else %>
29
29
 
30
- <% workers = resque.working.reject { |w| w.idle? } %>
31
- <h1 class='wi'><%= workers.size %> of <%= resque.workers.size %> Workers Working</h1>
30
+ <%
31
+ workers = resque.working
32
+ jobs = workers.collect {|w| w.job }
33
+ worker_jobs = workers.zip(jobs)
34
+ worker_jobs = worker_jobs.reject { |w, j| w.idle? }
35
+ %>
36
+
37
+ <h1 class='wi'><%= worker_jobs.size %> of <%= resque.workers.size %> Workers Working</h1>
32
38
  <p class='intro'>The list below contains all workers which are currently running a job.</p>
33
39
  <table class='workers'>
34
40
  <tr>
@@ -37,15 +43,13 @@
37
43
  <th>Queue</th>
38
44
  <th>Processing</th>
39
45
  </tr>
40
- <% if workers.empty? %>
46
+ <% if worker_jobs.empty? %>
41
47
  <tr>
42
48
  <td colspan="4" class='no-data'>Nothing is happening right now...</td>
43
49
  </tr>
44
50
  <% end %>
45
51
 
46
- <% for worker in workers.sort_by { |w| w.job['run_at'] ? w.job['run_at'] : '' } %>
47
- <% job = worker.job %>
48
-
52
+ <% worker_jobs.sort_by {|w, j| j['run_at'] ? j['run_at'] : '' }.each do |worker, job| %>
49
53
  <tr>
50
54
  <td class='icon'><img src="<%=u state = worker.state %>.png" alt="<%= state %>" title="<%= state %>"></td>
51
55
  <% host, pid, queues = worker.to_s.split(':') %>
@@ -1,3 +1,3 @@
1
1
  module Resque
2
- Version = VERSION = '1.15.0'
2
+ Version = VERSION = '1.16.0'
3
3
  end
@@ -116,13 +116,13 @@ module Resque
116
116
  loop do
117
117
  break if shutdown?
118
118
 
119
- if not @paused and job = reserve
119
+ if not paused? and job = reserve
120
120
  log "got: #{job.inspect}"
121
121
  run_hook :before_fork, job
122
122
  working_on job
123
123
 
124
124
  if @child = fork
125
- rand # Reseeding
125
+ srand # Reseeding
126
126
  procline "Forked #{@child} at #{Time.now.to_i}"
127
127
  Process.wait
128
128
  else
@@ -136,7 +136,7 @@ module Resque
136
136
  else
137
137
  break if interval.zero?
138
138
  log! "Sleeping for #{interval} seconds"
139
- procline @paused ? "Paused" : "Waiting for #{@queues.join(',')}"
139
+ procline paused? ? "Paused" : "Waiting for #{@queues.join(',')}"
140
140
  sleep interval
141
141
  end
142
142
  end
@@ -298,6 +298,11 @@ module Resque
298
298
  end
299
299
  end
300
300
 
301
+ # are we paused?
302
+ def paused?
303
+ @paused
304
+ end
305
+
301
306
  # Stop processing jobs after the current one has completed (if we're
302
307
  # currently running one).
303
308
  def pause_processing
File without changes
File without changes
@@ -0,0 +1,25 @@
1
+ require 'test_helper'
2
+
3
+ begin
4
+ require 'hoptoad_notifier'
5
+ rescue LoadError
6
+ warn "Install hoptoad_notifier gem to run Hoptoad tests."
7
+ end
8
+
9
+ if defined? HoptoadNotifier
10
+ context "Hoptoad" do
11
+ test "should be notified of an error" do
12
+ exception = StandardError.new("BOOM")
13
+ worker = Resque::Worker.new(:test)
14
+ queue = "test"
15
+ payload = {'class' => Object, 'args' => 66}
16
+
17
+ HoptoadNotifier.expects(:notify_or_ignore).with(
18
+ exception,
19
+ :parameters => {:payload_class => 'Object', :payload_args => '66'})
20
+
21
+ backend = Resque::Failure::Hoptoad.new(exception, worker, queue, payload)
22
+ backend.save
23
+ end
24
+ end
25
+ end
@@ -16,6 +16,15 @@ context "Resque" do
16
16
  assert_equal 'namespace', Resque.redis.namespace
17
17
  end
18
18
 
19
+ test "redis= works correctly with a Redis::Namespace param" do
20
+ new_redis = Redis.new(:host => "localhost", :port => 9736)
21
+ new_namespace = Redis::Namespace.new("namespace", :redis => new_redis)
22
+ Resque.redis = new_namespace
23
+ assert_equal new_namespace, Resque.redis
24
+
25
+ Resque.redis = 'localhost:9736/namespace'
26
+ end
27
+
19
28
  test "can put jobs on a queue" do
20
29
  assert Resque::Job.create(:jobs, 'SomeJob', 20, '/tmp')
21
30
  assert Resque::Job.create(:jobs, 'SomeJob', 20, '/tmp')
@@ -1,9 +1,12 @@
1
+ require 'rubygems'
2
+ require 'bundler'
3
+ Bundler.setup(:default, :test)
4
+ Bundler.require(:default, :test)
5
+
1
6
  dir = File.dirname(File.expand_path(__FILE__))
2
7
  $LOAD_PATH.unshift dir + '/../lib'
3
8
  $TESTING = true
4
9
  require 'test/unit'
5
- require 'rubygems'
6
- require 'resque'
7
10
 
8
11
  begin
9
12
  require 'leftright'
metadata CHANGED
@@ -1,13 +1,13 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: resque
3
3
  version: !ruby/object:Gem::Version
4
- hash: 43
5
- prerelease: false
4
+ hash: 87
5
+ prerelease:
6
6
  segments:
7
7
  - 1
8
- - 15
8
+ - 16
9
9
  - 0
10
- version: 1.15.0
10
+ version: 1.16.0
11
11
  platform: ruby
12
12
  authors:
13
13
  - Chris Wanstrath
@@ -15,7 +15,7 @@ autorequire:
15
15
  bindir: bin
16
16
  cert_chain: []
17
17
 
18
- date: 2011-03-19 00:00:00 -07:00
18
+ date: 2011-05-16 00:00:00 -07:00
19
19
  default_executable:
20
20
  dependencies:
21
21
  - !ruby/object:Gem::Dependency
@@ -24,14 +24,14 @@ dependencies:
24
24
  requirement: &id001 !ruby/object:Gem::Requirement
25
25
  none: false
26
26
  requirements:
27
- - - ">="
27
+ - - ~>
28
28
  - !ruby/object:Gem::Version
29
- hash: 55
29
+ hash: 19
30
30
  segments:
31
+ - 1
31
32
  - 0
32
- - 10
33
- - 0
34
- version: 0.10.0
33
+ - 2
34
+ version: 1.0.2
35
35
  type: :runtime
36
36
  version_requirements: *id001
37
37
  - !ruby/object:Gem::Dependency
@@ -72,7 +72,7 @@ dependencies:
72
72
  requirement: &id004 !ruby/object:Gem::Requirement
73
73
  none: false
74
74
  requirements:
75
- - - ~>
75
+ - - ">="
76
76
  - !ruby/object:Gem::Version
77
77
  hash: 11
78
78
  segments:
@@ -80,6 +80,13 @@ dependencies:
80
80
  - 4
81
81
  - 6
82
82
  version: 1.4.6
83
+ - - <
84
+ - !ruby/object:Gem::Version
85
+ hash: 3
86
+ segments:
87
+ - 1
88
+ - 6
89
+ version: "1.6"
83
90
  type: :runtime
84
91
  version_requirements: *id004
85
92
  description: " Resque is a Redis-backed Ruby library for creating background jobs,\n placing those jobs on multiple queues, and processing them later.\n\n Background jobs can be any Ruby class or module that responds to\n perform. Your existing classes can easily be converted to background\n jobs or you can create new classes specifically to do work. Or, you\n can do both.\n\n Resque is heavily inspired by DelayedJob (which rocks) and is\n comprised of three parts:\n\n * A Ruby library for creating, querying, and processing jobs\n * A Rake task for starting a worker which processes jobs\n * A Sinatra app for monitoring queues, jobs, and workers.\n"
@@ -106,6 +113,7 @@ files:
106
113
  - lib/resque/helpers.rb
107
114
  - lib/resque/job.rb
108
115
  - lib/resque/plugin.rb
116
+ - lib/resque/server/public/favicon.ico
109
117
  - lib/resque/server/public/idle.png
110
118
  - lib/resque/server/public/jquery-1.3.2.min.js
111
119
  - lib/resque/server/public/jquery.relatize_date.js
@@ -132,8 +140,11 @@ files:
132
140
  - lib/resque/version.rb
133
141
  - lib/resque/worker.rb
134
142
  - lib/resque.rb
143
+ - lib/tasks/redis.rake
144
+ - lib/tasks/resque.rake
135
145
  - bin/resque
136
146
  - bin/resque-web
147
+ - test/hoptoad_test.rb
137
148
  - test/job_hooks_test.rb
138
149
  - test/job_plugins_test.rb
139
150
  - test/plugin_test.rb
@@ -142,8 +153,6 @@ files:
142
153
  - test/resque_test.rb
143
154
  - test/test_helper.rb
144
155
  - test/worker_test.rb
145
- - tasks/redis.rake
146
- - tasks/resque.rake
147
156
  has_rdoc: true
148
157
  homepage: http://github.com/defunkt/resque
149
158
  licenses: []
@@ -174,7 +183,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
174
183
  requirements: []
175
184
 
176
185
  rubyforge_project:
177
- rubygems_version: 1.3.7
186
+ rubygems_version: 1.5.2
178
187
  signing_key:
179
188
  specification_version: 3
180
189
  summary: Resque is a Redis-backed queueing system.