resque-scheduler 4.4.0 → 4.11.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.
@@ -8,13 +8,18 @@ module Resque
8
8
  yield self
9
9
  end
10
10
 
11
+ attr_writer :environment
12
+ def environment
13
+ @environment ||= ENV
14
+ end
15
+
11
16
  # Used in `#load_schedule_job`
12
17
  attr_writer :env
13
18
 
14
19
  def env
15
20
  return @env if @env
16
21
  @env ||= Rails.env if defined?(Rails) && Rails.respond_to?(:env)
17
- @env ||= ENV['RAILS_ENV']
22
+ @env ||= environment['RAILS_ENV']
18
23
  @env
19
24
  end
20
25
 
@@ -22,42 +27,48 @@ module Resque
22
27
  attr_writer :verbose
23
28
 
24
29
  def verbose
25
- @verbose ||= !!ENV['VERBOSE']
30
+ @verbose ||= to_bool(environment['VERBOSE'])
26
31
  end
27
32
 
28
33
  # If set, produces no output
29
34
  attr_writer :quiet
30
35
 
31
36
  def quiet
32
- @quiet ||= !!ENV['QUIET']
37
+ @quiet ||= to_bool(environment['QUIET'])
33
38
  end
34
39
 
35
40
  # If set, will write messages to the file
36
41
  attr_writer :logfile
37
42
 
38
43
  def logfile
39
- @logfile ||= ENV['LOGFILE']
44
+ @logfile ||= environment['LOGFILE']
40
45
  end
41
46
 
42
- # Sets whether to log in 'text' or 'json'
47
+ # Sets whether to log in 'text', 'json' or 'logfmt'
43
48
  attr_writer :logformat
44
49
 
45
50
  def logformat
46
- @logformat ||= ENV['LOGFORMAT']
51
+ @logformat ||= environment['LOGFORMAT']
47
52
  end
48
53
 
49
54
  # If set, will try to update the schedule in the loop
50
55
  attr_writer :dynamic
51
56
 
52
57
  def dynamic
53
- @dynamic ||= !!ENV['DYNAMIC_SCHEDULE']
58
+ @dynamic ||= to_bool(environment['DYNAMIC_SCHEDULE'])
54
59
  end
55
60
 
56
61
  # If set, will append the app name to procline
57
62
  attr_writer :app_name
58
63
 
59
64
  def app_name
60
- @app_name ||= ENV['APP_NAME']
65
+ @app_name ||= environment['APP_NAME']
66
+ end
67
+
68
+ def delayed_requeue_batch_size
69
+ @delayed_requeue_batch_size ||= \
70
+ ENV['DELAYED_REQUEUE_BATCH_SIZE'].to_i if environment['DELAYED_REQUEUE_BATCH_SIZE']
71
+ @delayed_requeue_batch_size ||= 100
61
72
  end
62
73
 
63
74
  # Amount of time in seconds to sleep between polls of the delayed
@@ -66,7 +77,32 @@ module Resque
66
77
 
67
78
  def poll_sleep_amount
68
79
  @poll_sleep_amount ||=
69
- Float(ENV.fetch('RESQUE_SCHEDULER_INTERVAL', '5'))
80
+ Float(environment.fetch('RESQUE_SCHEDULER_INTERVAL', '5'))
81
+ end
82
+
83
+ # Sets timeout for Resque::Scheduler::Lock::Base
84
+ attr_writer :lock_timeout
85
+
86
+ def lock_timeout
87
+ @lock_timeout ||= environment.fetch('LOCK_TIMEOUT', 60 * 3).to_i
88
+ end
89
+
90
+ private
91
+
92
+ # Copied from https://github.com/rails/rails/blob/main/activemodel/lib/active_model/type/boolean.rb#L17
93
+ TRUE_VALUES = [
94
+ true, 1,
95
+ '1', :'1',
96
+ 't', :t,
97
+ 'T', :T,
98
+ 'true', :true,
99
+ 'TRUE', :TRUE,
100
+ 'on', :on,
101
+ 'ON', :ON
102
+ ].to_set.freeze
103
+
104
+ def to_bool(value)
105
+ TRUE_VALUES.include?(value)
70
106
  end
