resque 1.23.0 → 2.6.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (70) hide show
  1. checksums.yaml +7 -0
  2. data/HISTORY.md +271 -0
  3. data/README.markdown +454 -484
  4. data/Rakefile +4 -17
  5. data/bin/resque-web +10 -22
  6. data/lib/resque/data_store.rb +335 -0
  7. data/lib/resque/errors.rb +15 -1
  8. data/lib/resque/failure/airbrake.rb +32 -4
  9. data/lib/resque/failure/base.rb +16 -7
  10. data/lib/resque/failure/multiple.rb +26 -8
  11. data/lib/resque/failure/redis.rb +92 -15
  12. data/lib/resque/failure/redis_multi_queue.rb +104 -0
  13. data/lib/resque/failure.rb +62 -32
  14. data/lib/resque/helpers.rb +11 -57
  15. data/lib/resque/job.rb +79 -12
  16. data/lib/resque/log_formatters/quiet_formatter.rb +7 -0
  17. data/lib/resque/log_formatters/verbose_formatter.rb +7 -0
  18. data/lib/resque/log_formatters/very_verbose_formatter.rb +8 -0
  19. data/lib/resque/logging.rb +18 -0
  20. data/lib/resque/plugin.rb +22 -10
  21. data/lib/resque/railtie.rb +10 -0
  22. data/lib/resque/server/public/jquery-3.6.0.min.js +2 -0
  23. data/lib/resque/server/public/jquery.relatize_date.js +4 -4
  24. data/lib/resque/server/public/main.js +3 -0
  25. data/lib/resque/server/public/ranger.js +16 -8
  26. data/lib/resque/server/public/style.css +13 -8
  27. data/lib/resque/server/views/error.erb +1 -1
  28. data/lib/resque/server/views/failed.erb +27 -59
  29. data/lib/resque/server/views/failed_job.erb +50 -0
  30. data/lib/resque/server/views/failed_queues_overview.erb +24 -0
  31. data/lib/resque/server/views/job_class.erb +8 -0
  32. data/lib/resque/server/views/key_sets.erb +2 -4
  33. data/lib/resque/server/views/key_string.erb +1 -1
  34. data/lib/resque/server/views/layout.erb +7 -6
  35. data/lib/resque/server/views/next_more.erb +22 -10
  36. data/lib/resque/server/views/processing.erb +2 -0
  37. data/lib/resque/server/views/queues.erb +22 -13
  38. data/lib/resque/server/views/stats.erb +5 -5
  39. data/lib/resque/server/views/workers.erb +4 -4
  40. data/lib/resque/server/views/working.erb +10 -11
  41. data/lib/resque/server.rb +51 -108
  42. data/lib/resque/server_helper.rb +185 -0
  43. data/lib/resque/stat.rb +19 -7
  44. data/lib/resque/tasks.rb +26 -25
  45. data/lib/resque/thread_signal.rb +24 -0
  46. data/lib/resque/vendor/utf8_util.rb +2 -8
  47. data/lib/resque/version.rb +1 -1
  48. data/lib/resque/web_runner.rb +374 -0
  49. data/lib/resque/worker.rb +487 -163
  50. data/lib/resque.rb +332 -52
  51. data/lib/tasks/redis.rake +11 -11
  52. metadata +169 -149
  53. data/lib/resque/failure/hoptoad.rb +0 -33
  54. data/lib/resque/failure/thoughtbot.rb +0 -33
  55. data/lib/resque/server/public/jquery-1.3.2.min.js +0 -19
  56. data/lib/resque/server/test_helper.rb +0 -19
  57. data/lib/resque/vendor/utf8_util/utf8_util_18.rb +0 -91
  58. data/lib/resque/vendor/utf8_util/utf8_util_19.rb +0 -5
  59. data/test/airbrake_test.rb +0 -27
  60. data/test/hoptoad_test.rb +0 -26
  61. data/test/job_hooks_test.rb +0 -464
  62. data/test/job_plugins_test.rb +0 -230
  63. data/test/plugin_test.rb +0 -116
  64. data/test/redis-test-cluster.conf +0 -115
  65. data/test/redis-test.conf +0 -115
  66. data/test/resque-web_test.rb +0 -59
  67. data/test/resque_failure_redis_test.rb +0 -19
  68. data/test/resque_test.rb +0 -278
  69. data/test/test_helper.rb +0 -178
  70. data/test/worker_test.rb +0 -657
