resque 2.2.0 → 2.2.1

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: b6f395169f58a51122135f8cbf6495ca914a472a94038277d6d022ac1387459a
4
- data.tar.gz: ba5b39c8521b48b0f882c2290d105dc8b2db24308cf08d14d630841ed45585ed
3
+ metadata.gz: 42bdd72240bcf206aa094dc525eca1747b51f4456ed28ae562ceccb10c4f313f
4
+ data.tar.gz: 44297a31bb61f835b6acbba5195f77826b1d476611169f47ebfa07fbae7df1f3
5
5
  SHA512:
6
- metadata.gz: f03920bbf92a185a5d6c062d9d10dbc17c8b3090ed9bbd04138e85b3a40f0cefa377c21f22a343c3c9b64cd3502998efa5b42f5a6f6c7f314712ceb54bc9671e
7
- data.tar.gz: af2ac4eb41bd9dc30951fd1122deada0b445000736ff08a020313e4337655c61e79af888e7b21e3c6c1cacab2e3bc5cc1f4d28577d2e2e02e62c5f8bf3452a18
6
+ metadata.gz: 76d9e121e971b063d1ca1b6207c9a867cc3c97731197167fc2e4dacf8ff76d92857a5bf3a7d61f22f4d6a8eb2c216c519b5ba4ce7e0fbf728c386e0e96f073a3
7
+ data.tar.gz: b36861b666b72c962b12c35fb8214931a49e422886b03e29ee718dad831114a4ff475a36153997787c01c6d451ca202d34c1d8b563b9a657f5a2447e5e24b2b3
data/HISTORY.md CHANGED
@@ -2,13 +2,19 @@
2
2
 
3
3
  ### Fixed
4
4
 