71
107
  end
72
108
  end
@@ -22,24 +22,22 @@ module Resque
22
22
  # timestamp has passed. It respects Resque.inline option, by
23
23
  # creating the job right away instead of adding to the queue.
24
24
  def enqueue_at_with_queue(queue, timestamp, klass, *args)
25
- return false unless plugin.run_before_schedule_hooks(klass, *args)
26
-
27
- if Resque.inline? || timestamp.to_i < Time.now.to_i
28
- # Just create the job and let resque perform it right away with
29
- # inline. If the class is a custom job class, call self#scheduled
30
- # on it. This allows you to do things like
31
- # Resque.enqueue_at(timestamp, CustomJobClass, :opt1 => val1).
32
- # Otherwise, pass off to Resque.
33
- if klass.respond_to?(:scheduled)
34
- klass.scheduled(queue, klass.to_s, *args)
25
+ plugin.process_schedule_hooks(klass, *args) do
26
+ if Resque.inline? || timestamp.to_i <= Time.now.to_i
27
+ # Just create the job and let resque perform it right away with
28
+ # inline. If the class is a custom job class, call self#scheduled
29
+ # on it. This allows you to do things like
30
+ # Resque.enqueue_at(timestamp, CustomJobClass, :opt1 => val1).
31
+ # Otherwise, pass off to Resque.
32
+ if klass.respond_to?(:scheduled)
33
+ klass.scheduled(queue, klass.to_s, *args)
34
+ else
35
+ Resque.enqueue_to(queue, klass, *args)
36
+ end
35
37
  else
36
- Resque::Job.create(queue, klass, *args)
38
+ delayed_push(timestamp, job_to_hash_with_queue(queue, klass, args))
37
39
  end
38
- else
39
- delayed_push(timestamp, job_to_hash_with_queue(queue, klass, args))
40
40
  end
41
-
42
- plugin.run_after_schedule_hooks(klass, *args)
43
41
  end
44
42
 
45
43
  # Identical to enqueue_at but takes number_of_seconds_from_now
@@ -63,16 +61,34 @@ module Resque
63
61
  klass, *args)
64
62
  end
65
63
 
64
+ # Update the delayed timestamp of any matching delayed jobs or enqueue a
65
+ # new job if no matching jobs are found. Returns the number of delayed or
66
+ # enqueued jobs.
67
+ def delay_or_enqueue_at(timestamp, klass, *args)
68
+ count = remove_delayed(klass, *args)
69
+ count = 1 if count == 0
70
+
71
+ count.times do
72
+ enqueue_at(timestamp, klass, *args)
73
+ end
74
+ end
75
+
76
+ # Identical to +delay_or_enqueue_at+, except it takes
77
+ # number_of_seconds_from_now instead of a timestamp
78
+ def delay_or_enqueue_in(number_of_seconds_from_now, klass, *args)
79
+ delay_or_enqueue_at(Time.now + number_of_seconds_from_now, klass, *args)
80
+ end
81
+
66
82
  # Used internally to stuff the item into the schedule sorted list.
67
- # +timestamp+ can be either in seconds or a datetime object Insertion
68
- # if O(log(n)). Returns true if it's the first job to be scheduled at
69
- # that time, else false
83
+ # +timestamp+ can be either in seconds or a datetime object. The
84
+ # insertion time complexity is O(log(n)). Returns true if it's
85
+ # the first job to be scheduled at that time, else false.
70
86
  def delayed_push(timestamp, item)
71
87
  # First add this item to the list for this timestamp
72
88
  redis.rpush("delayed:#{timestamp.to_i}", encode(item))
73
89
 
74
90
  # Store the timestamps at with this item occurs
75
- redis.sadd("timestamps:#{encode(item)}", "delayed:#{timestamp.to_i}")
91
+ redis.sadd("timestamps:#{encode(item)}", ["delayed:#{timestamp.to_i}"])
76
92
 
77
93
  # Now, add this timestamp to the zsets. The score and the value are
78
94
  # the same since we'll be querying by timestamp, and we don't have
@@ -88,6 +104,7 @@ module Resque
88
104
  end
89
105
 