@@ -0,0 +1,185 @@
1
+ require 'rack/utils'
2
+
3
+ module Resque
4
+ module ServerHelper
5
+ include Rack::Utils
6
+ alias_method :h, :escape_html
7
+
8
+ def current_section
9
+ url_path request.path_info.sub('/','').split('/')[0].downcase
10
+ end
11
+
12
+ def current_page
13
+ url_path request.path_info.sub('/','')
14
+ end
15
+
16
+ def url_path(*path_parts)
17
+ [ url_prefix, path_prefix, path_parts ].join("/").squeeze('/')
18
+ end
19
+ alias_method :u, :url_path
20
+
21
+ def path_prefix
22
+ request.env['SCRIPT_NAME']
23
+ end
24
+
25
+ def class_if_current(path = '')
26
+ 'class="current"' if current_page[0, path.size] == path
27
+ end
28
+
29
+ def tab(name)
30
+ dname = name.to_s.downcase
31
+ path = url_path(dname)
32
+ "<li #{class_if_current(path)}><a href='#{path.gsub(" ", "_")}'>#{name}</a></li>"
33
+ end
34
+
35
+ def tabs
36
+ Resque::Server.tabs
37
+ end
38
+
39
+ def url_prefix
40
+ Resque::Server.url_prefix
41
+ end
42
+
43
+ def redis_get_size(key)
44
+ case Resque.redis.type(key)
45
+ when 'none'
46
+ 0
47
+ when 'hash'
48
+ Resque.redis.hlen(key)
49
+ when 'list'
50
+ Resque.redis.llen(key)
51
+ when 'set'
52
+ Resque.redis.scard(key)
53
+ when 'string'
54
+ Resque.redis.get(key).length
55
+ when 'zset'
56
+ Resque.redis.zcard(key)
57
+ end
58
+ end
59
+
60
+ def redis_get_value_as_array(key, start=0)
61
+ case Resque.redis.type(key)
62
+ when 'none'
63
+ []
64
+ when 'hash'
65
+ Resque.redis.hgetall(key).to_a[start..(start + 20)]
66
+ when 'list'
67
+ Resque.redis.lrange(key, start, start + 20)
68
+ when 'set'
69
+ Resque.redis.smembers(key)[start..(start + 20)]
70
+ when 'string'
71
+ [Resque.redis.get(key)]
72
+ when 'zset'
73
+ Resque.redis.zrange(key, start, start + 20)
74
+ end
75
+ end
76
+
77
+ def show_args(args)
78
+ Array(args).map do |a|
79
+ a.to_yaml
80
+ end.join("\n")
81
+ rescue
82
+ args.to_s
83
+ end
84
+
85
+ def worker_hosts
86
+ @worker_hosts ||= worker_hosts!
87
+ end
88
+
89
+ def worker_hosts!
90
+ hosts = Hash.new { [] }
91
+
92
+ Resque.workers.each do |worker|
93
+ host, _ = worker.to_s.split(':')
94
+ hosts[host] += [worker.to_s]
95
+ end
96
+
97
+ hosts
98
+ end
99
+
100
+ def partial?
101
+ @partial
102
+ end
103
+
104
+ def partial(template, local_vars = {})
105
+ @partial = true
106
+ erb(template.to_sym, {:layout => false}, local_vars)
107
+ ensure
108
+ @partial = false
109
+ end
110
+
111
+ def poll
112
+ if defined?(@polling) && @polling
113
+ text = "Last Updated: #{Time.now.strftime("%H:%M:%S")}"
114
+ else
115
+ text = "<a href='#{u(request.path_info)}.poll' rel='poll'>Live Poll!!</a>"
116
+ end
117
+ "<p class='poll'>#{text}</p>"
118
+ end
119
+
120
+ ####################
121
+ #failed.erb helpers#
122
+ ####################
123
+
124
+ def failed_date_format
125
+ "%Y/%m/%d %T %z"
126
+ end
127
+
128
+ def failed_multiple_queues?
129
+ return @multiple_failed_queues if defined?(@multiple_failed_queues)
130
+
131
+ @multiple_failed_queues = Resque::Failure.queues.size > 1 ||
132
+ (defined?(Resque::Failure::RedisMultiQueue) && Resque::Failure.backend == Resque::Failure::RedisMultiQueue)
133
+ end
134
+
135
+ def failed_size
136
+ @failed_size ||= Resque::Failure.count(params[:queue], params[:class])
137
+ end
138
+
139
+ def failed_per_page
140
+ @failed_per_page = if params[:class]
141
+ failed_size
142
+ else
143
+ 20
144
+ end
145
+ end
146
+
147
+ def failed_start_at
148
+ params[:start].to_i
149
+ end
150
+
151
+ def failed_end_at
152
+ if failed_start_at + failed_per_page > failed_size
153
+ failed_size
154
+ else
155
+ failed_start_at + failed_per_page - 1
156
+ end
157
+ end
158
+
159
+ def failed_order
160
+ params[:order] || 'desc'
161
+ end
162
+
163
+ def failed_class_counts(queue = params[:queue])
164
+ classes = Hash.new(0)
165
+ Resque::Failure.each(0, Resque::Failure.count(queue), queue) do |_, item|
166
+ class_name = item['payload']['class'] if item['payload']
167
+ class_name ||= "nil"
168
+ classes[class_name] += 1
169
+ end
170
+ classes
171
+ end
172
+
173
+ def page_entries_info(start, stop, size, name = nil)
174
+ if size == 0
175
+ name ? "No #{name}s" : '<b>0</b>'
176
+ elsif size == 1
177
+ 'Showing <b>1</b>' + (name ? " #{name}" : '')
178
+ elsif size > failed_per_page
179
+ "Showing #{start}-#{stop} of <b>#{size}</b>" + (name ? " #{name}s" : '')
180
+ else
181
+ "Showing #{start} to <b>#{size - 1}</b>" + (name ? " #{name}s" : '')
182
+ end
183
+ end
184
+ end
185
+ end
data/lib/resque/stat.rb CHANGED
@@ -7,11 +7,23 @@ module Resque
7
7
  # Kill a stat: Stat.clear(name)