5
- *
6
- *
5
+ ### Added
6
+
7
+ ## 2.2.1
8
+
9
+ ### Fixed
10
+
11
+ * Escape HTML from the params to avoid XSS (#1790)
12
+ * Remove vegas as a dependency (#1780)
7
13
 
8
14
  ### Added
9
15
 
10
- *
11
- *
16
+ * Add support for specifying queues that workers should ignore when using globs
17
+ * Allow plugins to have spaces in their name (#1718)
12
18
 
13
19
  ## 2.2.0
14
20
 
data/README.markdown CHANGED
@@ -4,9 +4,7 @@ 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
- Resque (pronounced like "rescue") is a Redis-backed library for creating
8
- background jobs, placing those jobs on multiple queues, and processing
9
- them later.
7
+ Resque is a Redis-backed queueing system.
10
8
 
11
9
  ---------
12
10
  ### Note on the future of this repo
@@ -17,39 +15,12 @@ on just that topic, so please feel free to join in. We'd love to hear your thoug
17
15
  and/or have people volunteer to be a part of the project!
18
16
 
19
17
  ---------
20
- Background jobs can be any Ruby class or module that responds to
21
- `perform`. Your existing classes can easily be converted to background
22
- jobs or you can create new classes specifically to do work. Or, you
23
- can do both.
24
-
25
- Resque is heavily inspired by DelayedJob (which rocks) and comprises
26
- three parts:
27
-
28
- 1. A Ruby library for creating, querying, and processing jobs
29
- 2. A Rake task for starting a worker which processes jobs
30
- 3. A Sinatra app for monitoring queues, jobs, and workers.
31
-
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.
36
-
37
- Resque queues are persistent; support constant time, atomic push and
38
- pop (thanks to Redis); provide visibility into their contents; and
39
- store jobs as simple JSON packages.
40
-
41
- The Resque frontend tells you what workers are doing, what workers are
42
- not doing, what queues you're using, what's in those queues, provides
43
- general usage stats, and helps you track failures.
44
-
45
- Resque now supports Ruby 2.3.0 and above.
46
- We will also only be supporting Redis 3.0 and above going forward.
47
-
48
18
 
49
19
  Table of Contents
50
20
  -----------------
51
21
 
52
- * [Overview](#overview)
22
+ * [Introduction](#introduction)
23
+ * [Example](#example)
53
24
  * [Installation](#installation)
54
25
  * [Running Workers](#running-workers)
55
26
  * [The Front End](#the-front-end)
@@ -74,13 +45,46 @@ Table of Contents
74
45
  * [Meta](#meta)
75
46
  * [Author](#author)
76
47
 
77
- Overview
78
- --------
48
+ Introduction
49
+ ------------
50
+
51
+ Resque (pronounced like "rescue") is a Redis-backed library for creating
52
+ background jobs, placing those jobs on multiple queues, and processing
53
+ them later.
54
+
55
+ For the backstory, philosophy, and history of Resque's beginnings, please see [the blog post](http://github.com/blog/542-introducing-resque) (2009).
79
56
 
80
- For the backstory, philosophy, and history of Resque's beginnings, please see [the blog post](http://github.com/blog/542-introducing-resque).
57
+ Background jobs can be any Ruby class or module that responds to
58
+ `perform`. Your existing classes can easily be converted to background
59
+ jobs or you can create new classes specifically to do work. Or, you
60
+ can do both.
81
61
 
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.
62
+ Resque is heavily inspired by DelayedJob (which rocks) and comprises
63
+ three parts:
64
+
65
+ 1. A Ruby library for creating, querying, and processing jobs
66
+ 2. A Rake task for starting a worker which processes jobs
67
+ 3. A Sinatra app for monitoring queues, jobs, and workers.
68
+
69
+ Resque workers can be given multiple queues (a "queue list"),
70
+ distributed between multiple machines,
71
+ run anywhere with network access to the Redis server,
72
+ support priorities, are resilient to memory bloat / "leaks,"
73
+ tell you what they're doing, and expect failure.
74
+
75
+ Resque queues are persistent; support constant time, atomic push and
76
+ pop (thanks to Redis); provide visibility into their contents; and
77
+ store jobs as simple JSON packages.
78
+
79
+ The Resque frontend tells you what workers are doing, what workers are
80
+ not doing, what queues you're using, what's in those queues, provides
81
+ general usage stats, and helps you track failures.
82
+
83
+ Resque now supports Ruby 2.3.0 and above.
84
+ We will also only be supporting Redis 3.0 and above going forward.
85
+
86
+ Example
87
+ -------
84
88
 
85
89
  Resque jobs are Ruby classes (or modules) which respond to the
86
90
  `perform` method. Here's an example:
@@ -140,10 +144,6 @@ This starts one Resque worker and tells it to work off the
140
144
  find any more, at which point it will sleep for a small period and
141
145
  repeatedly poll the queue for more jobs.
142
146
 
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
147
  Installation
148
148
  ------------
149
149
 
@@ -165,7 +165,7 @@ require 'resque/tasks'
165
165
  require 'your/app' # Include this line if you want your workers to have access to your application
166
166
  ```
167
167
 
168
- #### Rails 3+
168
+ #### Rails
169
169
 
170
170
  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
171
 
@@ -253,6 +253,22 @@ Or, prioritize some queues above `*`:
253
253
 
254
254
  # QUEUE=critical,* rake resque:work
255
255
 
256
+ #### Running All Queues Except for Some
257
+
258
+ If you want your workers to work off of all queues except for some,
259
+ you can use negation:
260
+
261
+ $ QUEUE=*,!low rake resque:work
262
+
263
+ Negated globs also work. The following will instruct workers to work
264
+ off of all queues except those beginning with `file_`:
265
+
266
+ $ QUEUE=*,!file_* rake resque:work
267
+
268
+ Note that the order in which negated queues are specified does not
269
+ matter, so `QUEUE=*,!file_*` and `QUEUE=!file_*,*` will have the same
270
+ effect.
271
+
256
272
  #### Process IDs (PIDs)
257
273
 
258
274
  There are scenarios where it's helpful to record the PID of a resque
@@ -331,9 +347,9 @@ run Rack::URLMap.new \
331
347
  Check `examples/demo/config.ru` for a functional example (including
332
348
  HTTP basic auth).
333
349
 
334
- #### Rails 3+
350
+ #### Rails
335
351
 
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`:
352
+ 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
353
 
338
354
  ``` ruby
339
355
  mount Resque::Server.new, :at => "/resque"
@@ -687,6 +703,12 @@ complicated.
687
703
 
688
704
  Workers instead handle their own state.
689
705
 
706
+ #### `at_exit` Callbacks
707
+
708
+ 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.
709
+
710
+ You can alter this behavior by setting the `RUN_AT_EXIT_HOOKS` environment variable.
711
+
690
712
  #### Parents and Children
691
713
 
692
714
  Here's a parent / child pair doing some work:
@@ -770,7 +792,7 @@ send patches for any tweaks or improvements you can make to it.
770
792
 
771
793
  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
794
 
773
- ##### Rails 3.x
795
+ ##### Rails
774
796
  In your `perform` method, add the following line:
775
797
 
776
798
  ``` ruby
@@ -861,7 +883,6 @@ Meta
861
883
  * Home: <http://github.com/resque/resque>
862
884
  * Docs: <http://rubydoc.info/gems/resque>
863
885
  * Bugs: <http://github.com/resque/resque/issues>
864
- * Chat: <irc://irc.freenode.net/resque>
865
886
  * Gems: <https://rubygems.org/gems/resque>
866
887
 
867
888
  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)
@@ -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,12 +1,12 @@
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
11
 
12
12
  <% unless params[:queue] %>
@@ -15,7 +15,7 @@
15
15
  </form>
16
16
  <% end %>
17
17
  <form method="POST" action="<%= u "failed#{'/' + params[:queue] if params[:queue]}/requeue/all" %>">
18
- <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" />
19
19
  </form>
20
20
  <% end %>
21
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>
@@ -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
@@ -1,3 +1,3 @@
1
1
  module Resque
2
- VERSION = '2.2.0'
2
+ VERSION = '2.2.1'
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 (namespace = options[:redis_namespace])
89
+ runner.logger.info "Using Redis namespace '#{namespace}'"
90
+ Resque.redis.namespace = namespace
91
+ end
92
+ if (redis_conf = options[:redis_conf])
93
+ logger.info "Using Redis connection '#{redis_conf}'"
94
+ Resque.redis = redis_conf
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
 
data/lib/resque.rb CHANGED
@@ -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.
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: resque
3
3
  version: !ruby/object:Gem::Version
4
- version: 2.2.0
4
+ version: 2.2.1
5
5
  platform: ruby
6
6
  authors:
7
7
  - Chris Wanstrath
@@ -11,7 +11,7 @@ authors:
11
11
  autorequire:
12
12
  bindir: bin
13
13
  cert_chain: []
14
- date: 2021-11-04 00:00:00.000000000 Z
14
+ date: 2022-03-27 00:00:00.000000000 Z
15
15
  dependencies:
16
16
  - !ruby/object:Gem::Dependency
17
17
  name: redis-namespace
@@ -27,20 +27,6 @@ dependencies:
27
27
  - - "~>"
28
28
  - !ruby/object:Gem::Version
29
29
  version: '1.6'
30
- - !ruby/object:Gem::Dependency
31
- name: vegas
32
- requirement: !ruby/object:Gem::Requirement
33
- requirements:
34
- - - "~>"
35
- - !ruby/object:Gem::Version
36
- version: 0.1.2
37
- type: :runtime
38
- prerelease: false
39
- version_requirements: !ruby/object:Gem::Requirement
40
- requirements:
41
- - - "~>"
42
- - !ruby/object:Gem::Version
43
- version: 0.1.2
44
30
  - !ruby/object:Gem::Dependency
45
31
  name: sinatra
46
32
  requirement: !ruby/object:Gem::Requirement
@@ -83,6 +69,34 @@ dependencies:
83
69
  - - "~>"
84
70
  - !ruby/object:Gem::Version
85
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'
86
100
  description: |2
87
101
  Resque is a Redis-backed Ruby library for creating background jobs,
88
102
  placing those jobs on multiple queues, and processing them later.
@@ -163,6 +177,7 @@ files:
163
177
  - lib/resque/thread_signal.rb
164
178
  - lib/resque/vendor/utf8_util.rb
165
179
  - lib/resque/version.rb
180
+ - lib/resque/web_runner.rb
166
181
  - lib/resque/worker.rb
167
182
  - lib/tasks/redis.rake
168
183
  - lib/tasks/resque.rake