resque-scheduler-web 0.0.1 → 0.0.2

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 (36) hide show
  1. checksums.yaml +4 -4
  2. data/.gitignore +3 -3
  3. data/.rubocop.yml +1 -0
  4. data/.travis.yml +11 -0
  5. data/README.md +8 -2
  6. data/Rakefile +10 -1
  7. data/app/assets/javascripts/resque_web/plugins/resque_scheduler/application.js +0 -0
  8. data/app/assets/stylesheets/resque_web/plugins/resque_scheduler/application.css +3 -0
  9. data/app/controllers/resque_web/plugins/resque_scheduler/delayed_controller.rb +9 -1
  10. data/app/controllers/resque_web/plugins/resque_scheduler/schedules_controller.rb +7 -1
  11. data/app/helpers/resque_web/plugins/resque_scheduler/delayed_helper.rb +9 -0
  12. data/app/helpers/resque_web/plugins/resque_scheduler/schedules_helper.rb +29 -1
  13. data/app/models/resque_web/plugins/resque_scheduler/job_finder.rb +15 -9
  14. data/app/models/resque_web/plugins/resque_scheduler/job_finder/working_job_finder.rb +22 -5
  15. data/app/views/resque_web/plugins/resque_scheduler/delayed/index.erb +1 -1
  16. data/lib/resque/scheduler/web.rb +1 -1
  17. data/lib/resque/scheduler/web/version.rb +1 -1
  18. data/lib/resque_web/plugins/resque_scheduler/engine.rb +10 -6
  19. data/resque-scheduler-web.gemspec +10 -5
  20. data/spec/controllers/delayed_controller_spec.rb +10 -18
  21. data/spec/controllers/schedules_controller_spec.rb +28 -21
  22. data/spec/dummy/app/controllers/application_controller.rb +1 -0
  23. data/spec/dummy/config/application.rb +1 -0
  24. data/spec/dummy/log/test.log +5666 -0
  25. data/spec/features/navigation_spec.rb +1 -2
  26. data/spec/features/schedules/requeuing_a_job_with_parameters_spec.rb +8 -4
  27. data/spec/features/schedules/scheduled_jobs_page_spec.rb +8 -2
  28. data/spec/models/job_finder/working_job_finder_spec.rb +9 -7
  29. data/spec/models/job_finder_spec.rb +16 -13
  30. data/spec/rails_helper.rb +12 -9
  31. data/spec/routing/delayed_routing_spec.rb +5 -3
  32. data/spec/spec_helper.rb +6 -7
  33. data/spec/support/redis_instance.rb +13 -11
  34. data/spec/support/test_jobs.rb +9 -4
  35. metadata +68 -24
  36. data/spec/dummy/app/helpers/application_helper.rb +0 -2
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: 1e03854b76a62075cb549985fff801655ebea3d5
4
- data.tar.gz: c17f6ae62c750215da4aa0a57985a4187f7ff354
3
+ metadata.gz: 117651b5c62bac5f16c145b3f4aa0f6f38f3d9bc
4
+ data.tar.gz: 31af2fd0dc677d3014f097436dc1e7e2c06b577f
5
5
  SHA512:
6
- metadata.gz: 7a869d83a46db7b6e5e66e0090f0d54cc2fb5e61772b4512043e5c74ba486a729fb03ce775aa8eddf563e936aca433cc1847f4bcf2efd5c8f76c25cd5df84dd8
7
- data.tar.gz: b3a62b9f4cde28c559480b9aa452a4ab3ef8b984923d02417b01e66749a8aa7b734ced4949f8ba468018b83e339d1325ca71ff1592aa691dd9143d333dd1890f
6
+ metadata.gz: 7205b8b5e211acac1efc24d102e34fe6cb2f7c0ff5f1a187b608dedb22c7a071577e629b4bf13e8c380e00ec184e4a833455929558d6fb8b240ded5552ec1cec
7
+ data.tar.gz: f70ea78760c27134564163b973f2a900c6ae797f8357526f5bf0bb1abfea5c33fb2a147cf8afa04f6497ce068d7898afa16edabbea8779517d0124fdde72ea14
data/.gitignore CHANGED
@@ -12,9 +12,9 @@ lib/bundler/man
12
12
  pkg
13
13
  rdoc