8
8
  module Stat
9
9
  extend self
10
- extend Helpers
10
+
11
+ def redis
12
+ warn '[Resque] [Deprecation] Resque::Stat #redis method is deprecated (please use #data_strore)'
13
+ data_store
14
+ end
15
+
16
+ def data_store
17
+ @data_store ||= Resque.redis
18
+ end
19
+
20
+ def data_store=(data_store)
21
+ @data_store = data_store
22
+ end
11
23
 
12
24
  # Returns the int value of a stat, given a string stat name.
13
25
  def get(stat)
14
- redis.get("stat:#{stat}").to_i
26
+ data_store.stat(stat)
15
27
  end
16
28
 
17
29
  # Alias of `get`
@@ -23,8 +35,8 @@ module Resque
23
35
  #
24
36
  # Can optionally accept a second int parameter. The stat is then
25
37
  # incremented by that amount.
26
- def incr(stat, by = 1)
27
- redis.incrby("stat:#{stat}", by)
38
+ def incr(stat, by = 1, **opts)
39
+ data_store.increment_stat(stat, by, **opts)
28
40
  end
29
41
 
30
42
  # Increments a stat by one.
@@ -37,7 +49,7 @@ module Resque
37
49
  # Can optionally accept a second int parameter. The stat is then
38
50
  # decremented by that amount.
39
51
  def decr(stat, by = 1)
40
- redis.decrby("stat:#{stat}", by)
52
+ data_store.decrement_stat(stat,by)
41
53
  end
42
54
 
43
55
  # Decrements a stat by one.
@@ -46,8 +58,8 @@ module Resque
46
58
  end
47
59
 
48
60
  # Removes a stat from Redis, effectively setting it to 0.
49
- def clear(stat)
50
- redis.del("stat:#{stat}")
61
+ def clear(stat, **opts)
62
+ data_store.clear_stat(stat, **opts)
51
63
  end
52
64
  end
53
65
  end
data/lib/resque/tasks.rb CHANGED
@@ -1,6 +1,7 @@
1
1
  # require 'resque/tasks'
2
2
  # will give you the resque tasks
3
3
 
4
+
4
5
  namespace :resque do
5
6
  task :setup
6
7
 
@@ -8,31 +9,14 @@ namespace :resque do
8
9
  task :work => [ :preload, :setup ] do
9
10
  require 'resque'
10
11
 
11
- queues = (ENV['QUEUES'] || ENV['QUEUE']).to_s.split(',')
12
-
13
12
  begin
14
- worker = Resque::Worker.new(*queues)
15
- worker.verbose = ENV['LOGGING'] || ENV['VERBOSE']
16
- worker.very_verbose = ENV['VVERBOSE']
17
- worker.term_timeout = ENV['RESQUE_TERM_TIMEOUT'] || 4.0
18
- worker.term_child = ENV['TERM_CHILD']
13
+ worker = Resque::Worker.new
19
14
  rescue Resque::NoQueueError