90
106
  # Returns the size of the delayed queue schedule
107
+ # this does not represent the number of items in the queue to be scheduled
91
108
  def delayed_queue_schedule_size
92
109
  redis.zcard :delayed_queue_schedule
93
110
  end
@@ -121,7 +138,7 @@ module Resque
121
138
  key = "delayed:#{timestamp.to_i}"
122
139
 
123
140
  encoded_item = redis.lpop(key)
124
- redis.srem("timestamps:#{encoded_item}", key)
141
+ redis.srem("timestamps:#{encoded_item}", [key])
125
142
  item = decode(encoded_item)
126
143
 
127
144
  # If the list is empty, remove it.
@@ -134,10 +151,7 @@ module Resque
134
151
  Array(redis.zrange(:delayed_queue_schedule, 0, -1)).each do |item|
135
152
  key = "delayed:#{item}"
136
153
  items = redis.lrange(key, 0, -1)
137
- redis.pipelined do
138
- items.each { |ts_item| redis.del("timestamps:#{ts_item}") }
139
- end
140
- redis.del key
154
+ redis.del(key, items.map { |ts_item| "timestamps:#{ts_item}" })
141
155
  end
142
156
 
143
157
  redis.del :delayed_queue_schedule
@@ -149,6 +163,11 @@ module Resque
149
163
  remove_delayed_job(search)
150
164
  end
151
165
 
166
+ def remove_delayed_in_queue(klass, queue, *args)
167
+ search = encode(job_to_hash_with_queue(queue, klass, args))
168
+ remove_delayed_job(search)
169
+ end
170
+
152
171
  # Given an encoded item, enqueue it now
153
172
  def enqueue_delayed(klass, *args)
154
173
  hash = job_to_hash(klass, args)
@@ -157,6 +176,13 @@ module Resque
157
176
  end
158
177
  end
159
178
 
179
+ def enqueue_delayed_with_queue(klass, queue, *args)
180
+ hash = job_to_hash_with_queue(queue, klass, args)
181
+ remove_delayed_in_queue(klass, queue, *args).times do
182
+ Resque::Scheduler.enqueue_from_config(hash)
183
+ end
184
+ end
185
+
160
186
  # Given a block, remove jobs that return true from a block
161
187
  #
162
188
  # This allows for removal of delayed jobs that have arguments matching
@@ -181,7 +207,15 @@ module Resque
181
207
  found_jobs.reduce(0) do |sum, encoded_job|
182
208
  decoded_job = decode(encoded_job)
183
209
  klass = Util.constantize(decoded_job['class'])
184
- sum + enqueue_delayed(klass, *decoded_job['args'])
210
+ queue = decoded_job['queue']
211
+
212
+ if queue
213
+ jobs_queued = enqueue_delayed_with_queue(klass, queue, *decoded_job['args'])
214
+ else
215
+ jobs_queued = enqueue_delayed(klass, *decoded_job['args'])
216
+ end
217
+
218
+ jobs_queued + sum
185
219
  end
186
220
  end
187
221
 
@@ -196,9 +230,9 @@ module Resque
196
230
 
197
231
  # Beyond 100 there's almost no improvement in speed
198
232
  found = timestamps.each_slice(100).map do |ts_group|
199
- jobs = redis.pipelined do |r|
233
+ jobs = redis.pipelined do |pipeline|
200
234
  ts_group.each do |ts|
201
- r.lrange("delayed:#{ts}", 0, -1)
235
+ pipeline.lrange("delayed:#{ts}", 0, -1)
202
236
  end
203
237
  end
204
238
 
@@ -221,7 +255,7 @@ module Resque
221
255
  key = "delayed:#{timestamp.to_i}"
222
256
  encoded_job = encode(job_to_hash(klass, args))
223
257
 
224
- redis.srem("timestamps:#{encoded_job}", key)
258
+ redis.srem("timestamps:#{encoded_job}", [key])
225
259
  count = redis.lrem(key, 0, encoded_job)
226
260
  clean_up_timestamp(key, timestamp)
227
261
 
@@ -261,6 +295,22 @@ module Resque
261
295
  redis.hget('delayed:last_enqueued_at', job_name)
