resque 2.1.0 → 2.3.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.

checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: b930a952313756e06d51bb6daa493ebeed0c4498940e46d24300f7fafdac36b3
4
- data.tar.gz: ea821158f150dbf5740dff8cb210be0f7507c1e183acd3a902308f0ef91e7f2c
3
+ metadata.gz: 26c77950669242c68e75f64480a798486a84ac3aa2c4bd22c5ae212caa6bf57c
4
+ data.tar.gz: bea29587e61e5b2a41c675ff26afb69cca7891613212e0d052a41a43ce5404b4
5
5
  SHA512:
6
- metadata.gz: d266f8019b93add5de76d0d3e5a460c2a03c3fc04b3d71c65f296269c7e286875b6b1925d31d01699c952d14319164cab39062f9310314fed0b4229b92f47821
7
- data.tar.gz: d375348987a655202483adb5eccb253ed07eea17d88749c04837e0ec05dad948805cb371500ac42b11650595327875f0af56e9c3501261e8223f6c1fbfff5f5f
6
+ metadata.gz: 81f58c37a382d84e6f168ad9ada384ac160c223fa5cc1070c251ad01c8840389af78736af263aa3cd594dcd77970a2539a7f44082dca07a25f236c6d147625b4
7
+ data.tar.gz: f28ffa6efb6e8037cf3ec7d233f824b7190f97d91c4d3d6ba00399e6533f2958581e98422a31068a9145dd789f63d1caff58ca8744905a1cf747b02eaeed9d02
data/HISTORY.md CHANGED
@@ -1,14 +1,40 @@
1
- ## Unreleased
1
+ ## 2.3.0
2
+
3
+ ### Fixed
4
+
5
+ * Fix NoMethodError: undefined method 'application' for Rails:Module when Rails module is defined but not a full Rails app (#1799)
6
+ * Fix deprecation warnings in Redis#pipelined for redis 4.6 (#1806)
7
+ * Add Ruby syntax highlighting to remaining markdown docs (#1802)
8
+ * Fix pagination section (#1809)
9
+ * Fix `before_run` undefined local variable or method `runner` (#1811)
10
+
11
+ ### Added
12
+
13
+ * Added support for pausing all workers by setting the Redis key `pause-all-workers` to string value "true" (#1803)
14
+
15
+ ## 2.2.1
16
+
17
+ ### Fixed
18
+
19
+ * Escape HTML from the params to avoid XSS (#1790)
20
+ * Remove vegas as a dependency (#1780)
21
+
22
+ ### Added
23
+
24
+ * Add support for specifying queues that workers should ignore when using globs
25
+ * Allow plugins to have spaces in their name (#1718)
26
+
27
+ ## 2.2.0
2
28
 
3
29
  ### Added
4
30
 
5
- *
6
- *
31
+ * Add 'Retry Failed Jobs' button to Failed page
7
32
 
8
33
  ### Fixed
9
34
 
10
- *
11
- *
35
+ * Loading railtie when it did not exist #1765
36
+ * Fix closing parent Redis connection in child process after fork
37
+ * Fix the failed queues list on /queues UI when the RedisMultiQueue backend is used #1638
12
38
 
13
39
  ## 2.1.0
14
40
 
data/README.markdown CHANGED
@@ -4,19 +4,15 @@ Resque
4
4
  [![Gem Version](https://badge.fury.io/rb/resque.svg)](https://rubygems.org/gems/resque)
5
5
  [![Build Status](https://github.com/resque/resque/actions/workflows/ci.yml/badge.svg)](https://github.com/resque/resque/actions/workflows/ci.yml)
6
6
 
7
+ Introduction
8
+ ------------
9
+
7
10
  Resque (pronounced like "rescue") is a Redis-backed library for creating
8
11
  background jobs, placing those jobs on multiple queues, and processing
9
12
  them later.
10
13
 
11
- ---------
12
- ### Note on the future of this repo
13
-
14
- Would you like to be involved in Resque? Do you have thoughts about what
15
- Resque should be and do going forward? There's currently an [open discussion here](https://github.com/resque/resque/issues/1759)
16
- on just that topic, so please feel free to join in. We'd love to hear your thoughts
17
- and/or have people volunteer to be a part of the project!
14
+ For the backstory, philosophy, and history of Resque's beginnings, please see [the blog post](http://github.com/blog/542-introducing-resque) (2009).
18
15
 
19
- ---------
20
16
  Background jobs can be any Ruby class or module that responds to
21
17
  `perform`. Your existing classes can easily be converted to background
22
18
  jobs or you can create new classes specifically to do work. Or, you
@@ -29,10 +25,11 @@ three parts:
29
25
  2. A Rake task for starting a worker which processes jobs
30
26
  3. A Sinatra app for monitoring queues, jobs, and workers.
31
27
 
32
- Resque workers can be distributed between multiple machines,
33
- support priorities, are resilient to memory bloat / "leaks," are
34
- optimized for REE (but work on MRI and JRuby), tell you what they're
35
- doing, and expect failure.
28
+ Resque workers can be given multiple queues (a "queue list"),
29
+ distributed between multiple machines,
30
+ run anywhere with network access to the Redis server,
31
+ support priorities, are resilient to memory bloat / "leaks,"
32
+ tell you what they're doing, and expect failure.
36
33
 
37
34
  Resque queues are persistent; support constant time, atomic push and
38
35
  pop (thanks to Redis); provide visibility into their contents; and
@@ -45,42 +42,15 @@ general usage stats, and helps you track failures.
45
42
  Resque now supports Ruby 2.3.0 and above.
46
43
  We will also only be supporting Redis 3.0 and above going forward.
47
44
 
45
+ ### Note on the future of Resque
48
46
 
49
- Table of Contents
50
- -----------------
47
+ Would you like to be involved in Resque? Do you have thoughts about what
48
+ Resque should be and do going forward? There's currently an [open discussion here](https://github.com/resque/resque/issues/1759)
49
+ on just that topic, so please feel free to join in. We'd love to hear your thoughts
50
+ and/or have people volunteer to be a part of the project!
51
51
 
52
- * [Overview](#overview)
53
- * [Installation](#installation)
54
- * [Running Workers](#running-workers)
55
- * [The Front End](#the-front-end)
56
- * [Jobs](#jobs)
57
- * [Configuration](#configuration)
58
- * * [Redis](#redis)
59
- * * [Logging](#logging)
60
- * * [Namespaces](#namespaces)
61
- * * [Storing Statistics](#storing-statistics)
62
- * [Plugins and Hooks](#plugins-and-hooks)
63
- * [Additional Information](#additional-information)
64
- * * [Resque vs DelayedJob](#resque-vs-delayedjob)
65
- * * [Forking](#forking)
66
- * * [Signals](#signals)
67
- * * [Heroku](#heroku)
68
- * * [Monitoring](#monitoring)
69
- * * [Mysql::Error](#mysqlerror-mysql-server-has-gone-away)
70
- * [Development](#development)
71
- * * [Demo](#demo)
72
- * * [Contributing](#contributing)
73
- * [Questions](#questions)
74
- * [Meta](#meta)
75
- * [Author](#author)
76
-
77
- Overview
78
- --------
79
-
80
- For the backstory, philosophy, and history of Resque's beginnings, please see [the blog post](http://github.com/blog/542-introducing-resque).
81
-
82
- Resque allows you to create jobs and place them on a queue, then,
83
- later, pull those jobs off the queue and process them.
52
+ Example
53
+ -------
84
54
 
85
55
  Resque jobs are Ruby classes (or modules) which respond to the
86
56
  `perform` method. Here's an example:
@@ -140,10 +110,6 @@ This starts one Resque worker and tells it to work off the
140
110
  find any more, at which point it will sleep for a small period and
141
111
  repeatedly poll the queue for more jobs.
142
112
 
143
- Workers can be given multiple queues (a "queue list") and run on
144
- multiple machines. In fact they can be run anywhere with network
145
- access to the Redis server.
146
-
147
113
  Installation
148
114
  ------------
149
115
 
@@ -165,7 +131,7 @@ require 'resque/tasks'
165
131
  require 'your/app' # Include this line if you want your workers to have access to your application
166
132
  ```
167
133
 
168
- #### Rails 3+
134
+ #### Rails
169
135
 
170
136
  To make resque specific changes, you can override the `resque:setup` job in `lib/tasks` (ex: `lib/tasks/resque.rake`). GitHub's setup task looks like this:
171
137
 
@@ -253,6 +219,22 @@ Or, prioritize some queues above `*`:
253
219
 
254
220
  # QUEUE=critical,* rake resque:work
255
221
 
222
+ #### Running All Queues Except for Some
223
+
224
+ If you want your workers to work off of all queues except for some,
225
+ you can use negation:
226
+
227
+ $ QUEUE=*,!low rake resque:work
228
+
229
+ Negated globs also work. The following will instruct workers to work
230
+ off of all queues except those beginning with `file_`:
231
+
232
+ $ QUEUE=*,!file_* rake resque:work
233
+
234
+ Note that the order in which negated queues are specified does not
235
+ matter, so `QUEUE=*,!file_*` and `QUEUE=!file_*,*` will have the same
236
+ effect.
237
+
256
238
  #### Process IDs (PIDs)
257
239
 
258
240
  There are scenarios where it's helpful to record the PID of a resque
@@ -331,9 +313,9 @@ run Rack::URLMap.new \
331
313
  Check `examples/demo/config.ru` for a functional example (including
332
314
  HTTP basic auth).
333
315
 
334
- #### Rails 3+
316
+ #### Rails
335
317
 
336
- You can also mount Resque on a subpath in your existing Rails 3 app by adding `require 'resque/server'` to the top of your routes file or in an initializer then adding this to `routes.rb`:
318
+ You can also mount Resque on a subpath in your existing Rails app by adding `require 'resque/server'` to the top of your routes file or in an initializer then adding this to `routes.rb`:
337
319
 
338
320
  ``` ruby
339
321
  mount Resque::Server.new, :at => "/resque"
@@ -687,6 +669,12 @@ complicated.
687
669
 
688
670
  Workers instead handle their own state.
689
671
 
672
+ #### `at_exit` Callbacks
673
+
674
+ Resque uses `Kernel#exit!` for exiting its workers' child processes. So any `at_exit` callback defined in your application won't be executed when the job is finished and the child process exits.
675
+
676
+ You can alter this behavior by setting the `RUN_AT_EXIT_HOOKS` environment variable.
677
+
690
678
  #### Parents and Children
691
679
 
692
680
  Here's a parent / child pair doing some work:
@@ -728,7 +716,7 @@ If you want to kill a stale or stuck child and shutdown, use `TERM`
728
716
 
729
717
  If you want to stop processing jobs, but want to leave the worker running
730
718
  (for example, to temporarily alleviate load), use `USR2` to stop processing,
731
- then `CONT` to start it again.
719
+ then `CONT` to start it again. It's also possible to [pause all workers](#pausing-all-workers).
732
720
 
733
721
  #### Heroku
734
722
 
@@ -752,6 +740,22 @@ time to complete before being forced to die.
752
740
 
753
741
  * `RESQUE_TERM_TIMEOUT` - By default you have a few seconds to handle `Resque::TermException` in your job. `RESQUE_TERM_TIMEOUT` and `RESQUE_PRE_SHUTDOWN_TIMEOUT` must be lower than the [heroku dyno timeout](https://devcenter.heroku.com/articles/limits#exit-timeout).
754
742
 
743
+ #### Pausing all workers
744
+
745
+ Workers will not process pending jobs if the Redis key `pause-all-workers` is set with the string value "true".
746
+
747
+ ``` ruby
748
+ Resque.redis.set('pause-all-workers', 'true')
749
+ ```
750
+
751
+ Nothing happens to jobs that are already being processed by workers.
752
+
753
+ Unpause by removing the Redis key `pause-all-workers`.
754
+
755
+ ``` ruby
756
+ Resque.redis.del('pause-all-workers')
757
+ ```
758
+
755
759
  #### Monitoring
756
760
 
757
761
  ##### god
@@ -770,7 +774,7 @@ send patches for any tweaks or improvements you can make to it.
770
774
 
771
775
  If your workers remain idle for too long they may lose their MySQL connection. Depending on your version of Rails, we recommend the following:
772
776
 
773
- ##### Rails 3.x
777
+ ##### Rails
774
778
  In your `perform` method, add the following line:
775
779
 
776
780
  ``` ruby
@@ -861,7 +865,6 @@ Meta
861
865
  * Home: <http://github.com/resque/resque>
862
866
  * Docs: <http://rubydoc.info/gems/resque>
863
867
  * Bugs: <http://github.com/resque/resque/issues>
864
- * Chat: <irc://irc.freenode.net/resque>
865
868
  * Gems: <https://rubygems.org/gems/resque>
866
869
 
867
870
  This project uses [Semantic Versioning](http://semver.org/)
data/bin/resque-web CHANGED
@@ -1,31 +1,15 @@
1
1
  #!/usr/bin/env ruby
2
2
 
3
3
  $LOAD_PATH.unshift File.expand_path(File.dirname(__FILE__) + '/../lib')
4
- begin
5
- require 'vegas'
6
- rescue LoadError
7
- require 'rubygems'
8
- require 'vegas'
9
- end
10
- require 'resque/server'
11
-
12
4
 
13
- Vegas::Runner.new(Resque::Server, 'resque-web', {
14
- :before_run => lambda {|v|
15
- path = (ENV['RESQUECONFIG'] || v.args.first)
16
- load path.to_s.strip if path
17
- }
18
- }) do |runner, opts, app|
19
- opts.on('-N NAMESPACE', "--namespace NAMESPACE", "set the Redis namespace") {|namespace|
20
- runner.logger.info "Using Redis namespace '#{namespace}'"
21
- Resque.redis.namespace = namespace
22
- }
23
- opts.on('-r redis-connection', "--redis redis-connection", "set the Redis connection string") {|redis_conf|
24
- runner.logger.info "Using Redis connection '#{redis_conf}'"
25
- Resque.redis = redis_conf
26
- }
27
- opts.on('-a url-prefix', "--append url-prefix", "set reverse_proxy friendly prefix to links") {|url_prefix|
28
- runner.logger.info "Using URL Prefix '#{url_prefix}'"
29
- Resque::Server.url_prefix = url_prefix
30
- }
5
+ if !!(RUBY_PLATFORM =~ /(mingw|bccwin|wince|mswin32)/i)
6
+ begin
7
+ require 'win32/process'
8
+ rescue
9
+ puts "Sorry, in order to use resque-web on Windows you need the win32-process gem:",
10
+ "gem install win32-process"
11
+ end
31
12
  end
13
+ require 'resque/web_runner'
14
+
15
+ Resque::WebRunner.new(*ARGV)
@@ -76,9 +76,10 @@ module Resque
76
76
  @redis.inspect
77
77
  end
78
78
 
79
- # Force a reconnect to Redis.
79
+ # Force a reconnect to Redis without closing the connection in the parent
80
+ # process after a fork.
80
81
  def reconnect
81
- @redis._client.reconnect
82
+ @redis._client.connect
82
83
  end
83
84
 
84
85
  # Returns an array of all known Resque keys in Redis. Redis' KEYS operation
@@ -99,9 +100,9 @@ module Resque
99
100
  @redis = redis
100
101
  end
101
102
  def push_to_queue(queue,encoded_item)
102
- @redis.pipelined do
103
- watch_queue(queue)
104
- @redis.rpush redis_key_for_queue(queue), encoded_item
103
+ @redis.pipelined do |piped|
104
+ watch_queue(queue, redis: piped)
105
+ piped.rpush redis_key_for_queue(queue), encoded_item
105
106
  end
106
107
  end
107
108
 
@@ -128,9 +129,9 @@ module Resque
128
129
  end
129
130
 
130
131
  def remove_queue(queue)
131
- @redis.pipelined do
132
- @redis.srem(:queues, queue.to_s)
133
- @redis.del(redis_key_for_queue(queue))
132
+ @redis.pipelined do |piped|
133
+ piped.srem(:queues, queue.to_s)
134
+ piped.del(redis_key_for_queue(queue))
134
135
  end
135
136
  end
136
137
 
@@ -144,8 +145,8 @@ module Resque
144
145
  end
145
146
 
146
147
  # Private: do not call
147
- def watch_queue(queue)
148
- @redis.sadd(:queues, queue.to_s)
148
+ def watch_queue(queue, redis: @redis)
149
+ redis.sadd(:queues, queue.to_s)
149
150
  end
150
151
 
151
152
  # Private: do not call
@@ -236,24 +237,24 @@ module Resque
236
237
  end
237
238
 
238
239
  def register_worker(worker)
239
- @redis.pipelined do
240
- @redis.sadd(:workers, worker)
241
- worker_started(worker)
240
+ @redis.pipelined do |piped|
241
+ piped.sadd(:workers, worker)
242
+ worker_started(worker, redis: piped)
242
243
  end
243
244
  end
244
245
 
245
- def worker_started(worker)
246
- @redis.set(redis_key_for_worker_start_time(worker), Time.now.to_s)
246
+ def worker_started(worker, redis: @redis)
247
+ redis.set(redis_key_for_worker_start_time(worker), Time.now.to_s)
247
248
  end
248
249
 
249
250
  def unregister_worker(worker, &block)
250
- @redis.pipelined do
251
- @redis.srem(:workers, worker)
252
- @redis.del(redis_key_for_worker(worker))
253
- @redis.del(redis_key_for_worker_start_time(worker))
254
- @redis.hdel(HEARTBEAT_KEY, worker.to_s)
251
+ @redis.pipelined do |piped|
252
+ piped.srem(:workers, worker)
253
+ piped.del(redis_key_for_worker(worker))
254
+ piped.del(redis_key_for_worker_start_time(worker))
255
+ piped.hdel(HEARTBEAT_KEY, worker.to_s)
255
256
 
256
- block.call
257
+ block.call redis: piped
257
258
  end
258
259
  end
259
260
 
@@ -287,9 +288,9 @@ module Resque
287
288
  end
288
289
 
289
290
  def worker_done_working(worker, &block)
290
- @redis.pipelined do
291
- @redis.del(redis_key_for_worker(worker))
292
- block.call
291
+ @redis.pipelined do |piped|
292
+ piped.del(redis_key_for_worker(worker))
293
+ block.call redis: piped
293
294
  end
294
295
  end
295
296
 
@@ -316,16 +317,16 @@ module Resque
316
317
  @redis.get("stat:#{stat}").to_i
317
318
  end
318
319
 
319
- def increment_stat(stat, by = 1)
320
- @redis.incrby("stat:#{stat}", by)
320
+ def increment_stat(stat, by = 1, redis: @redis)
321
+ redis.incrby("stat:#{stat}", by)
321
322
  end
322
323
 
323
324
  def decremet_stat(stat, by = 1)
324
325
  @redis.decrby("stat:#{stat}", by)
325
326
  end
326
327
 
327
- def clear_stat(stat)
328
- @redis.del("stat:#{stat}")
328
+ def clear_stat(stat, redis: @redis)
329
+ redis.del("stat:#{stat}")
329
330
  end
330
331
  end
331
332
  end
@@ -91,6 +91,12 @@ module Resque
91
91
  backend.clear(queue)
92
92
  end
93
93
 
94
+ def self.clear_retried
95
+ each do |index, job|
96
+ remove(index) unless job['retried_at'].nil?
97
+ end
98
+ end
99
+
94
100
  def self.requeue(id, queue = nil)
95
101
  backend.requeue(id, queue)
96
102
  end
@@ -9,7 +9,9 @@ Resque::Server.helpers do
9
9
 
10
10
  def failed_multiple_queues?
11
11
  return @multiple_failed_queues if defined?(@multiple_failed_queues)
12
- @multiple_failed_queues = Resque::Failure.queues.size > 1
12
+
13
+ @multiple_failed_queues = Resque::Failure.queues.size > 1 ||
14
+ (defined?(Resque::Failure::RedisMultiQueue) && Resque::Failure.backend == Resque::Failure::RedisMultiQueue)
13
15
  end
14
16
 
15
17
  def failed_size
@@ -1 +1 @@
1
- <h1 style="font-size:110%;font-family:Arial, sans-serif;"><%= error %></h1>
1
+ <h1 style="font-size:110%;font-family:Arial, sans-serif;"><%= escape_html(error) %></h1>
@@ -1,15 +1,21 @@
1
1
  <% if failed_multiple_queues? && !params[:queue] %>
2
2
  <h1>All Failed Queues: <%= Resque::Failure.queues.size %> total</h1>
3
3
  <% else %>
4
- <h1>Failed Jobs <%= "on '#{params[:queue]}'" if params[:queue] %> <%= "with class '#{params[:class]}'" if params[:class] %></h1>
4
+ <h1>Failed Jobs <%= "on '#{escape_html(params[:queue])}'" if params[:queue] %> <%= "with class '#{escape_html(params[:class])}'" if params[:class] %></h1>
5
5
  <% end %>
6
6
 
7
7
  <% unless failed_size.zero? %>
8
8
  <form method="POST" action="<%= u "failed#{'/' + params[:queue] if params[:queue]}/clear" %>">
9
- <input type="submit" name="" value="Clear <%= params[:queue] ? "'#{params[:queue]}'" : 'Failed' %> Jobs" class="confirmSubmission" />
9
+ <input type="submit" name="" value="Clear <%= params[:queue] ? "'#{escape_html(params[:queue])}'" : 'Failed' %> Jobs" class="confirmSubmission" />
10
10
  </form>
11
+
12
+ <% unless params[:queue] %>
13
+ <form method="POST" action="<%= u "failed/clear_retried" %>">
14
+ <input type="submit" name="" value="Clear Retried Jobs" onclick='return confirm("Are you absolutely sure? This cannot be undone.");' />
15
+ </form>
16
+ <% end %>
11
17
  <form method="POST" action="<%= u "failed#{'/' + params[:queue] if params[:queue]}/requeue/all" %>">
12
- <input type="submit" name="" value="Retry <%= params[:queue] ? "'#{params[:queue]}'" : 'Failed' %> Jobs" class="confirmSubmission" />
18
+ <input type="submit" name="" value="Retry <%= params[:queue] ? "'#{escape_html(params[:queue])}'" : 'Failed' %> Jobs" class="confirmSubmission" />
13
19
  </form>
14
20
  <% end %>
15
21
 
@@ -1,6 +1,8 @@
1
1
  <% if job['class'] == 'ActiveJob::QueueAdapters::ResqueAdapter::JobWrapper' %>
2
2
  <code><%= job['args'].first['job_class'] %></code>
3
- <small><a href="http://edgeguides.rubyonrails.org/active_job_basics.html" target="_blank">(via ActiveJob)</a></small>
3
+ <small>
4
+ <a href="http://edgeguides.rubyonrails.org/active_job_basics.html" rel="noopener noreferrer" target="_blank">(via ActiveJob)</a>
5
+ </small>
4
6
  <% else %>
5
7
  <code><%= job['class'] %></code>
6
8
  <% end %>
@@ -1,5 +1,5 @@
1
1
  <% if key = params[:key] %>
2
- <h1>Key "<%= key %>" is a <%= resque.redis.type key %></h1>
2
+ <h1>Key "<%= escape_html(key) %>" is a <%= resque.redis.type key %></h1>
3
3
  <h2>size: <%= redis_get_size(key) %></h2>
4
4
  <table>
5
5
  <tr>
@@ -37,7 +37,7 @@
37
37
  </div>
38
38
 
39
39
  <div id="footer">
40
- <p>Powered by <a href="http://github.com/resque/resque">Resque</a> v<%=Resque::Version%></p>
40
+ <p>Powered by <a href="http://github.com/resque/resque">Resque</a> v<%=Resque::VERSION%></p>
41
41
  <p>Connected to Redis namespace <%= Resque.redis.namespace %> on <%=Resque.redis_id%></p>
42
42
  </div>
43
43
 
@@ -7,7 +7,7 @@
7
7
  <a href="<%= current_page %>?start=<%= start - per_page %>" class='less'>&laquo; Previous</a>
8
8
  <% end %>
9
9
 
10
- <% (size / per_page.to_f - 1).ceil.times do |page_num| %>
10
+ <% (size / per_page.to_f).ceil.times do |page_num| %>
11
11
  <% if start == page_num * per_page %>
12
12
  <span><%= page_num + 1 %></span>
13
13
  <% else %>
@@ -15,7 +15,7 @@
15
15
  <% end %>
16
16
  <% end %>
17
17
 
18
- <% if start + per_page <= size %>
18
+ <% if start + per_page < size %>
19
19
  <a href="<%= current_page %>?start=<%= start + per_page %>" class='more'>Next &raquo;</a>
20
20
  <% end %>
21
21
  </div>
@@ -2,7 +2,7 @@
2
2
 
3
3
  <% if current_queue = params[:id] %>
4
4
 
5
- <h1>Pending jobs on <span class='hl'><%= h current_queue %></span></h1>
5
+ <h1>Pending jobs on <span class='hl'><%= h escape_html(current_queue) %></span></h1>
6
6
  <form method="POST" action="<%=u "/queues/#{current_queue}/remove" %>" class='remove-queue'>
7
7
  <input type='submit' name='' value='Remove Queue' class="confirmSubmission" />
8
8
  </form>
data/lib/resque/server.rb CHANGED
@@ -53,7 +53,7 @@ module Resque
53
53
  def tab(name)
54
54
  dname = name.to_s.downcase
55
55
  path = url_path(dname)
56
- "<li #{class_if_current(path)}><a href='#{path}'>#{name}</a></li>"
56
+ "<li #{class_if_current(path)}><a href='#{path.gsub(" ", "_")}'>#{name}</a></li>"
57
57
  end
58
58
 
59
59
  def tabs
@@ -205,6 +205,11 @@ module Resque
205
205
  redirect u('failed')
206
206
  end
207
207
 
208
+ post "/failed/clear_retried" do
209
+ Resque::Failure.clear_retried
210
+ redirect u('failed')
211
+ end
212
+
208
213
  post "/failed/:queue/clear" do
209
214
  Resque::Failure.clear params[:queue]
210
215
  redirect u('failed')
data/lib/resque/stat.rb CHANGED
@@ -35,8 +35,8 @@ module Resque
35
35
  #
36
36
  # Can optionally accept a second int parameter. The stat is then
37
37
  # incremented by that amount.
38
- def incr(stat, by = 1)
39
- data_store.increment_stat(stat,by)
38
+ def incr(stat, by = 1, **opts)
39
+ data_store.increment_stat(stat, by, **opts)
40
40
  end
41
41
 
42
42
  # Increments a stat by one.
@@ -58,8 +58,8 @@ module Resque
58
58
  end
59
59
 
60
60
  # Removes a stat from Redis, effectively setting it to 0.
61
- def clear(stat)
62
- data_store.clear_stat(stat)
61
+ def clear(stat, **opts)
62
+ data_store.clear_stat(stat, **opts)
63
63
  end
64
64
  end
65
65
  end
data/lib/resque/tasks.rb CHANGED
@@ -39,7 +39,7 @@ namespace :resque do
39
39
 
40
40
  # Preload app files if this is Rails
41
41
  task :preload => :setup do
42
- if defined?(Rails)
42
+ if defined?(Rails) && Rails.respond_to?(:application)
43
43
  if Rails.application.config.eager_load
44
44
  ActiveSupport.run_load_hooks(:before_eager_load, Rails.application)
45
45
  Rails.application.config.eager_load_namespaces.each(&:eager_load!)
@@ -1,3 +1,3 @@
1
1
  module Resque
2
- Version = VERSION = '2.1.0'
2
+ VERSION = '2.3.0'
3
3
  end
@@ -0,0 +1,372 @@
1
+ require 'open-uri'
2
+ require 'logger'
3
+ require 'optparse'
4
+ require 'fileutils'
5
+ require 'rack'
6
+ require 'resque/server'
7
+
8
+ # only used with `bin/resque-web`
9
+ # https://github.com/resque/resque/pull/1780
10
+
11
+ module Resque
12
+ WINDOWS = !!(RUBY_PLATFORM =~ /(mingw|bccwin|wince|mswin32)/i)
13
+ JRUBY = !!(RbConfig::CONFIG["RUBY_INSTALL_NAME"] =~ /^jruby/i)
14
+
15
+ class WebRunner
16
+ attr_reader :app, :app_name, :filesystem_friendly_app_name,
17
+ :rack_handler, :port, :options, :args
18
+
19
+ PORT = 5678
20
+ HOST = WINDOWS ? 'localhost' : '0.0.0.0'
21
+
22
+ def initialize(*runtime_args)
23
+ @options = runtime_args.last.is_a?(Hash) ? runtime_args.pop : {}
24
+
25
+ self.class.logger.level = options[:debug] ? Logger::DEBUG : Logger::INFO
26
+
27
+ @app = Resque::Server
28
+ @app_name = 'resque-web'
29
+ @filesystem_friendly_app_name = @app_name.gsub(/\W+/, "_")
30
+
31
+ @args = load_options(runtime_args)
32
+
33
+ @rack_handler = (s = options[:rack_handler]) ? Rack::Handler.get(s) : setup_rack_handler
34
+
35
+ case option_parser.command
36
+ when :help
37
+ puts option_parser
38
+ when :kill
39
+ kill!
40
+ when :status
41
+ status
42
+ when :version
43
+ puts "resque #{Resque::VERSION}"
44
+ puts "rack #{Rack::VERSION.join('.')}"
45
+ puts "sinatra #{Sinatra::VERSION}" if defined?(Sinatra)
46
+ else
47
+ before_run
48
+ start unless options[:start] == false
49
+ end
50
+ end
51
+
52
+ def launch_path
53
+ if options[:launch_path].respond_to?(:call)
54
+ options[:launch_path].call(self)
55
+ else
56
+ options[:launch_path]
57
+ end
58
+ end
59
+
60
+ def app_dir
61
+ if !options[:app_dir] && !ENV['HOME']
62
+ raise ArgumentError.new("nor --app-dir neither ENV['HOME'] defined")
63
+ end
64
+ options[:app_dir] || File.join(ENV['HOME'], filesystem_friendly_app_name)
65
+ end
66
+
67
+ def pid_file
68
+ options[:pid_file] || File.join(app_dir, "#{filesystem_friendly_app_name}.pid")
69
+ end
70
+
71
+ def url_file
72
+ options[:url_file] || File.join(app_dir, "#{filesystem_friendly_app_name}.url")
73
+ end
74
+
75
+ def log_file
76
+ options[:log_file] || File.join(app_dir, "#{filesystem_friendly_app_name}.log")
77
+ end
78
+
79
+ def host
80
+ options.fetch(:host) { HOST }
81
+ end
82
+
83
+ def url
84
+ "http://#{host}:#{port}"
85
+ end
86
+
87
+ def before_run
88
+ if (redis_conf = options[:redis_conf])
89
+ logger.info "Using Redis connection '#{redis_conf}'"
90
+ Resque.redis = redis_conf
91
+ end
92
+ if (namespace = options[:redis_namespace])
93
+ logger.info "Using Redis namespace '#{namespace}'"
94
+ Resque.redis.namespace = namespace
95
+ end
96
+ if (url_prefix = options[:url_prefix])
97
+ logger.info "Using URL Prefix '#{url_prefix}'"
98
+ Resque::Server.url_prefix = url_prefix
99
+ end
100
+ app.set(options.merge web_runner: self)
101
+ path = (ENV['RESQUECONFIG'] || args.first)
102
+ load_config_file(path.to_s.strip) if path
103
+ end
104
+
105
+ def start(path = launch_path)
106
+ logger.info "Running with Windows Settings" if WINDOWS
107
+ logger.info "Running with JRuby" if JRUBY
108
+ logger.info "Starting '#{app_name}'..."
109
+
110
+ check_for_running(path)
111
+ find_port
112
+ write_url
113
+ launch!(url, path)
114
+ daemonize! unless options[:foreground]
115
+ run!
116
+ rescue RuntimeError => e
117
+ logger.warn "There was an error starting '#{app_name}': #{e}"
118
+ exit
119
+ end
120
+
121
+ def find_port
122
+ if @port = options[:port]
123
+ announce_port_attempted
124
+
125
+ unless port_open?
126
+ logger.warn "Port #{port} is already in use. Please try another. " +
127
+ "You can also omit the port flag, and we'll find one for you."
128
+ end
129
+ else
130
+ @port = PORT
131
+ announce_port_attempted
132
+
133
+ until port_open?
134
+ @port += 1
135
+ announce_port_attempted
136
+ end
137
+ end
138
+ end
139
+
140
+ def announce_port_attempted
141
+ logger.info "trying port #{port}..."
142
+ end
143
+
144
+ def port_open?(check_url = nil)
145
+ begin
146
+ check_url ||= url
147
+ options[:no_proxy] ? uri_open(check_url, :proxy => nil) : uri_open(check_url)
148
+ false
149
+ rescue Errno::ECONNREFUSED, Errno::EPERM, Errno::ETIMEDOUT
150
+ true
151
+ end
152
+ end
153
+
154
+ def uri_open(*args)
155
+ (RbConfig::CONFIG['ruby_version'] < '2.7') ? open(*args) : URI.open(*args)
156
+ end
157
+
158
+ def write_url
159
+ # Make sure app dir is setup
160
+ FileUtils.mkdir_p(app_dir)
161
+ File.open(url_file, 'w') {|f| f << url }
162
+ end
163
+
164
+ def check_for_running(path = nil)
165
+ if File.exist?(pid_file) && File.exist?(url_file)
166
+ running_url = File.read(url_file)
167
+ if !port_open?(running_url)
168
+ logger.warn "'#{app_name}' is already running at #{running_url}"
169
+ launch!(running_url, path)
170
+ exit!(1)
171
+ end
172
+ end
173
+ end
174
+
175
+ def run!
176
+ logger.info "Running with Rack handler: #{@rack_handler.inspect}"
177
+
178
+ rack_handler.run app, :Host => host, :Port => port do |server|
179
+ kill_commands.each do |command|
180
+ trap(command) do
181
+ ## Use thins' hard #stop! if available, otherwise just #stop
182
+ server.respond_to?(:stop!) ? server.stop! : server.stop
183
+ logger.info "'#{app_name}' received INT ... stopping"
184
+ delete_pid!
185
+ end
186
+ end
187
+ end
188
+ end
189
+
190
+ # Adapted from Rackup
191
+ def daemonize!
192
+ if JRUBY
193
+ # It's not a true daemon but when executed with & works like one
194
+ thread = Thread.new {daemon_execute}
195
+ thread.join
196
+
197
+ elsif RUBY_VERSION < "1.9"
198
+ logger.debug "Parent Process: #{Process.pid}"
199
+ exit!(0) if fork
200
+ logger.debug "Child Process: #{Process.pid}"
201
+ daemon_execute
202
+
203
+ else
204
+ Process.daemon(true, true)
205
+ daemon_execute
206
+ end
207
+ end
208
+
209
+ def daemon_execute
210
+ File.umask 0000
211
+ FileUtils.touch log_file
212
+ STDIN.reopen log_file
213
+ STDOUT.reopen log_file, "a"
214
+ STDERR.reopen log_file, "a"
215
+
216
+ logger.debug "Child Process: #{Process.pid}"
217
+
218
+ File.open(pid_file, 'w') {|f| f.write("#{Process.pid}") }
219
+ at_exit { delete_pid! }
220
+ end
221
+
222
+ def launch!(specific_url = nil, path = nil)
223
+ return if options[:skip_launch]
224
+ cmd = WINDOWS ? "start" : "open"
225
+ system "#{cmd} #{specific_url || url}#{path}"
226
+ end
227
+
228
+ def kill!
229
+ pid = File.read(pid_file)
230
+ logger.warn "Sending #{kill_command} to #{pid.to_i}"
231
+ Process.kill(kill_command, pid.to_i)
232
+ rescue => e
233
+ logger.warn "pid not found at #{pid_file} : #{e}"
234
+ end
235
+
236
+ def status
237
+ if File.exists?(pid_file)
238
+ logger.info "'#{app_name}' running"
239
+ logger.info "PID #{File.read(pid_file)}"
240
+ logger.info "URL #{File.read(url_file)}" if File.exists?(url_file)
241
+ else
242
+ logger.info "'#{app_name}' not running!"
243
+ end
244
+ end
245
+
246
+ # Loads a config file at config_path and evals it in the context of the @app.
247
+ def load_config_file(config_path)
248
+ abort "Can not find config file at #{config_path}" if !File.readable?(config_path)
249
+ config = File.read(config_path)
250
+ # trim off anything after __END__
251
+ config.sub!(/^__END__\n.*/, '')
252
+ @app.module_eval(config)
253
+ end
254
+
255
+ def self.logger=(logger)
256
+ @logger = logger
257
+ end
258
+
259
+ def self.logger
260
+ @logger ||= LOGGER if defined?(LOGGER)
261
+ if !@logger
262
+ @logger = Logger.new(STDOUT)
263
+ @logger.formatter = Proc.new {|s, t, n, msg| "[#{t}] #{msg}\n"}
264
+ @logger
265
+ end
266
+ @logger
267
+ end
268
+
269
+ def logger
270
+ self.class.logger
271
+ end
272
+
273
+ private
274
+ def setup_rack_handler
275
+ # First try to set Rack handler via a special hook we honor
276
+ @rack_handler = if @app.respond_to?(:detect_rack_handler)
277
+ @app.detect_rack_handler
278
+
279
+ # If they aren't using our hook, try to use their @app.server settings
280
+ elsif @app.respond_to?(:server) and @app.server
281
+ # If :server isn't set, it returns an array of possibilities,
282
+ # sorted from most to least preferable.
283
+ if @app.server.is_a?(Array)
284
+ handler = nil
285
+ @app.server.each do |server|
286
+ begin
287
+ handler = Rack::Handler.get(server)
288
+ break
289
+ rescue LoadError, NameError => e
290
+ next
291
+ end
292
+ end
293
+ handler
294
+
295
+ # :server might be set explicitly to a single option like "mongrel"
296
+ else
297
+ Rack::Handler.get(@app.server)
298
+ end
299
+
300
+ # If all else fails, we'll use Thin
301
+ else
302
+ JRUBY ? Rack::Handler::WEBrick : Rack::Handler::Thin
303
+ end
304
+ end
305
+
306
+ def load_options(runtime_args)
307
+ @args = option_parser.parse!(runtime_args)
308
+ options.merge!(option_parser.options)
309
+ args
310
+ rescue OptionParser::MissingArgument => e
311
+ logger.warn "#{e}, run -h for options"
312
+ exit
313
+ end
314
+
315
+ def option_parser
316
+ @option_parser ||= Parser.new(app_name)
317
+ end
318
+
319
+ class Parser < OptionParser
320
+ attr_reader :command, :options
321
+
322
+ def initialize(app_name)
323
+ super("", 24, ' ')
324
+ self.banner = "Usage: #{app_name} [options]"
325
+
326
+ @options = {}
327
+ basename = app_name.gsub(/\W+/, "_")
328
+ on('-K', "--kill", "kill the running process and exit") { @command = :kill }
329
+ on('-S', "--status", "display the current running PID and URL then quit") { @command = :status }
330
+ string_option("-s", "--server SERVER", "serve using SERVER (thin/mongrel/webrick)", :rack_handler)
331
+ string_option("-o", "--host HOST", "listen on HOST (default: #{HOST})", :host)
332
+ string_option("-p", "--port PORT", "use PORT (default: #{PORT})", :port)
333
+ on("-x", "--no-proxy", "ignore env proxy settings (e.g. http_proxy)") { opts[:no_proxy] = true }
334
+ boolean_option("-F", "--foreground", "don't daemonize, run in the foreground", :foreground)
335
+ boolean_option("-L", "--no-launch", "don't launch the browser", :skip_launch)
336
+ boolean_option('-d', "--debug", "raise the log level to :debug (default: :info)", :debug)
337
+ string_option("--app-dir APP_DIR", "set the app dir where files are stored (default: ~/#{basename}/)", :app_dir)
338
+ string_option("-P", "--pid-file PID_FILE", "set the path to the pid file (default: app_dir/#{basename}.pid)", :pid_file)
339
+ string_option("--log-file LOG_FILE", "set the path to the log file (default: app_dir/#{basename}.log)", :log_file)
340
+ string_option("--url-file URL_FILE", "set the path to the URL file (default: app_dir/#{basename}.url)", :url_file)
341
+ string_option('-N NAMESPACE', "--namespace NAMESPACE", "set the Redis namespace", :redis_namespace)
342
+ string_option('-r redis-connection', "--redis redis-connection", "set the Redis connection string", :redis_conf)
343
+ string_option('-a url-prefix', "--append url-prefix", "set reverse_proxy friendly prefix to links", :url_prefix)
344
+ separator ""
345
+ separator "Common options:"
346
+ on_tail("-h", "--help", "Show this message") { @command = :help }
347
+ on_tail("--version", "Show version") { @command = :version }
348
+ end
349
+
350
+ def boolean_option(*argv)
351
+ k = argv.pop; on(*argv) { options[k] = true }
352
+ end
353
+
354
+ def string_option(*argv)
355
+ k = argv.pop; on(*argv) { |value| options[k] = value }
356
+ end
357
+ end
358
+
359
+ def kill_commands
360
+ WINDOWS ? [1] : [:INT, :TERM]
361
+ end
362
+
363
+ def kill_command
364
+ kill_commands[0]
365
+ end
366
+
367
+ def delete_pid!
368
+ File.delete(pid_file) if File.exist?(pid_file)
369
+ end
370
+ end
371
+
372
+ end
data/lib/resque/worker.rb CHANGED
@@ -180,9 +180,17 @@ module Resque
180
180
  WILDCARDS = ['*', '?', '{', '}', '[', ']'].freeze
181
181
 
182
182
  def queues=(queues)
183
- queues = queues.empty? ? (ENV["QUEUES"] || ENV['QUEUE']).to_s.split(',') : queues
184
- @queues = queues.map { |queue| queue.to_s.strip }
185
- @has_dynamic_queues = WILDCARDS.any? {|char| @queues.join.include?(char) }
183
+ queues = (ENV["QUEUES"] || ENV['QUEUE']).to_s.split(',') if queues.empty?
184
+ queues = queues.map { |queue| queue.to_s.strip }
185
+
186
+ @skip_queues, @queues = queues.partition { |queue| queue.start_with?('!') }
187
+ @skip_queues.map! { |queue| queue[1..-1] }
188
+
189
+ # The behavior of `queues` is dependent on the value of `@has_dynamic_queues: if it's true, the method returns the result of filtering @queues with `glob_match`
190
+ # if it's false, the method returns @queues directly. Since `glob_match` will cause skipped queues to be filtered out, we want to make sure it's called if we have @skip_queues.any?
191
+ @has_dynamic_queues =
192
+ @skip_queues.any? || WILDCARDS.any? { |char| @queues.join.include?(char) }
193
+
186
194
  validate_queues
187
195
  end
188
196
 
@@ -210,7 +218,8 @@ module Resque
210
218
 
211
219
  def glob_match(list, pattern)
212
220
  list.select do |queue|
213
- File.fnmatch?(pattern, queue)
221
+ File.fnmatch?(pattern, queue) &&
222
+ @skip_queues.none? { |skip_pattern| File.fnmatch?(skip_pattern, queue) }
214
223
  end.sort
215
224
  end
216
225
 
@@ -570,7 +579,7 @@ module Resque
570
579
 
571
580
  # are we paused?
572
581
  def paused?
573
- @paused
582
+ @paused || redis.get('pause-all-workers').to_s.strip.downcase == 'true'
574
583
  end
575
584
 
576
585
  # Stop processing jobs after the current one has completed (if we're
@@ -688,9 +697,9 @@ module Resque
688
697
 
689
698
  kill_background_threads
690
699
 
691
- data_store.unregister_worker(self) do
692
- Stat.clear("processed:#{self}")
693
- Stat.clear("failed:#{self}")
700
+ data_store.unregister_worker(self) do |**opts|
701
+ Stat.clear("processed:#{self}", **opts)
702
+ Stat.clear("failed:#{self}", **opts)
694
703
  end
695
704
  rescue Exception => exception_while_unregistering
696
705
  message = exception_while_unregistering.message
@@ -717,8 +726,8 @@ module Resque
717
726
  # Called when we are done working - clears our `working_on` state
718
727
  # and tells Redis we processed a job.
719
728
  def done_working
720
- data_store.worker_done_working(self) do
721
- processed!
729
+ data_store.worker_done_working(self) do |**opts|
730
+ processed!(**opts)
722
731
  end
723
732
  end
724
733
 
@@ -736,9 +745,9 @@ module Resque
736
745
  end
737
746
 
738
747
  # Tell Redis we've processed a job.
739
- def processed!
740
- Stat << "processed"
741
- Stat << "processed:#{self}"
748
+ def processed!(**opts)
749
+ Stat.incr("processed", 1, **opts)
750
+ Stat.incr("processed:#{self}", 1, **opts)
742
751
  end
743
752
 
744
753
  # How many failed jobs has this worker seen? Returns an int.
@@ -852,7 +861,7 @@ module Resque
852
861
  `ps -A -o pid,comm | grep "[r]uby" | grep -v "resque-web"`.split("\n").map do |line|
853
862
  real_pid = line.split(' ')[0]
854
863
  pargs_command = `pargs -a #{real_pid} 2>/dev/null | grep [r]esque | grep -v "resque-web"`
855
- if pargs_command.split(':')[1] == " resque-#{Resque::Version}"
864
+ if pargs_command.split(':')[1] == " resque-#{Resque::VERSION}"
856
865
  real_pid
857
866
  end
858
867
  end.compact
@@ -862,7 +871,7 @@ module Resque
862
871
  # Procline is always in the format of:
863
872
  # RESQUE_PROCLINE_PREFIXresque-VERSION: STRING
864
873
  def procline(string)
865
- $0 = "#{ENV['RESQUE_PROCLINE_PREFIX']}resque-#{Resque::Version}: #{string}"
874
+ $0 = "#{ENV['RESQUE_PROCLINE_PREFIX']}resque-#{Resque::VERSION}: #{string}"
866
875
  log_with_severity :debug, $0
867
876
  end
868
877
 
data/lib/resque.rb CHANGED
@@ -23,7 +23,7 @@ require 'resque/thread_signal'
23
23
 
24
24
  require 'resque/vendor/utf8_util'
25
25
 
26
- require 'resque/railtie' if defined?(Rails)
26
+ require 'resque/railtie' if defined?(Rails::Railtie)
27
27
 
28
28
  module Resque
29
29
  include Helpers
@@ -364,8 +364,8 @@ module Resque
364
364
  data_store.queue_size(queue)
365
365
  end
366
366
 
367
- # Returns an array of items currently queued. Queue name should be
368
- # a string.
367
+ # Returns an array of items currently queued, or the item itself
368
+ # if count = 1. Queue name should be a string.
369
369
  #
370
370
  # start and count should be integer and can be used for pagination.
371
371
  # start is the item to begin, count is how many items to return.
@@ -584,9 +584,9 @@ module Resque
584
584
  def queue_sizes
585
585
  queue_names = queues
586
586
 
587
- sizes = redis.pipelined do
587
+ sizes = redis.pipelined do |piped|
588
588
  queue_names.each do |name|
589
- redis.llen("queue:#{name}")
589
+ piped.llen("queue:#{name}")
590
590
  end
591
591
  end
592
592
 
@@ -597,11 +597,11 @@ module Resque
597
597
  def sample_queues(sample_size = 1000)
598
598
  queue_names = queues
599
599
 
600
- samples = redis.pipelined do
600
+ samples = redis.pipelined do |piped|
601
601
  queue_names.each do |name|
602
602
  key = "queue:#{name}"
603
- redis.llen(key)
604
- redis.lrange(key, 0, sample_size - 1)
603
+ piped.llen(key)
604
+ piped.lrange(key, 0, sample_size - 1)
605
605
  end
606
606
  end
607
607
 
metadata CHANGED
@@ -1,16 +1,17 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: resque
3
3
  version: !ruby/object:Gem::Version
4
- version: 2.1.0
4
+ version: 2.3.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Chris Wanstrath
8
8
  - Steve Klabnik
9
9
  - Terence Lee
10
- autorequire:
10
+ - Michael Bianco
11
+ autorequire:
11
12
  bindir: bin
12
13
  cert_chain: []
13
- date: 2021-08-10 00:00:00.000000000 Z
14
+ date: 2022-08-20 00:00:00.000000000 Z
14
15
  dependencies:
15
16
  - !ruby/object:Gem::Dependency
16
17
  name: redis-namespace
@@ -26,20 +27,6 @@ dependencies:
26
27
  - - "~>"
27
28
  - !ruby/object:Gem::Version
28
29
  version: '1.6'
29
- - !ruby/object:Gem::Dependency
30
- name: vegas
31
- requirement: !ruby/object:Gem::Requirement
32
- requirements:
33
- - - "~>"
34
- - !ruby/object:Gem::Version
35
- version: 0.1.2
36
- type: :runtime
37
- prerelease: false
38
- version_requirements: !ruby/object:Gem::Requirement
39
- requirements:
40
- - - "~>"
41
- - !ruby/object:Gem::Version
42
- version: 0.1.2
43
30
  - !ruby/object:Gem::Dependency
44
31
  name: sinatra
45
32
  requirement: !ruby/object:Gem::Requirement
@@ -82,6 +69,34 @@ dependencies:
82
69
  - - "~>"
83
70
  - !ruby/object:Gem::Version
84
71
  version: '1.0'
72
+ - !ruby/object:Gem::Dependency
73
+ name: thin
74
+ requirement: !ruby/object:Gem::Requirement
75
+ requirements:
76
+ - - ">="
77
+ - !ruby/object:Gem::Version
78
+ version: '0'
79
+ type: :development
80
+ prerelease: false
81
+ version_requirements: !ruby/object:Gem::Requirement
82
+ requirements:
83
+ - - ">="
84
+ - !ruby/object:Gem::Version
85
+ version: '0'
86
+ - !ruby/object:Gem::Dependency
87
+ name: webrick
88
+ requirement: !ruby/object:Gem::Requirement
89
+ requirements:
90
+ - - ">="
91
+ - !ruby/object:Gem::Version
92
+ version: '0'
93
+ type: :development
94
+ prerelease: false
95
+ version_requirements: !ruby/object:Gem::Requirement
96
+ requirements:
97
+ - - ">="
98
+ - !ruby/object:Gem::Version
99
+ version: '0'
85
100
  description: |2
86
101
  Resque is a Redis-backed Ruby library for creating background jobs,
87
102
  placing those jobs on multiple queues, and processing them later.
@@ -162,14 +177,17 @@ files:
162
177
  - lib/resque/thread_signal.rb
163
178
  - lib/resque/vendor/utf8_util.rb
164
179
  - lib/resque/version.rb
180
+ - lib/resque/web_runner.rb
165
181
  - lib/resque/worker.rb
166
182
  - lib/tasks/redis.rake
167
183
  - lib/tasks/resque.rake
168
- homepage: http://resque.github.io/
184
+ homepage: https://github.com/resque/resque
169
185
  licenses:
170
186
  - MIT
171
- metadata: {}
172
- post_install_message:
187
+ metadata:
188
+ changelog_uri: https://github.com/resque/resque/blob/master/HISTORY.md
189
+ rubygems_mfa_required: 'true'
190
+ post_install_message:
173
191
  rdoc_options:
174
192
  - "--charset=UTF-8"
175
193
  require_paths:
@@ -185,8 +203,8 @@ required_rubygems_version: !ruby/object:Gem::Requirement
185
203
  - !ruby/object:Gem::Version
186
204
  version: '0'
187
205
  requirements: []
188
- rubygems_version: 3.1.6
189
- signing_key:
206
+ rubygems_version: 3.3.5
207
+ signing_key:
190
208
  specification_version: 4
191
209
  summary: Resque is a Redis-backed queueing system.
192
210
  test_files: []