14
14
  spec/reports
15
- test/tmp
16
- test/dummy/log
17
- test/version_tmp
15
+ spec/tmp
16
+ spec/dummy/log
17
+ spec/version_tmp
18
18
  tmp
19
19
  *.bundle
20
20
  *.so
data/.rubocop.yml ADDED
@@ -0,0 +1 @@
1
+ require: rubocop-rspec
data/.travis.yml ADDED
@@ -0,0 +1,11 @@
1
+ language: ruby
2
+ cache: bundler
3
+ rvm:
4
+ - 2.2.0
5
+ - 2.1.5
6
+ - 2.0.0
7
+ - 1.9.3
8
+
9
+ addons:
10
+ code_climate:
11
+ repo_token: 854dad5a427f26dc32dcfafd54d1824c8f052a31c4b11fa51b5181334e53a434
data/README.md CHANGED
@@ -1,5 +1,12 @@
1
1
  # Resque::Scheduler::Web
2
2
 
3
+ [![Gem Version](https://badge.fury.io/rb/resque-scheduler-web.svg)](http://badge.fury.io/rb/resque-scheduler-web)
4
+ [![Code Climate](https://codeclimate.com/github/mattgibson/resque-scheduler-web/badges/gpa.svg)](https://codeclimate.com/github/mattgibson/resque-scheduler-web)
5
+ [![Test Coverage](https://codeclimate.com/github/mattgibson/resque-scheduler-web/badges/coverage.svg)](https://codeclimate.com/github/mattgibson/resque-scheduler-web)
6
+ [![Inline docs](http://inch-ci.org/github/mattgibson/resque-scheduler-web.svg?branch=master)](http://inch-ci.org/github/mattgibson/resque-scheduler-web)
7
+ [![Dependency Status](https://gemnasium.com/mattgibson/resque-scheduler-web.svg)](https://gemnasium.com/mattgibson/resque-scheduler-web)
8
+ [![Build Status](https://travis-ci.org/mattgibson/resque-scheduler-web.svg?branch=master)](https://travis-ci.org/mattgibson/resque-scheduler-web)
9
+
3
10
  This gem provides tabs in [Resque Web](https://github.com/resque/resque-web)
4
11
  for managing [Resque Scheduler](https://github.com/resque/resque-scheduler). It uses the
5
12
  new Rails Engine approach, rather than the old Sinatra one.
@@ -28,8 +35,7 @@ Web engine mounted like this in routes.rb:
28
35
  ## Running the tests
29
36
 
30
37
  cd resque-scheduler-web
31
- bundle exec rspec spec
32
-
38
+ bundle exec rake
33
39
 
34
40
  ## Contributing
35
41
 
data/Rakefile CHANGED
@@ -1,2 +1,11 @@
1
- require "bundler/gem_tasks"
1
+ require 'bundler/gem_tasks'
2
2
 
3
+ begin
4
+ require 'rspec/core/rake_task'
5
+
6
+ RSpec::Core::RakeTask.new(:spec)
7
+
8
+ task default: :spec
9
+ rescue LoadError
10
+ puts 'RSpec is not installed!'
11
+ end
@@ -0,0 +1,3 @@
1
+ .container form {
2
+ margin-top: 0;
3
+ }
@@ -5,6 +5,7 @@ module ResqueWeb
5
5
  # application, so here, they can be run immediately, deleted from the
6
6
  # queue, or rescheduled.
7
7
  class DelayedController < ResqueWeb::ApplicationController
8
+ # GET /delayed
8
9
  def index
9
10
  @start = params[:start].to_i
10
11
  @number_to_show = 20
@@ -12,6 +13,9 @@ module ResqueWeb
12
13
  @timestamps = Resque.delayed_queue_peek(@start, @number_to_show)
13
14
  end
14
15
 
16
+ # GET /delayed/jobs/:klass
17
+ # Shows us all of the jobs of this type, with these args. Accessed by
18
+ # clicking the 'All schedules' link next to a delayed job.
15
19
  def jobs_klass
16
20
  klass = Resque::Scheduler::Util.constantize(params[:klass])
17
21
  @args = JSON.load(URI.decode(params[:args]))
@@ -20,10 +24,12 @@ module ResqueWeb
20
24
  @timestamps = []
21
25
  end
22
26
 
27
+ # POST /delayed/search
23
28
  def search
24
29
  @jobs = JobFinder.new(params[:search]).find_jobs
25
30
  end
26
31
 
32
+ # POST /delayed/cancel_now
27
33
  def cancel_now
28
34
  klass = Resque::Scheduler::Util.constantize(params['klass'])
29
35
  timestamp = params['timestamp']
@@ -32,11 +38,13 @@ module ResqueWeb
32
38
  redirect_to Engine.app.url_helpers.delayed_path
33
39
  end
34
40
 
41
+ # POST /delayed/clear
35
42
  def clear
36
43
  Resque.reset_delayed_queue
37
44
  redirect_to Engine.app.url_helpers.delayed_path
38
45
  end
39
46
 
47
+ # POST /delayed/queue_now
40
48
  def queue_now
41
49
  timestamp = params['timestamp'].to_i
42
50
  if timestamp > 0
@@ -45,10 +53,10 @@ module ResqueWeb
45
53
  redirect_to ResqueWeb::Engine.app.url_helpers.overview_path
46
54
  end
47
55
 
56
+ # GET /delayed/:timestamp
48
57
  def timestamp
49
58
  @timestamp = params[:timestamp].to_i
50
59
  end
51
-
52
60
  end
53
61
  end
54
62
  end
@@ -3,10 +3,13 @@ require 'resque/scheduler/server'
3
3
  module ResqueWeb
4
4
  module Plugins
5
5
  module ResqueScheduler
6
+ # Controller for the schedule. If it is dynamic, then the actions allow
7
+ # the jobs to be destroyed. Otherwise, the jobs can be manually queued
8
+ # for immediate execution.
6
9
  class SchedulesController < ResqueWeb::ApplicationController
7
-
8
10
  include Resque::Scheduler::Server::HelperMethods
9
11
 
12
+ # GET /schedule
10
13
  def index
11
14
  Resque.reload_schedule! if Resque::Scheduler.dynamic
12
15
  jobs_in_this_env = Resque.schedule.select do |name|
@@ -18,6 +21,7 @@ module ResqueWeb
18
21
  end
19
22
  end
20
23
 
24
+ # DELETE /schedule
21
25
  def destroy
22
26
  if Resque::Scheduler.dynamic
23
27
  job_name = params['job_name'] || params[:job_name]
@@ -26,6 +30,7 @@ module ResqueWeb
26
30
  redirect_to Engine.app.url_helpers.schedules_path
27
31
  end
28
32
 
33
+ # POST /schedule/requeue
29
34
  def requeue
30
35
  @job_name = params['job_name'] || params[:job_name]
31
36
  config = Resque.schedule[@job_name]
@@ -38,6 +43,7 @@ module ResqueWeb
38
43
  end
39
44
  end
40
45
 
46
+ # POST /schedule/requeue_with_params
41
47
  def requeue_with_params
42
48
  job_name = params['job_name'] || params[:job_name]
43
49
  config = Resque.schedule[job_name]
@@ -1,7 +1,16 @@
1
1
  module ResqueWeb
2
2
  module Plugins
3
3
  module ResqueScheduler
4
+ # Helper methods for the delayed jobs UI
4
5
  module DelayedHelper
6
+ # Outputs the time in a human readable way.
7
+ #
8
+ # @example
9
+ # format_time(Time.at(timestamp))
10
+ #
11
+ # @param t [Time]
12
+ # @return [String] A string in this format: 2015-04-12 12:27:05 +0100
13
+ #
5
14
  def format_time(t)
6
15
  t.strftime('%Y-%m-%d %H:%M:%S %z')
7
16
  end
@@ -1,16 +1,31 @@
1
1
  module ResqueWeb
2
2
  module Plugins
3
3
  module ResqueScheduler
4
+ # Helper methods for the schedule UI
4
5
  module SchedulesHelper
6
+ # Tells us whether this job is scheduled for e.g. the production env.
7
+ # Jobs for other environments may be in Redis but should be ignored.
8
+ #
9
+ # @param [String] name
10
+ # @return [true, false]
5
11
  def scheduled_in_this_env?(name)
6
12
  return true if Resque.schedule[name]['rails_env'].nil?
7
13
  rails_env(name).split(/[\s,]+/).include?(Resque::Scheduler.env)
8
14
  end
9
15
 
16
+ # Returns the Rails env for the Resque schedule
17
+ #
18
+ # @param [String] name
19
+ # @return [String]
10
20
  def rails_env(name)
11
21
  Resque.schedule[name]['rails_env']
12
22
  end
13
23
 
24
+ # Outputs a human readable string showing the schedule for a job when it
25
+ # it configured for every X interval.
26
+ #
27
+ # @param [Array] every
28
+ # @return [String]
14
29
  def schedule_interval_every(every)
15
30
  every = [*every]
16
31
  s = 'every: ' << every.first
@@ -24,6 +39,11 @@ module ResqueWeb
24
39
  s << meta.join(', ') << ')'
25
40
  end
26
41
 
42
+ # Outputs a human readable string for the UI, showing when the job is
43
+ # scheduled.
44
+ #
45
+ # @param [Hash] config Config hash for one job
46
+ # @return [String]
27
47
  def schedule_interval(config)
28
48
  if config['every']
29
49
  schedule_interval_every(config['every'])
@@ -34,6 +54,10 @@ module ResqueWeb
34
54
  end
35
55
  end
36
56
 
57
+ # Retrieves the class name of the job from the job config and returns it
58
+ #
59
+ # @param [Hash] config
60
+ # @return [String]
37
61
  def schedule_class(config)
38
62
  if config['class'].nil? && !config['custom_job_class'].nil?
39
63
  config['custom_job_class']
@@ -42,9 +66,13 @@ module ResqueWeb
42
66
  end
43
67
  end
44
68
 
69
+ # Returns the name of the queue that a given class uses.
70
+ #
71
+ # @param [String] class_name
72
+ # @return [String]
45
73
  def queue_from_class_name(class_name)
46
74
  Resque.queue_from_class(
47
- Resque::Scheduler::Util.constantize(class_name)
75
+ Resque::Scheduler::Util.constantize(class_name)
48
76
  )
49
77
  end
50
78
  end
@@ -4,14 +4,19 @@ module ResqueWeb
4
4
  # This class exists to find jobs which match a search term. They may be
5
5
  # being processed, in the queue, or delayed.
6
6
  class JobFinder
7
-
7
+ # The search term that the user entered.
8
8
  attr_accessor :search_term
9
9
 
10
+ # @param [String] search_term
10
11
  def initialize(search_term = nil)
11
12
  @search_term = search_term || ''
12
13
  @search_term.downcase!
13
14
  end
14
15
 
16
+ # Finds all jobs that match the search term supplied when the class was
17
+ # initialized.
18
+ #
19
+ # @return [Array]
15
20
  def find_jobs
16
21
  return [] if search_term.empty?
17
22
  results = []
@@ -20,13 +25,15 @@ module ResqueWeb
20
25
  results + queued_jobs_where_class_name_matches_search_term
21
26
  end
22
27
 
28
+ protected
29
+
23
30
  def working_jobs_where_class_name_contains_search_term
24
31
  WorkingJobFinder.new(search_term).find_jobs
25
32
  end
26
33
 
27
34
  def delayed_jobs_where_class_name_contains_search_term
28
- delayed_job_timestamps.inject([]) do |matching_jobs, timestamp|
29
- matching_jobs + delayed_jobs_for_timestamp_that_match_search_term(timestamp)
35
+ delayed_job_timestamps.inject([]) do |jobs, timestamp|
36
+ jobs + delayed_jobs_for_timestamp_that_match_search_term(timestamp)
30
37
  end
31
38
  end
32
39
 
@@ -67,15 +74,14 @@ module ResqueWeb
67
74
  end
68
75
 
69
76
  def queued_jobs_from_queue(queue)
70
- bits = Resque.peek(queue, 0, Resque.size(queue))
71
- if bits.is_a? Array
72
- bits
77
+ jobs = Resque.peek(queue, 0, Resque.size(queue))
78
+ if jobs.is_a? Array
79
+ jobs
73
80
  else
74
- [bits]
81
+ [jobs]
75
82
  end
76
83
  end
77
-
78
84
  end
79
85
  end
80
86
  end
81
- end
87
+ end
@@ -4,15 +4,32 @@ module ResqueWeb
4
4
  class JobFinder
5
5
  # This class finds working jobs that Resque is currently processing
6
6
  class WorkingJobFinder
7
-
7
+ # The terms that the user entered.
8
8
  attr_accessor :search_term
9
9
 
10
+ # The search term will be used to match against the class name of any
11
+ # jobs that are currently being processed by any of the workers.
12
+ #
13
+ # @param search_term [String]
10
14
  def initialize(search_term)
11
15
  @search_term = search_term
12
16
  end
13
17
 
18
+ # Finds all jobs that match the search term provided when the class
19
+ # was instantiated.
20
+ #
21
+ # [
22
+ # {
23
+ # 'class' => 'SomeClass',
24
+ # 'queue' => 'some_queue',
25
+ # 'where_at' => 'working'
26
+ # }
27
+ # ]
28
+ #
29
+ # @return [Array] Returns an array of hashes.
30
+ #
14
31
  def find_jobs
15
- workers_with_jobs_that_match_search_term.collect do |w|
32
+ workers_with_jobs_that_match_search_term.map do |w|
16
33
  w.job['payload'].merge(
17
34
  'queue' => w.job['queue'],
18
35
  'where_at' => 'working'
@@ -20,6 +37,8 @@ module ResqueWeb
20
37
  end
21
38
  end
22
39
 
40
+ protected
41
+
23
42
  def workers_with_jobs_that_match_search_term
24
43
  all_working_jobs.select do |w|
25
44
  w.job &&
@@ -28,8 +47,6 @@ module ResqueWeb
28
47
  end
29
48
  end
30
49
 
31
- protected
32
-
33
50
  def all_working_jobs
34
51
  [*Resque.working]
35
52
  end
@@ -37,4 +54,4 @@ module ResqueWeb
37
54
  end
38
55
  end
39
56
  end
40
- end
57
+ end
@@ -23,7 +23,7 @@
23
23
  <th>All schedules</th>
24
24
  </tr>
25
25
  <% @timestamps.each do |timestamp| %>
26
- <tr>
26
+ <tr class="delayed-job">
27
27
  <td>
28
28
  <form action="<%= queue_now_path %>" method="post">
29
29
  <input type="hidden" name="timestamp" value="<%= timestamp.to_i %>">
@@ -1,4 +1,4 @@
1
- require "resque/scheduler/web/version"
1
+ require 'resque/scheduler/web/version'
2
2
 
3
3
  require 'resque_web'
4
4
  require 'resque/scheduler'
@@ -1,7 +1,7 @@
1
1
  module Resque
2
2
  module Scheduler
3
3
  module Web
4
- VERSION = "0.0.1"
4
+ VERSION = '0.0.2'
5
5
  end
6
6
  end
7
7
  end
@@ -3,16 +3,12 @@ require 'resque_web'
3
3
  module ResqueWeb
4
4
  module Plugins
5
5
  module ResqueScheduler
6
+ # Main engine class for the Resque Scheduler Web plugin.
6
7
  class Engine < ::Rails::Engine
7
8
  isolate_namespace ResqueWeb::Plugins::ResqueScheduler
8
-
9
- # paths['app'] << 'app'
10
- # paths['app/helpers'] << 'app/helpers'
11
- # paths['app/views'] << 'app/views'
12
- # paths['app/controllers'] << 'app/controllers'
13
- # paths['app/models'] << 'app/models'
14
9
  end
15
10
 
11
+ # Draws the routes for the engine.
16
12
  Engine.routes do
17
13
  get 'schedule', to: 'schedules#index', as: 'schedules'
18
14
  post 'schedule/requeue', to: 'schedules#requeue', as: 'requeue'
@@ -32,10 +28,18 @@ module ResqueWeb
32
28
  post '/delayed/clear', to: 'delayed#clear', as: 'clear'
33
29
  end
34
30
 
31
+ # provides the path where the engine will live. This is appended after
32
+ # the main resque-web path.
33
+ #
34
+ # @return [String]
35
35
  def self.engine_path
36
36
  '/scheduler'
37
37
  end
38
38
 
39
+ # Tells Resque web what extra tabs to ass to the main navigation at the
40
+ # top of the resque-web interface.
41
+ #
42
+ # @return [Array]
39
43
  def self.tabs
40
44
  [
41
45
  {