262
296
  end
263
297
 
298
+ def clean_up_timestamp(key, timestamp)
299
+ # Use a watch here to ensure nobody adds jobs to this delayed
300
+ # queue while we're removing it.
301
+ redis.watch(key) do
302
+ if redis.llen(key).to_i == 0
303
+ # If the list is empty, remove it.
304
+ redis.multi do |transaction|
305
+ transaction.del(key)
306
+ transaction.zrem(:delayed_queue_schedule, timestamp.to_i)
307
+ end
308
+ else
309
+ redis.redis.unwatch
310
+ end
311
+ end
312
+ end
313
+
264
314
  private
265
315
 
266
316
  def job_to_hash(klass, args)
@@ -271,38 +321,27 @@ module Resque
271
321
  { class: klass.to_s, args: args, queue: queue }
272
322
  end
273
323
 
324
+ # Removes a job from the queue, but not modify the timestamp schedule. This method
325
+ # will not effect the output of `delayed_queue_schedule_size`
274
326
  def remove_delayed_job(encoded_job)
275
327
  return 0 if Resque.inline?
276
328
 
277
329
  timestamps = redis.smembers("timestamps:#{encoded_job}")
278
330
 
279
- replies = redis.pipelined do
331
+ replies = redis.pipelined do |pipeline|
280
332
  timestamps.each do |key|
281
- redis.lrem(key, 0, encoded_job)
282
- redis.srem("timestamps:#{encoded_job}", key)
333
+ pipeline.lrem(key, 0, encoded_job)
334
+ pipeline.srem("timestamps:#{encoded_job}", [key])
283
335
  end
284
336
  end
285
337
 
338
+ # timestamp key is not removed from the schedule, this is done later
339
+ # by the scheduler loop
340
+
286
341
  return 0 if replies.nil? || replies.empty?
287
342
  replies.each_slice(2).map(&:first).inject(:+)
288
343
  end
289
344
 
290
- def clean_up_timestamp(key, timestamp)
291
- # Use a watch here to ensure nobody adds jobs to this delayed
292
- # queue while we're removing it.
293
- redis.watch(key) do
294
- if redis.llen(key).to_i == 0
295
- # If the list is empty, remove it.
296
- redis.multi do
297
- redis.del(key)
298
- redis.zrem(:delayed_queue_schedule, timestamp.to_i)
299
- end
300
- else
301
- redis.redis.unwatch
302
- end
303
- end
304
- end
305
-
306
345
  def search_first_delayed_timestamp_in_range(start_at, stop_at)
307
346
  start_at = start_at.nil? ? '-inf' : start_at.to_i
308
347
  stop_at = stop_at.nil? ? '+inf' : stop_at.to_i
@@ -38,12 +38,8 @@ module Resque
38
38
  true
39
39
  end
40
40
 
41
- unless Process.respond_to?('daemon')
42
- abort 'background option is set, which requires ruby >= 1.9'
43
- end
44
-
45
41
  Process.daemon(true, !Resque::Scheduler.quiet)
46
- Resque.redis._client.reconnect
42
+ Resque.redis.reconnect
47
43
  end
48
44
 
49
45
  def setup_pid_file
@@ -58,6 +54,7 @@ module Resque
58
54
  at_exit { cleanup_pid_file }
59
55
  end
60
56
 
57
+ # rubocop:disable Metrics/AbcSize
61
58
  def setup_scheduler_configuration
62
59
  Resque::Scheduler.configure do |c|
63
60
  c.app_name = options[:app_name] if options.key?(:app_name)
@@ -70,6 +67,8 @@ module Resque
70
67
 
71
68
  c.logformat = options[:logformat] if options.key?(:logformat)
72
69
 
70
+ c.lock_timeout = options[:lock_timeout] if options.key?(:lock_timeout)
71
+
73
72
  if (psleep = options[:poll_sleep_amount]) && !psleep.nil?
74
73
  c.poll_sleep_amount = Float(psleep)
75
74
  end
@@ -77,6 +76,7 @@ module Resque
77
76
  c.verbose = !!options[:verbose] if options.key?(:verbose)
78
77
  end
