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 +4 -4
- data/HISTORY.md +10 -4
- data/README.markdown +67 -46
- data/bin/resque-web +10 -26
- data/lib/resque/server/views/error.erb +1 -1
- data/lib/resque/server/views/failed.erb +3 -3
- data/lib/resque/server/views/job_class.erb +3 -1
- data/lib/resque/server/views/key_string.erb +1 -1
- data/lib/resque/server/views/queues.erb +1 -1
- data/lib/resque/server.rb +1 -1
- data/lib/resque/version.rb +1 -1
- data/lib/resque/web_runner.rb +372 -0
- data/lib/resque/worker.rb +13 -4
- data/lib/resque.rb +2 -2
- metadata +31 -16
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 42bdd72240bcf206aa094dc525eca1747b51f4456ed28ae562ceccb10c4f313f
|
4
|
+
data.tar.gz: 44297a31bb61f835b6acbba5195f77826b1d476611169f47ebfa07fbae7df1f3
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
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
|
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
|
-
* [
|
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
|
-
|
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
|
-
|
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
|
83
|
-
|
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
|
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
|
350
|
+
#### Rails
|
335
351
|
|
336
|
-
You can also mount Resque on a subpath in your existing Rails
|
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
|
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
|
-
|
14
|
-
|
15
|
-
|
16
|
-
|
17
|
-
|
18
|
-
|
19
|
-
|
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
|
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 %>
|
@@ -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
|
data/lib/resque/version.rb
CHANGED
@@ -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 =
|
184
|
-
|
185
|
-
|
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
|
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.
|
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:
|
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
|