resque_admin-scheduler 1.0.4 → 1.0.5

Sign up to get free protection for your applications and to get access to all the features.
Files changed (33) hide show
  1. checksums.yaml +4 -4
  2. metadata +63 -39
  3. data/bin/migrate_to_timestamps_set.rb +0 -16
  4. data/exe/resque-scheduler +0 -5
  5. data/lib/resque-scheduler.rb +0 -4
  6. data/lib/resque_admin/scheduler.rb +0 -447
  7. data/lib/resque_admin/scheduler/cli.rb +0 -147
  8. data/lib/resque_admin/scheduler/configuration.rb +0 -73
  9. data/lib/resque_admin/scheduler/delaying_extensions.rb +0 -324
  10. data/lib/resque_admin/scheduler/env.rb +0 -89
  11. data/lib/resque_admin/scheduler/extension.rb +0 -13
  12. data/lib/resque_admin/scheduler/failure_handler.rb +0 -11
  13. data/lib/resque_admin/scheduler/lock.rb +0 -4
  14. data/lib/resque_admin/scheduler/lock/base.rb +0 -61
  15. data/lib/resque_admin/scheduler/lock/basic.rb +0 -27
  16. data/lib/resque_admin/scheduler/lock/resilient.rb +0 -78
  17. data/lib/resque_admin/scheduler/locking.rb +0 -104
  18. data/lib/resque_admin/scheduler/logger_builder.rb +0 -72
  19. data/lib/resque_admin/scheduler/plugin.rb +0 -31
  20. data/lib/resque_admin/scheduler/scheduling_extensions.rb +0 -141
  21. data/lib/resque_admin/scheduler/server.rb +0 -268
  22. data/lib/resque_admin/scheduler/server/views/delayed.erb +0 -63
  23. data/lib/resque_admin/scheduler/server/views/delayed_schedules.erb +0 -20
  24. data/lib/resque_admin/scheduler/server/views/delayed_timestamp.erb +0 -26
  25. data/lib/resque_admin/scheduler/server/views/requeue-params.erb +0 -23
  26. data/lib/resque_admin/scheduler/server/views/scheduler.erb +0 -58
  27. data/lib/resque_admin/scheduler/server/views/search.erb +0 -72
  28. data/lib/resque_admin/scheduler/server/views/search_form.erb +0 -8
  29. data/lib/resque_admin/scheduler/signal_handling.rb +0 -40
  30. data/lib/resque_admin/scheduler/tasks.rb +0 -25
  31. data/lib/resque_admin/scheduler/util.rb +0 -39
  32. data/lib/resque_admin/scheduler/version.rb +0 -7
  33. data/tasks/resque_scheduler.rake +0 -2