79
78
  end
79
+ # rubocop:enable Metrics/AbcSize
80
80
 
81
81
  def cleanup_pid_file
82
82
  return unless pidfile_path
@@ -11,7 +11,7 @@ module Resque
11
11
  @key = key
12
12
 
13
13
  # 3 minute default timeout
14
- @timeout = options[:timeout] || 60 * 3
14
+ @timeout = options[:timeout] || Resque::Scheduler.lock_timeout
15
15
  end
16
16
 
17
17
  # Attempts to acquire the lock. Returns true if successfully acquired.
@@ -47,7 +47,7 @@ module Resque
47
47
 
48
48
  def hostname
49
49
  local_hostname = Socket.gethostname
50
- Socket.gethostbyname(local_hostname).first
50
+ Addrinfo.getaddrinfo(local_hostname, 'http').first.getnameinfo.first
51
51
  rescue
52
52
  local_hostname
53
53
  end
@@ -2,7 +2,7 @@
2
2
 
3
3
  # ### Locking the scheduler process
4
4
  #
5
- # There are two places in resque-scheduler that need to be synchonized in order
5
+ # There are two places in resque-scheduler that need to be synchronized in order
6
6
  # to be able to run redundant scheduler processes while ensuring jobs don't get
7
7
  # queued multiple times when the master process changes.
8
8
  #
@@ -15,7 +15,7 @@ module Resque
15
15
  # - :quiet if logger needs to be silent for all levels. Default - false
16
16
  # - :verbose if there is a need in debug messages. Default - false
17
17
  # - :log_dev to output logs into a desired file. Default - STDOUT
18
- # - :format log format, either 'text' or 'json'. Default - 'text'
18
+ # - :format log format, either 'text', 'json' or 'logfmt'. Default - 'text'
19
19
  #
20
20
  # Example:
21
21
  #
@@ -32,6 +32,7 @@ module Resque
32
32
  # Returns an instance of MonoLogger
33
33
  def build
34
34
  logger = MonoLogger.new(@log_dev)
35
+ logger.progname = 'resque-scheduler'.freeze
35
36
  logger.level = level
36
37
  logger.formatter = send(:"#{@format}_formatter")
37
38
  logger
@@ -50,21 +51,31 @@ module Resque
50
51
  end
51
52
 
52
53
  def text_formatter
53
- proc do |severity, datetime, _progname, msg|
54
- "resque-scheduler: [#{severity}] #{datetime.iso8601}: #{msg}\n"
54
+ proc do |severity, datetime, progname, msg|
55
+ "#{progname}: [#{severity}] #{datetime.iso8601}: #{msg}\n"
55
56
  end
56
57
  end
57
58
 
58
59
  def json_formatter
59
60
  proc do |severity, datetime, progname, msg|
60
61
  require 'json'
61
- JSON.dump(
62
- name: 'resque-scheduler',
62
+ log_data = {
63
+ name: progname,
63
64
  progname: progname,
64
65
  level: severity,
65
66
  timestamp: datetime.iso8601,
66
67
  msg: msg
67
- ) + "\n"
68
+ }
69
+ JSON.dump(log_data) + "\n"
70
+ end
71
+ end
72
+
73
+ def logfmt_formatter
74
+ proc do |severity, datetime, progname, msg|
75
+ "timestamp=\"#{datetime.iso8601}\" " \
76
+ "level=\"#{severity}\" " \
77
+ "progname=\"#{progname}\" " \
78
+ "msg=\"#{msg}\"\n"
68
79
  end
69
80
  end
70
81
  end
@@ -3,6 +3,15 @@
3
3
  module Resque
4
4
  module Scheduler
5
5
  module Plugin
6
+ def self.process_schedule_hooks(klass, *args)
7
+ # the documentation states that if any before_schedule hook returns
8
+ # false, the process should not be enqueued
9
+ return unless run_before_schedule_hooks(klass, *args)
10
+
11
+ yield
12
+ run_after_schedule_hooks(klass, *args)
13
+ end
14
+
6
15
  def self.hooks(job, pattern)
