diff --git a/.gitignore b/.gitignore index f979559b..6cf79dee 100644 --- a/.gitignore +++ b/.gitignore @@ -15,3 +15,5 @@ nbproject .env .env.* + +/test/dummy/log/ diff --git a/lib/resque-scheduler.rb b/lib/resque-scheduler.rb index b770cd91..5c64f324 100644 --- a/lib/resque-scheduler.rb +++ b/lib/resque-scheduler.rb @@ -1,4 +1,5 @@ # vim:fileencoding=utf-8 require_relative 'resque/scheduler' +require 'resque/scheduler/engine' Resque.extend Resque::Scheduler::Extension diff --git a/lib/resque/scheduler/engine.rb b/lib/resque/scheduler/engine.rb new file mode 100644 index 00000000..ef6a1cbc --- /dev/null +++ b/lib/resque/scheduler/engine.rb @@ -0,0 +1,48 @@ +require 'resque_web' + +module ResqueWeb + module Plugins + module ResqueScheduler + class Engine < Rails::Engine + isolate_namespace ResqueWeb::Plugins::ResqueScheduler + paths['app'] << 'lib/resque/scheduler/engine/app' + paths['app/helpers'] << 'lib/resque/scheduler/engine/app/helpers' + paths['app/views'] << 'lib/resque/scheduler/engine/app/views' + paths['app/controllers'] << 'lib/resque/scheduler/'\ + 'engine/app/controllers' + end + + Engine.routes do + get 'schedule', to: 'schedules#index', as: 'schedules' + post 'schedule/requeue', to: 'schedules#requeue', as: 'requeue' + post 'schedule/requeue_with_params', + to: 'schedules#requeue_with_params', + as: 'requeue_with_params' + delete 'schedule', to: 'schedules#destroy', as: 'schedule' + + get 'delayed', to: 'delayed#index', as: 'delayed' + get 'delayed/jobs/:klass', + to: 'delayed#jobs_klass', + as: 'delayed_job_class' + post 'delayed/search', to: 'delayed#search', as: 'delayed_search' + get 'delayed/:timestamp', to: 'delayed#timestamp', as: 'timestamp' + post 'delayed/queue_now', to: 'delayed#queue_now', as: 'queue_now' + post 'delayed/cancel_now', to: 'delayed#cancel_now', as: 'cancel_now' + post '/delayed/clear', to: 'delayed#clear', as: 'clear' + end + + def self.engine_path + '/scheduler' + end + + def self.tabs + [ + { + 'schedule' => Engine.app.url_helpers.schedules_path, + 'delayed' => Engine.app.url_helpers.delayed_path + } + ] + end + end + end +end diff --git a/lib/resque/scheduler/engine/app/controllers/resque_web/plugins/resque_scheduler/delayed_controller.rb b/lib/resque/scheduler/engine/app/controllers/resque_web/plugins/resque_scheduler/delayed_controller.rb new file mode 100644 index 00000000..c0f45982 --- /dev/null +++ b/lib/resque/scheduler/engine/app/controllers/resque_web/plugins/resque_scheduler/delayed_controller.rb @@ -0,0 +1,100 @@ +module ResqueWeb + module Plugins + module ResqueScheduler + class DelayedController < ResqueWeb::ApplicationController + def index + end + + def jobs_klass + klass = Resque::Scheduler::Util.constantize(params[:klass]) + @args = JSON.load(URI.decode(params[:args])) + @timestamps = Resque.scheduled_at(klass, *@args) + rescue + @timestamps = [] + end + + def search + @jobs = find_job(params[:search]) + end + + def cancel_now + klass = Resque::Scheduler::Util.constantize(params['klass']) + timestamp = params['timestamp'] + args = Resque.decode params['args'] + Resque.remove_delayed_job_from_timestamp(timestamp, klass, *args) + redirect_to Engine.app.url_helpers.delayed_path + end + + def clear + Resque.reset_delayed_queue + redirect_to Engine.app.url_helpers.delayed_path + end + + def queue_now + timestamp = params['timestamp'].to_i + if timestamp > 0 + Resque::Scheduler.enqueue_delayed_items_for_timestamp(timestamp) + end + redirect_to ResqueWeb::Engine.app.url_helpers.overview_path + end + + def timestamp + @timestamp = params[:timestamp].to_i + end + + protected + + def find_job(worker) + worker = worker.downcase + results = working_jobs_for_worker(worker) + + dels = delayed_jobs_for_worker(worker) + results += dels.select do |j| + j['class'].downcase.include?(worker) && + j.merge!('where_at' => 'delayed') + end + + Resque.queues.each do |queue| + queued = Resque.peek(queue, 0, Resque.size(queue)) + queued = [queued] unless queued.is_a?(Array) + results += queued.select do |j| + j['class'].downcase.include?(worker) && + j.merge!('queue' => queue, 'where_at' => 'queued') + end + end + + results + end + + def working_jobs_for_worker(worker) + [].tap do |results| + working = [*Resque.working] + work = working.select do |w| + w.job && w.job['payload'] && + w.job['payload']['class'].downcase.include?(worker) + end + work.each do |w| + results += [ + w.job['payload'].merge( + 'queue' => w.job['queue'], 'where_at' => 'working' + ) + ] + end + end + end + + def delayed_jobs_for_worker(_worker) + [].tap do |dels| + schedule_size = Resque.delayed_queue_schedule_size + Resque.delayed_queue_peek(0, schedule_size).each do |d| + Resque.delayed_timestamp_peek( + d, 0, Resque.delayed_timestamp_size(d)).each do |j| + dels << j.merge!('timestamp' => d) + end + end + end + end + end + end + end +end diff --git a/lib/resque/scheduler/engine/app/controllers/resque_web/plugins/resque_scheduler/schedules_controller.rb b/lib/resque/scheduler/engine/app/controllers/resque_web/plugins/resque_scheduler/schedules_controller.rb new file mode 100644 index 00000000..a5002403 --- /dev/null +++ b/lib/resque/scheduler/engine/app/controllers/resque_web/plugins/resque_scheduler/schedules_controller.rb @@ -0,0 +1,50 @@ +module ResqueWeb + module Plugins + module ResqueScheduler + class SchedulesController < ResqueWeb::ApplicationController + def index + Resque.reload_schedule! if Resque::Scheduler.dynamic + end + + def destroy + if Resque::Scheduler.dynamic + job_name = params['job_name'] || params[:job_name] + Resque.remove_schedule(job_name) + end + redirect_to Engine.app.url_helpers.schedules_path + end + + def requeue + @job_name = params['job_name'] || params[:job_name] + config = Resque.schedule[@job_name] + @parameters = config['parameters'] || config[:parameters] + if @parameters + render 'requeue-params' + else + Resque::Scheduler.enqueue_from_config(config) + redirect_to ResqueWeb::Engine.app.url_helpers.overview_path + end + end + + def requeue_with_params + job_name = params['job_name'] || params[:job_name] + config = Resque.schedule[job_name] + # Build args hash from post data (removing the job name) + submitted_args = params.reject do |key, _value| + %w(job_name action controller).include?(key) + end + + # Merge constructed args hash with existing args hash for + # the job, if it exists + config_args = config['args'] || config[:args] || {} + config_args = config_args.merge(submitted_args) + + # Insert the args hash into config and queue the resque job + config = config.merge('args' => config_args) + Resque::Scheduler.enqueue_from_config(config) + redirect_to ResqueWeb::Engine.app.url_helpers.overview_path + end + end + end + end +end diff --git a/lib/resque/scheduler/engine/app/helpers/resque_web/plugins/resque_scheduler/delayed_helper.rb b/lib/resque/scheduler/engine/app/helpers/resque_web/plugins/resque_scheduler/delayed_helper.rb new file mode 100644 index 00000000..0f84f06f --- /dev/null +++ b/lib/resque/scheduler/engine/app/helpers/resque_web/plugins/resque_scheduler/delayed_helper.rb @@ -0,0 +1,11 @@ +module ResqueWeb + module Plugins + module ResqueScheduler + module DelayedHelper + def format_time(t) + t.strftime('%Y-%m-%d %H:%M:%S %z') + end + end + end + end +end diff --git a/lib/resque/scheduler/engine/app/helpers/resque_web/plugins/resque_scheduler/schedules_helper.rb b/lib/resque/scheduler/engine/app/helpers/resque_web/plugins/resque_scheduler/schedules_helper.rb new file mode 100644 index 00000000..e4170605 --- /dev/null +++ b/lib/resque/scheduler/engine/app/helpers/resque_web/plugins/resque_scheduler/schedules_helper.rb @@ -0,0 +1,53 @@ +module ResqueWeb + module Plugins + module ResqueScheduler + module SchedulesHelper + def scheduled_in_this_env?(name) + return true if Resque.schedule[name]['rails_env'].nil? + rails_env(name).split(/[\s,]+/).include?(Resque::Scheduler.env) + end + + def rails_env(name) + Resque.schedule[name]['rails_env'] + end + + def schedule_interval_every(every) + every = [*every] + s = 'every: ' << every.first + + return s unless every.length > 1 + + s << ' (' + meta = every.last.map do |key, value| + "#{key.to_s.gsub(/_/, ' ')} #{value}" + end + s << meta.join(', ') << ')' + end + + def schedule_interval(config) + if config['every'] + schedule_interval_every(config['every']) + elsif config['cron'] + 'cron: ' + config['cron'].to_s + else + 'Not currently scheduled' + end + end + + def schedule_class(config) + if config['class'].nil? && !config['custom_job_class'].nil? + config['custom_job_class'] + else + config['class'] + end + end + + def queue_from_class_name(class_name) + Resque.queue_from_class( + Resque::Scheduler::Util.constantize(class_name) + ) + end + end + end + end +end diff --git a/lib/resque/scheduler/engine/app/views/resque_web/plugins/resque_scheduler/delayed/_next_more.erb b/lib/resque/scheduler/engine/app/views/resque_web/plugins/resque_scheduler/delayed/_next_more.erb new file mode 100644 index 00000000..784233df --- /dev/null +++ b/lib/resque/scheduler/engine/app/views/resque_web/plugins/resque_scheduler/delayed/_next_more.erb @@ -0,0 +1,23 @@ +<% # per_page was added in 1.23.1; gems which add to resque-server don't pass that variable along so it would crash %> +<% # without a default value %> +<% per_page ||= 20 %> +<% if start - per_page >= 0 || start + per_page <= size %> +
+ <% if start + per_page <= size %> + « + Next + <% end %> + + <% (size / per_page.to_f - 1).ceil.downto(0).each do |page_num| %> + <% if start == page_num * per_page %> + <%= page_num %> + <% else %> + <%= page_num %> + <% end %> + <% end %> + + <% if start - per_page >= 0 %> + Previous » + <% end %> +
+<% end %> \ No newline at end of file diff --git a/lib/resque/scheduler/server/views/search_form.erb b/lib/resque/scheduler/engine/app/views/resque_web/plugins/resque_scheduler/delayed/_search_form.erb similarity index 67% rename from lib/resque/scheduler/server/views/search_form.erb rename to lib/resque/scheduler/engine/app/views/resque_web/plugins/resque_scheduler/delayed/_search_form.erb index c150c67a..f89eee9a 100644 --- a/lib/resque/scheduler/server/views/search_form.erb +++ b/lib/resque/scheduler/engine/app/views/resque_web/plugins/resque_scheduler/delayed/_search_form.erb @@ -1,4 +1,4 @@ - diff --git a/lib/resque/scheduler/server/views/delayed.erb b/lib/resque/scheduler/engine/app/views/resque_web/plugins/resque_scheduler/delayed/index.erb similarity index 52% rename from lib/resque/scheduler/server/views/delayed.erb rename to lib/resque/scheduler/engine/app/views/resque_web/plugins/resque_scheduler/delayed/index.erb index 857d16cf..d5197e70 100644 --- a/lib/resque/scheduler/server/views/delayed.erb +++ b/lib/resque/scheduler/engine/app/views/resque_web/plugins/resque_scheduler/delayed/index.erb @@ -1,7 +1,7 @@This list below contains the timestamps for scheduled delayed jobs. @@ -12,7 +12,7 @@ Showing <%= start = params[:start].to_i %> to <%= start + 20 %> of <%= size %> timestamps
-Timestamp | @@ -21,28 +21,28 @@Args | All schedules | |||||
---|---|---|---|---|---|---|---|
- | -"><%= format_time(Time.at(timestamp)) %> | -<%= delayed_timestamp_size = resque.delayed_timestamp_size(timestamp) %> | - <% job = resque.delayed_timestamp_peek(timestamp, 0, 1).first %> +<%= format_time(Time.at(timestamp)) %> | +<%= delayed_timestamp_size = Resque.delayed_timestamp_size(timestamp) %> | + <% job = Resque.delayed_timestamp_peek(timestamp, 0, 1).first %><% if job && delayed_timestamp_size == 1 %> <%= h(job['class']) %> <% else %> - ">see details + see details <% end %> | <%= h(job['args'].inspect) if job && delayed_timestamp_size == 1 %> | <% if job %> - ">All schedules + All schedules <% end %> |
Timestamp | +
---|
+ <%= Time.at(t) %> + | +
There are no such jobs scheduled. | +
@@ -14,13 +14,13 @@ <% delayed.each do |job| %> | |
---|---|
- | - |