20
15
  abort "set QUEUE env var, e.g. $ QUEUE=critical,high rake resque:work"
21
16
  end
22
17
 
23
- if ENV['BACKGROUND']
24
- unless Process.respond_to?('daemon')
25
- abort "env var BACKGROUND is set, which requires ruby >= 1.9"
26
- end
27
- Process.daemon(true)
28
- end
29
-
30
- if ENV['PIDFILE']
31
- File.open(ENV['PIDFILE'], 'w') { |f| f << worker.pid }
32
- end
33
-
18
+ worker.prepare
34
19
  worker.log "Starting worker #{worker}"
35
-
36
20
  worker.work(ENV['INTERVAL'] || 5) # interval, will block
37
21
  end
38
22
 
@@ -40,6 +24,10 @@ namespace :resque do
40
24
  task :workers do
41
25
  threads = []
42
26
 
27
+ if ENV['COUNT'].to_i < 1
28
+ abort "set COUNT env var, e.g. $ COUNT=2 rake resque:workers"
29
+ end
30
+
43
31
  ENV['COUNT'].to_i.times do
44
32
  threads << Thread.new do
45
33
  system "rake resque:work"
@@ -52,12 +40,25 @@ namespace :resque do
52
40
  # Preload app files if this is Rails
53
41
  task :preload => :setup do
54
42
  if defined?(Rails) && Rails.respond_to?(:application)
55
- # Rails 3
56
- Rails.application.eager_load!
57
- elsif defined?(Rails::Initializer)
58
- # Rails 2.3
59
- $rails_rake_task = false
60
- Rails::Initializer.run :load_application_classes
43
+ if Rails.application.config.eager_load
44
+ ActiveSupport.run_load_hooks(:before_eager_load, Rails.application)
45
+ Rails.application.config.eager_load_namespaces.each(&:eager_load!)
46
+ end
47
+ end
48
+ end
49
+
50
+ namespace :failures do
51
+ desc "Sort the 'failed' queue for the redis_multi_queue failure backend"
52
+ task :sort do
53
+ require 'resque'
54
+ require 'resque/failure/redis'
55
+
56
+ warn "Sorting #{Resque::Failure.count} failures..."
57
+ Resque::Failure.each(0, Resque::Failure.count) do |_, failure|
58
+ data = Resque.encode(failure)
59
+ Resque.redis.rpush(Resque::Failure.failure_queue_name(failure['queue']), data)
60
+ end
61
+ warn "done!"
61
62
  end
62
63
  end
63
64
  end
@@ -0,0 +1,24 @@
1
+ class Resque::ThreadSignal
2
+ def initialize
3
+ @mutex = Mutex.new
4
+ @signaled = false
5
+ @received = ConditionVariable.new
6
+ end
7
+
8
+ def signal
9
+ @mutex.synchronize do
10
+ @signaled = true
11
+ @received.signal
12
+ end
13
+ end
14
+
15
+ def wait_for_signal(timeout)
16
+ @mutex.synchronize do
17
+ unless @signaled
18
+ @received.wait(@mutex, timeout)
19
+ end
20
+
21
+ @signaled
22
+ end
23
+ end
24
+ end
@@ -7,7 +7,8 @@ module UTF8Util
7
7
  #
8
8
  # Returns self as valid UTF-8.
9
9
  def self.clean!(str)
10
- raise NotImplementedError
10
+ return str if str.encoding.to_s == "UTF-8"
11
+ str.force_encoding("binary").encode("UTF-8", :invalid => :replace, :undef => :replace, :replace => REPLACEMENT_CHAR)
11
12
  end
12
13
 
13
14
  # Replace invalid UTF-8 character sequences with a replacement character
@@ -16,11 +17,4 @@ module UTF8Util
16
17
  def self.clean(str)
17
18
  clean!(str.dup)
18
19
  end
19
-
20
- end
21
-
22
- if RUBY_VERSION <= '1.9'
23
- require 'resque/vendor/utf8_util/utf8_util_18'
24
- else
25
- require 'resque/vendor/utf8_util/utf8_util_19'
26
20
  end
@@ -1,3 +1,3 @@
1
1
  module Resque
2
- Version = VERSION = '1.23.0'
2
+ VERSION = '2.6.0'
3
3
  end