@@ -1,31 +0,0 @@
1
- # vim:fileencoding=utf-8
2
-
3
- module ResqueAdmin
4
- module Scheduler
5
- module Plugin
6
- def self.hooks(job, pattern)
7
- job.methods.grep(/^#{pattern}/).sort
8
- end
9
-
10
- def self.run_hooks(job, pattern, *args)
11
- results = hooks(job, pattern).map do |hook|
12
- job.send(hook, *args)
13
- end
14
-
15
- results.all? { |result| result != false }
16
- end
17
-
18
- def self.run_before_delayed_enqueue_hooks(klass, *args)
19
- run_hooks(klass, 'before_delayed_enqueue', *args)
20
- end
21
-
22
- def self.run_before_schedule_hooks(klass, *args)
23
- run_hooks(klass, 'before_schedule', *args)
24
- end
25
-
26
- def self.run_after_schedule_hooks(klass, *args)
27
- run_hooks(klass, 'after_schedule', *args)
28
- end
29
- end
30
- end
31
- end
@@ -1,141 +0,0 @@
1
- # vim:fileencoding=utf-8
2
-
3
- module ResqueAdmin
4
- module Scheduler
5
- module SchedulingExtensions
6
- # Accepts a new schedule configuration of the form:
7
- #
8
- # {
9
- # "MakeTea" => {
10
- # "every" => "1m" },
11
- # "some_name" => {
12
- # "cron" => "5/* * * *",
13
- # "class" => "DoSomeWork",
14
- # "args" => "work on this string",
15
- # "description" => "this thing works it"s butter off" },
16
- # ...
17
- # }
18
- #
19
- # Hash keys can be anything and are used to describe and reference
20
- # the scheduled job. If the "class" argument is missing, the key
21
- # is used implicitly as "class" argument - in the "MakeTea" example,
22
- # "MakeTea" is used both as job name and resque worker class.
23
- #
24
- # Any jobs that were in the old schedule, but are not
25
- # present in the new schedule, will be removed.
26
- #
27
- # :cron can be any cron scheduling string
28
- #
29
- # :every can be used in lieu of :cron. see rufus-scheduler's 'every'
30
- # usage for valid syntax. If :cron is present it will take precedence
31
- # over :every.
32
- #
33
- # :class must be a resque worker class. If it is missing, the job name
34
- # (hash key) will be used as :class.
35
- #
36
- # :args can be any yaml which will be converted to a ruby literal and
37
- # passed in a params. (optional)
38
- #
39
- # :rails_envs is the list of envs where the job gets loaded. Envs are
40
- # comma separated (optional)
41
- #
42
- # :description is just that, a description of the job (optional). If
43
- # params is an array, each element in the array is passed as a separate
44
- # param, otherwise params is passed in as the only parameter to
45
- # perform.
46
- def schedule=(schedule_hash)
47
- @non_persistent_schedules = nil
48
- prepared_schedules = prepare_schedules(schedule_hash)
49
-
50
- prepared_schedules.each do |schedule, config|
51
- set_schedule(schedule, config, false)
52
- end
53
-
54
- # ensure only return the successfully saved data!
55
- reload_schedule!
56
- end
57
-
58
- # Returns the schedule hash
59
- def schedule
60
- @schedule ||= all_schedules
61
- @schedule || {}
62
- end
63
-
64
- # reloads the schedule from redis and memory
65
- def reload_schedule!
66
- @schedule = all_schedules
67
- end
68
-
69
- # gets the schedules as it exists in redis
70
- def all_schedules
71
- non_persistent_schedules.merge(persistent_schedules)
72
- end
73
-
74
- # Create or update a schedule with the provided name and configuration.
75
- #
76
- # Note: values for class and custom_job_class need to be strings,
77
- # not constants.
78
- #
79
- # ResqueAdmin.set_schedule('some_job', {:class => 'SomeJob',
80
- # :every => '15mins',
81
- # :queue => 'high',
82
- # :args => '/tmp/poop'})
83
- #
84
- # Preventing a reload is optional and available to batch operations
85
- def set_schedule(name, config, reload = true)
86
- persist = config.delete(:persist) || config.delete('persist')
87
-
88
- if persist
89
- redis.hset(:persistent_schedules, name, encode(config))
90
- else
91
- non_persistent_schedules[name] = decode(encode(config))
92
- end
93
-
94
- redis.sadd(:schedules_changed, name)
95
- reload_schedule! if reload
96
- end
97
-
98
- # retrive the schedule configuration for the given name
99
- def fetch_schedule(name)
100
- schedule[name]
101
- end
102
-
103
- # remove a given schedule by name
104
- def remove_schedule(name)
105
- non_persistent_schedules.delete(name)
106
- redis.hdel(:persistent_schedules, name)
107
- redis.sadd(:schedules_changed, name)
108
-
109
- reload_schedule!
110
- end
111
-
112
- private
113
-
114
- # we store our non-persistent schedules in this hash
115
- def non_persistent_schedules
116
- @non_persistent_schedules ||= {}
117
- end
118
-
119
- # reads the persistent schedules from redis
120
- def persistent_schedules
121
- redis.hgetall(:persistent_schedules).tap do |h|
122
- h.each do |name, config|
123
- h[name] = decode(config)
124
- end
125
- end
126
- end
127
-
128
- def prepare_schedules(schedule_hash)
129
- prepared_hash = {}
130
- schedule_hash.each do |name, job_spec|
131
- job_spec = job_spec.dup
132
- unless job_spec.key?('class') || job_spec.key?(:class)
133
- job_spec['class'] = name
134
- end
135
- prepared_hash[name] = job_spec
136
- end
137
- prepared_hash
138
- end
139
- end
140
- end
141
- end
@@ -1,268 +0,0 @@
1
- # vim:fileencoding=utf-8
2
- require 'resque-scheduler'
3
- require 'resque_admin/server'
4
- require 'tilt/erb'
5
- require 'json'
6
-
7
- # Extend ResqueAdmin::Server to add tabs
8
- module ResqueAdmin
9
- module Scheduler
10
- module Server
11
- TIMESTAMP_FORMAT = '%Y-%m-%d %H:%M:%S %z'.freeze
12
-
13
- unless defined?(::ResqueAdmin::Scheduler::Server::VIEW_PATH)
14
- VIEW_PATH = File.join(File.dirname(__FILE__), 'server', 'views')
15
- end
16
-
17
- def self.included(base)
18
- base.class_eval do
19
- helpers { include HelperMethods }
20
- include ServerMethods
21
-
22
- get('/schedule') { schedule }
23
- post('/schedule/requeue') { schedule_requeue }
24
- post('/schedule/requeue_with_params') do
25
- schedule_requeue_with_params
26
- end
27
- delete('/schedule') { delete_schedule }
28
- get('/delayed') { delayed }
29
- get('/delayed/jobs/:klass') { delayed_jobs_klass }
30
- post('/delayed/search') { delayed_search }
31
- get('/delayed/:timestamp') { delayed_timestamp }
32
- post('/delayed/queue_now') { delayed_queue_now }
33
- post('/delayed/cancel_now') { delayed_cancel_now }
34
- post('/delayed/clear') { delayed_clear }
35
- end
36
- end
37
-
38
- module ServerMethods
39
- def schedule
40
- ResqueAdmin.reload_schedule! if ResqueAdmin::Scheduler.dynamic
41
- erb scheduler_template('scheduler')
42
- end
43
-
44
- def schedule_requeue
45
- @job_name = params['job_name'] || params[:job_name]
46
- config = ResqueAdmin.schedule[@job_name]
47
- @parameters = config['parameters'] || config[:parameters]
48
- if @parameters
49
- erb scheduler_template('requeue-params')
50
- else
51
- ResqueAdmin::Scheduler.enqueue_from_config(config)
52
- redirect u('/overview')
53
- end
54
- end
55
-
56
- def schedule_requeue_with_params
57
- job_name = params['job_name'] || params[:job_name]
58
- config = ResqueAdmin.schedule[job_name]
59
- # Build args hash from post data (removing the job name)
60
- submitted_args = params.reject do |key, _value|
61
- key == 'job_name' || key == :job_name
62
- end
63
-
64
- # Merge constructed args hash with existing args hash for
65
- # the job, if it exists
66
- config_args = config['args'] || config[:args] || {}
67
- config_args = config_args.merge(submitted_args)
68
-
69
- # Insert the args hash into config and queue the resque job
70
- config = config.merge('args' => config_args)
71
- ResqueAdmin::Scheduler.enqueue_from_config(config)
72
- redirect u('/overview')
73
- end
74
-
75
- def delete_schedule
76
- if ResqueAdmin::Scheduler.dynamic
77
- job_name = params['job_name'] || params[:job_name]
78
- ResqueAdmin.remove_schedule(job_name)
79
- end
80
- redirect u('/schedule')
81
- end
82
-
83
- def delayed
84
- erb scheduler_template('delayed')
85
- end
86
-
87
- def delayed_jobs_klass
88
- begin
89
- klass = ResqueAdmin::Scheduler::Util.constantize(params[:klass])
90
- @args = JSON.load(URI.decode(params[:args]))
91
- @timestamps = ResqueAdmin.scheduled_at(klass, *@args)
92
- rescue
93
- @timestamps = []
94
- end
95
-
96
- erb scheduler_template('delayed_schedules')
97
- end
98
-
99
- def delayed_search
100
- @jobs = find_job(params[:search])
101
- erb scheduler_template('search')
102
- end
103
-
104
- def delayed_timestamp
105
- erb scheduler_template('delayed_timestamp')
106
- end
107
-
108
- def delayed_queue_now
109
- timestamp = params['timestamp'].to_i
110
- formatted_time = Time.at(timestamp).strftime(
111
- ::ResqueAdmin::Scheduler::Server::TIMESTAMP_FORMAT
112
- )
113
-
114
- if timestamp > 0
115
- unless ResqueAdmin::Scheduler.enqueue_next_item(timestamp)
116
- @error_message = "Unable to remove item at #{formatted_time}"
117
- end
118
- else
119
- @error_message = "Incorrect timestamp #{formatted_time}"
120
- end
121
-
122
- erb scheduler_template('delayed')
123
- end
124
-
125
- def delayed_cancel_now
126
- klass = ResqueAdmin::Scheduler::Util.constantize(params['klass'])
127
- timestamp = params['timestamp']
128
- args = ResqueAdmin.decode params['args']
129
- ResqueAdmin.remove_delayed_job_from_timestamp(timestamp, klass, *args)
130
- redirect u('/delayed')
131
- end
132
-
133
- def delayed_clear
134
- ResqueAdmin.reset_delayed_queue
135
- redirect u('delayed')
136
- end
137
- end
138
-
139
- module HelperMethods
140
- def format_time(t)
141
- t.strftime(::ResqueAdmin::Scheduler::Server::TIMESTAMP_FORMAT)
142
- end
143
-
144
- def show_job_arguments(args)
145
- Array(args).map(&:inspect).join("\n")
146
- end
147
-
148
- def queue_from_class_name(class_name)
149
- ResqueAdmin.queue_from_class(
150
- ResqueAdmin::Scheduler::Util.constantize(class_name)
151
- )
152
- end
153
-
154
- def find_job(worker)
155
- worker = worker.downcase
156
- results = working_jobs_for_worker(worker)
157
-
158
- dels = delayed_jobs_for_worker(worker)
159
- results += dels.select do |j|
160
- j['class'].downcase.include?(worker) &&
161
- j.merge!('where_at' => 'delayed')
162
- end
163
-
164
- ResqueAdmin.queues.each do |queue|
165
- queued = ResqueAdmin.peek(queue, 0, ResqueAdmin.size(queue))
166
- queued = [queued] unless queued.is_a?(Array)
167
- results += queued.select do |j|
168
- j['class'].downcase.include?(worker) &&
169
- j.merge!('queue' => queue, 'where_at' => 'queued')
170
- end
171
- end
172
-
173
- results
174
- end
175
-
176
- def schedule_interval(config)
177
- if config['every']
178
- schedule_interval_every(config['every'])
179
- elsif config['cron']
180
- 'cron: ' + config['cron'].to_s
181
- else
182
- 'Not currently scheduled'
183
- end
184
- end
185
-
186
- def schedule_interval_every(every)
187
- every = [*every]
188
- s = 'every: ' << every.first
189
-
190
- return s unless every.length > 1
191
-
192
- s << ' ('
193
- meta = every.last.map do |key, value|
194
- "#{key.to_s.tr('_', ' ')} #{value}"
195
- end
196
- s << meta.join(', ') << ')'
197
- end
198
-
199
- def schedule_class(config)
200
- if config['class'].nil? && !config['custom_job_class'].nil?
201
- config['custom_job_class']
202
- else
203
- config['class']
204
- end
205
- end
206
-
207
- def scheduler_template(name)
208
- File.read(
209
- File.expand_path("../server/views/#{name}.erb", __FILE__)
210
- )
211
- end
212
-
213
- def scheduled_in_this_env?(name)
214
- return true if rails_env(name).nil?
215
- rails_env(name).split(/[\s,]+/).include?(ResqueAdmin::Scheduler.env)
216
- end
217
-
218
- def rails_env(name)
219
- ResqueAdmin.schedule[name]['rails_env'] || ResqueAdmin.schedule[name]['env']
220
- end
221
-
222
- def scheduler_view(filename, options = {}, locals = {})
223
- source = File.read(File.join(VIEW_PATH, "#{filename}.erb"))
224
- erb source, options, locals
225
- end
226
-
227
- private
228
-
229
- def working_jobs_for_worker(worker)
230
- [].tap do |results|
231
- working = [*ResqueAdmin.working]
232
- work = working.select do |w|
233
- w.job && w.job['payload'] &&
234
- w.job['payload']['class'].downcase.include?(worker)
235
- end
236
- work.each do |w|
237
- results += [
238
- w.job['payload'].merge(
239
- 'queue' => w.job['queue'], 'where_at' => 'working'
240
- )
241
- ]
242
- end
243
- end
244
- end
245
-
246
- def delayed_jobs_for_worker(_worker)
247
- [].tap do |dels|
248
- schedule_size = ResqueAdmin.delayed_queue_schedule_size
249
- ResqueAdmin.delayed_queue_peek(0, schedule_size).each do |d|
250
- ResqueAdmin.delayed_timestamp_peek(
251
- d, 0, ResqueAdmin.delayed_timestamp_size(d)
252
- ).each do |j|
253
- dels << j.merge!('timestamp' => d)
254
- end
255
- end
256
- end
257
- end
258
- end
259
- end
260
- end
261
- end
262
-
263
- ResqueAdmin::Server.tabs << 'Schedule'
264
- ResqueAdmin::Server.tabs << 'Delayed'
265
-
266
- ResqueAdmin::Server.class_eval do
267
- include ResqueAdmin::Scheduler::Server
268
- end
@@ -1,63 +0,0 @@
1
- <h1>Delayed Jobs</h1>
2
- <%- size = resque.delayed_queue_schedule_size %>
3
-
4
- <%= scheduler_view :search_form, layout: false %>
5
-
6
- <p style="font-color: red; font-weight: bold;">
7
- <%= @error_message %>
8
- </p>
9
-
10
- <p class='intro'>
11
- This list below contains the timestamps for scheduled delayed jobs.
12
- Server local time: <%= Time.now %>
13
- </p>
14
-
15
- <p class='sub'>
16
- Showing <%= start = params[:start].to_i %> to <%= start + 20 %> of <b><%= size %></b> timestamps
17
- </p>
18
-
19
- <table>
20
- <tr>
21
- <th></th>
22
- <th>Timestamp</th>
23
- <th>Job count</th>
24
- <th>Class</th>
25
- <th>Args</th>
26
- <th>All schedules</th>
27
- </tr>
28
- <% resque.delayed_queue_peek(start, 20).each do |timestamp| %>
29
- <tr>
30
- <td>
31
- <form action="<%= u "/delayed/queue_now" %>" method="post">
32
- <input type="hidden" name="timestamp" value="<%= timestamp.to_i %>">
33
- <input type="submit" value="Queue now">
34
- </form>
35
- </td>
36
- <td><a href="<%= u "delayed/#{timestamp}" %>"><%= format_time(Time.at(timestamp)) %></a></td>
37
- <td><%= delayed_timestamp_size = resque.delayed_timestamp_size(timestamp) %></td>
38
- <% job = resque.delayed_timestamp_peek(timestamp, 0, 1).first %>
39
- <td>
40
- <% if job && delayed_timestamp_size == 1 %>
41
- <%= h(job['class']) %>
42
- <% else %>
43
- <a href="<%= u "delayed/#{timestamp}" %>">see details</a>
44
- <% end %>
45
- </td>
46
- <td><%= h(show_job_arguments(job['args'])) if job && delayed_timestamp_size == 1 %></td>
47
- <td>
48
- <% if job %>
49
- <a href="<%=u URI("/delayed/jobs/#{job['class']}?args=" + URI.encode(job['args'].to_json)) %>">All schedules</a>
50
- <% end %>
51
- </td>
52
- </tr>
53
- <% end %>
54
- </table>
55
-
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
- <%= partial :next_more, :start => start, :size => size %>