7
16
  job.methods.grep(/^#{pattern}/).sort
8
17
  end
@@ -36,7 +36,7 @@ module Resque
36
36
  # :args can be any yaml which will be converted to a ruby literal and
37
37
  # passed in a params. (optional)
38
38
  #
39
- # :rails_envs is the list of envs where the job gets loaded. Envs are
39
+ # :rails_env is the list of envs where the job gets loaded. Envs are
40
40
  # comma separated (optional)
41
41
  #
42
42
  # :description is just that, a description of the job (optional). If
@@ -91,7 +91,7 @@ module Resque
91
91
  non_persistent_schedules[name] = decode(encode(config))
92
92
  end
93
93
 
94
- redis.sadd(:schedules_changed, name)
94
+ redis.sadd(:schedules_changed, [name])
95
95
  reload_schedule! if reload
96
96
  end
97
97
 
@@ -101,12 +101,13 @@ module Resque
101
101
  end
102
102
 
103
103
  # remove a given schedule by name
104
- def remove_schedule(name)
104
+ # Preventing a reload is optional and available to batch operations
105
+ def remove_schedule(name, reload = true)
105
106
  non_persistent_schedules.delete(name)
106
107
  redis.hdel(:persistent_schedules, name)
107
- redis.sadd(:schedules_changed, name)
108
+ redis.sadd(:schedules_changed, [name])
108
109
 
109
- reload_schedule!
110
+ reload_schedule! if reload
110
111
  end
111
112
 
112
113
  private
@@ -1,9 +1,9 @@
1
1
  <h1>Delayed Jobs</h1>
2
- <%- size = resque.delayed_queue_schedule_size %>
2
+ <% size = resque.delayed_queue_schedule_size %>
3
3
 
4
4
  <%= scheduler_view :search_form, layout: false %>
5
5
 
6
- <p style="font-color: red; font-weight: bold;">
6
+ <p style="color: red; font-weight: bold;">
7
7
  <%= @error_message %>
8
8
  </p>
9
9
 
@@ -16,6 +16,14 @@
16
16
  Showing <%= start = params[:start].to_i %> to <%= start + 20 %> of <b><%= size %></b> timestamps
17
17
  </p>
18
18
 
19
+ <% if size > 0 %>
20
+ <div style="padding-bottom: 10px">
21
+ <form method="POST" action="<%= u 'delayed/clear' %>" class='clear-delayed confirmSubmission'>
22
+ <input type='submit' name='' value='Clear Delayed Jobs' />
23
+ </form>
24
+ </div>
25
+ <% end %>
26
+
19
27
  <table>
20
28
  <tr>
21
29
  <th></th>
@@ -27,7 +35,7 @@
27
35
  </tr>
28
36
  <% resque.delayed_queue_peek(start, 20).each do |timestamp| %>
29
37
  <tr>
30
- <td>
38
+ <td style="padding-top: 12px; padding-bottom: 2px; width: 10px">
31
39
  <form action="<%= u "/delayed/queue_now" %>" method="post">
32
40
  <input type="hidden" name="timestamp" value="<%= timestamp.to_i %>">
33
41
  <input type="submit" value="Queue now">
@@ -46,18 +54,11 @@
46
54
  <td><%= h(show_job_arguments(job['args'])) if job && delayed_timestamp_size == 1 %></td>
47
55
  <td>
48
56
  <% if job %>
49
- <a href="<%=u URI("/delayed/jobs/#{URI.escape(job['class'])}?args=" + URI.encode(job['args'].to_json)) %>">All schedules</a>
57
+ <a href="<%= u URI("/delayed/jobs/#{CGI.escape(job['class'])}?args=" + CGI.escape(job['args'].to_json)) %>">All schedules</a>
50
58
  <% end %>
51
59
  </td>
52
60
  </tr>
53
61
  <% end %>
54
62
  </table>
55
63
 
56
- <% if size > 0 %>
57
- <br>
58
- <form method="POST" action="<%=u 'delayed/clear'%>" class='clear-delayed'>
59
- <input type='submit' name='' value='Clear Delayed Jobs' />
60
- </form>
61
- <% end %>
62
-
63
64
  <%= partial :next_more, :start => start, :size => size %>
@@ -1,4 +1,4 @@
1
- <h1>Delayed jobs scheduled for <%= params[:klass] %> (<%= show_job_arguments(@args) %>)</h1>
1
+ <h1>Delayed jobs scheduled for <%=h params[:klass] %> (<%=h show_job_arguments(@args) %>)</h1>
2
2
 
3
3
  <table class='jobs'>
4
4
  <tr>
@@ -13,7 +13,7 @@
13
13
  <% jobs.each do |job| %>
14
14
  <tr>
15
15
  <td class='class'><%= job['class'] %></td>
16
- <td class='args'><%=h show_job_arguments(job['args']) %></td>
16
+ <td class='args'><%= h show_job_arguments(job['args']) %></td>
17
17
  </tr>
18
18
  <% end %>
19
19
  <% if jobs.empty? %>
@@ -8,7 +8,7 @@
8
8
  <br/> Current master: <%= Resque.redis.get(Resque::Scheduler.master_lock.key) %>
9
9
  </p>
10
10
  <p class='intro'>
11
- The highlighted jobs are skipped for current environment.
11
+ The highlighted jobs are skipped for current environment.
12
12
  </p>
13
13
  <div style="overflow-y: auto; width:100%; padding: 0px 5px;">
14
14
  <table>
@@ -29,7 +29,7 @@
29
29
  <% Resque.schedule.keys.sort.each_with_index do |name, index| %>
30
30
  <% config = Resque.schedule[name] %>
31
31
  <tr style="<%= scheduled_in_this_env?(name) ? '' : 'color: #9F6000;background: #FEEFB3;' %>">
32
- <td style="padding-left: 15px;"><%= index+ 1 %>.</td>
32
+ <td style="padding-left: 15px;"><%= index + 1 %>.</td>
33
33
  <% if Resque::Scheduler.dynamic %>
34
34
  <td style="padding-top: 12px; padding-bottom: 2px; width: 10px">
35
35
  <form action="<%= u "/schedule" %>" method="post" style="margin-left: 0">
@@ -13,13 +13,13 @@
13
13
  </tr>
14
14
  <% delayed.each do |job| %>
15
15
  <tr>
16
- <td>
16
+ <td style="padding-top: 12px; padding-bottom: 2px; width: 10px">
17
17
  <form action="<%= u "/delayed/queue_now" %>" method="post">
18
18
  <input type="hidden" name="timestamp" value="<%= job['timestamp'].to_i %>">
19
19
  <input type="submit" value="Queue now">
20
20
  </form>
21
21
  </td>
22
- <td>
22
+ <td style="padding-top: 12px; padding-bottom: 2px; width: 10px">
23
23
  <form action="<%= u "/delayed/cancel_now" %>" method="post">
24
24
  <input type="hidden" name="timestamp" value="<%= job['timestamp'].to_i %>">
25
25
  <input type="hidden" name="klass" value="<%= job['class'] %>">
@@ -33,7 +33,6 @@
33
33
  </tr>
34
34
  <% end %>
35
35
  </table>
36
- </h1>
37
36
 
38
37
  <% queued = @jobs.select { |j| j['where_at'] == 'queued' } %>
39
38
  <h1>Queued jobs</h1>
@@ -68,5 +67,3 @@
68
67
  </tr>
69
68
  <% end %>
70
69
  </table>
71
-
72
-
@@ -1,8 +1,4 @@
1
1
  <form method="POST" action="<%= u 'delayed/search' %>">
2
- <input type='input' name='search' value="<%= params[:search] %>"/>
2
+ <input type='input' name='search' value="<%= h params[:search] %>"/>
3
3
  <input type='submit' value='Search'/>
4
4
  </form>
5
-
6
-
7
-
8
-
@@ -87,7 +87,7 @@ module Resque
87
87
  def delayed_jobs_klass
88
88
  begin
89
89
  klass = Resque::Scheduler::Util.constantize(params[:klass])
90
- @args = JSON.load(URI.decode(params[:args]))
90
+ @args = JSON.load(CGI.unescape(params[:args]))
91
91
  @timestamps = Resque.scheduled_at(klass, *@args)
92
92
  rescue
93
93
  @timestamps = []