sidekiq-cron 2.1.0 → 2.2.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.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 1d5f570d2d2d72cdb4fc1a2458dc6cae7abfa5a0da1f27915310b5d5dc835e89
4
- data.tar.gz: 514d74f88c65af3db1956190ca9092d4f1a95d6bce4b0a9191463e2bb0f9181a
3
+ metadata.gz: fcff473f7500a6ff2d006bb8af760d697b93aec6090b18e891f63a7b491396e2
4
+ data.tar.gz: 03a0e5508ee4f31e9c437c253bef8411a25de83deeb6e8c5eb18ccf84e836b50
5
5
  SHA512:
6
- metadata.gz: 61f4af041526789dcf51264baa88a5e1855fa124a0fe9f2c5ed04eec36bd4b617aae1152890ab281d5938914725ba9cce812f70bc258a6e4b8d82b642882212a
7
- data.tar.gz: 9e82488bd6459b3ce373e52c94fc3607631b5fc67fa58e578d190368a09f4edc3b4502318646d5285e9fb9d139a080d90d560b28ad31a56e9d01d81d1dc0a2f8
6
+ metadata.gz: 10d1500431656322f8f33feeec633bda703f601b98f1bc3e7f35e4ccfc93fef4fa4608d750a488282c0d02d274d9b2775969c1c072ebdd74292b00a6687593b8
7
+ data.tar.gz: 99aa76218a9acf896e10b801398ba5a6b4935ed33b24bf8fa5be25b0a30bf2c3c5afe2dd7cc30b7ad4b665ed827c1adc9fb48e5bb3987de60513ce334895fbda
data/CHANGELOG.md CHANGED
@@ -2,6 +2,14 @@
2
2
 
3
3
  All notable changes to this project will be documented in this file.
4
4
 
5
+ ## 2.2.0
6
+
7
+ - Add support for Sidekiq v8 (https://github.com/sidekiq-cron/sidekiq-cron/pull/531, https://github.com/sidekiq-cron/sidekiq-cron/pull/538)
8
+ - Always show parsed cron expression in web UI (https://github.com/sidekiq-cron/sidekiq-cron/pull/535)
9
+ - Add fallback to .yaml extension (https://github.com/sidekiq-cron/sidekiq-cron/pull/534)
10
+ - Refactor constantize helper to use Object.const_get (https://github.com/sidekiq-cron/sidekiq-cron/pull/541)
11
+ - Allow testing of schedule by library consumers (https://github.com/sidekiq-cron/sidekiq-cron/pull/543)
12
+
5
13
  ## 2.1.0
6
14
 
7
15
  - Add `available_namespaces` configuration option (https://github.com/sidekiq-cron/sidekiq-cron/pull/524)
data/Gemfile CHANGED
@@ -5,5 +5,5 @@ gemspec
5
5
  # To test different Sidekiq versions
6
6
  gem "sidekiq", ENV.fetch("SIDEKIQ_VERSION", ">= 6")
7
7
 
8
- # To test different Active Job versions
9
- gem "activejob", ENV.fetch("ACTIVE_JOB_VERSION", "~> 7")
8
+ # To test different Rails versions
9
+ gem "rails", ENV.fetch("RAILS_VERSION", "~> 7")
data/README.md CHANGED
@@ -73,9 +73,9 @@ Sidekiq::Cron.configure do |config|
73
73
  config.cron_schedule_file = 'config/my_schedule.yml' # Default is 'config/schedule.yml'
74
74
  config.cron_history_size = 20 # Default is 10
75
75
  config.default_namespace = 'statistics' # Default is 'default'
76
+ config.available_namespaces = %w[statistics maintenance billing] # Default is `nil`
76
77
  config.natural_cron_parsing_mode = :strict # Default is :single
77
78
  config.reschedule_grace_period = 300 # Default is 60
78
- config.available_namespaces = %w[maintenance billing] # Default is `nil`
79
79
  end
80
80
  ```
81
81
 
@@ -511,6 +511,45 @@ Sidekiq::Cron.configure do |config|
511
511
  end
512
512
  ```
513
513
 
514
+ ## Testing your configuration
515
+
516
+ You can test your application's configuration by loading the schedule in your test suite. Below is an example using RSpec in a Rails project:
517
+
518
+ ```ruby
519
+ # spec/cron_schedule_spec.rb
520
+ require "rails_helper"
521
+
522
+ RSpec.describe "Cron Schedule" do
523
+ let(:schedule_loader) { Sidekiq::Cron::ScheduleLoader.new }
524
+ let(:all_jobs) { Sidekiq::Cron::Job.all }
525
+
526
+ # Confirms that `config.cron_schedule_file` points to a real file.
527
+ it "has a schedule file" do
528
+ expect(schedule_loader).to have_schedule_file
529
+ end
530
+
531
+ # Confirms that no jobs in the schedule have an invalid cron string.
532
+ it "does not return any errors" do
533
+ expect(schedule_loader.load).to be_empty
534
+ end
535
+
536
+ # May be subject to churn, but adds confidence.
537
+ it "adds the expected number of jobs" do
538
+ schedule_loader.load
539
+ expect(all_jobs.size).to eq 5
540
+ end
541
+
542
+ # Confirms that all job classes exist.
543
+ it "has a valid class for each added job" do
544
+ schedule_loader.load
545
+ # Shows that all classes exist (as we can constantize the names without raising).
546
+ job_classes = all_jobs.map { |job| job.klass.constantize }
547
+ # Naive check that classes are sidekiq jobs (as they all have `.perfrom_async`).
548
+ expect(job_classes).to all(respond_to(:perform_async))
549
+ end
550
+ end
551
+ ```
552
+
514
553
  ## Contributing
515
554
 
516
555
  **Thanks to all [contributors](https://github.com/sidekiq-cron/sidekiq-cron/graphs/contributors), you’re awesome and this wouldn’t be possible without you!**
@@ -18,7 +18,7 @@ module Sidekiq
18
18
  GLOBALID_KEY = "_sc_globalid"
19
19
 
20
20
  attr_accessor :name, :namespace, :cron, :description, :klass, :args, :message
21
- attr_reader :last_enqueue_time, :fetch_missing_args, :source
21
+ attr_reader :cron_expression_string, :last_enqueue_time, :fetch_missing_args, :source
22
22
 
23
23
  def initialize input_args = {}
24
24
  args = Hash[input_args.map{ |k, v| [k.to_s, v] }]
@@ -132,12 +132,7 @@ module Sidekiq
132
132
  def enqueue! time = Time.now.utc
133
133
  @last_enqueue_time = time
134
134
 
135
- klass_const =
136
- begin
137
- Sidekiq::Cron::Support.constantize(@klass.to_s)
138
- rescue NameError
139
- nil
140
- end
135
+ klass_const = Sidekiq::Cron::Support.safe_constantize(@klass.to_s)
141
136
 
142
137
  jid =
143
138
  if klass_const
@@ -160,9 +155,10 @@ module Sidekiq
160
155
  end
161
156
 
162
157
  def is_active_job?(klass = nil)
163
- @active_job || defined?(::ActiveJob::Base) && (klass || Sidekiq::Cron::Support.constantize(@klass.to_s)) < ::ActiveJob::Base
164
- rescue NameError
165
- false
158
+ @active_job || defined?(::ActiveJob::Base) && begin
159
+ klass ||= Sidekiq::Cron::Support.safe_constantize(@klass.to_s)
160
+ klass ? klass < ::ActiveJob::Base : false
161
+ end
166
162
  end
167
163
 
168
164
  def date_as_argument?
@@ -600,6 +596,10 @@ module Sidekiq
600
596
  @args = parse_args(args)
601
597
  end
602
598
 
599
+ def cron_expression_string
600
+ parsed_cron.to_cron_s
601
+ end
602
+
603
603
  private
604
604
 
605
605
  def parsed_cron
@@ -800,11 +800,7 @@ module Sidekiq
800
800
  end
801
801
 
802
802
  def get_job_options(klass, args)
803
- klass = klass.is_a?(Class) ? klass : begin
804
- Sidekiq::Cron::Support.constantize(klass)
805
- rescue NameError
806
- # noop
807
- end
803
+ klass = klass.is_a?(Class) ? klass : Sidekiq::Cron::Support.safe_constantize(klass)
808
804
 
809
805
  if klass.nil?
810
806
  # Unknown class
@@ -1,16 +1,56 @@
1
- Sidekiq.configure_server do |config|
2
- schedule_file = Sidekiq::Cron.configuration.cron_schedule_file
3
-
4
- if File.exist?(schedule_file)
5
- config.on(:startup) do
6
- schedule = Sidekiq::Cron::Support.load_yaml(ERB.new(IO.read(schedule_file)).result)
7
- if schedule.kind_of?(Hash)
8
- Sidekiq::Cron::Job.load_from_hash!(schedule, source: "schedule")
9
- elsif schedule.kind_of?(Array)
10
- Sidekiq::Cron::Job.load_from_array!(schedule, source: "schedule")
11
- else
12
- raise "Not supported schedule format. Confirm your #{schedule_file}"
1
+ module Sidekiq
2
+ module Cron
3
+ class ScheduleLoader
4
+ def load_schedule
5
+ if schedule.is_a?(Hash)
6
+ Sidekiq::Cron::Job.load_from_hash!(schedule, source: "schedule")
7
+ elsif schedule.is_a?(Array)
8
+ Sidekiq::Cron::Job.load_from_array!(schedule, source: "schedule")
9
+ else
10
+ raise "Not supported schedule format. Confirm your #{schedule_file_name}"
11
+ end
12
+ end
13
+
14
+ def has_schedule_file?
15
+ File.exist?(schedule_file_name)
16
+ end
17
+
18
+ private
19
+
20
+ def schedule
21
+ @schedule ||= Sidekiq::Cron::Support.load_yaml(rendered_schedule_template)
22
+ end
23
+
24
+ def rendered_schedule_template
25
+ ERB.new(schedule_file_content).result
26
+ end
27
+
28
+ def schedule_file_content
29
+ IO.read(schedule_file_name)
30
+ end
31
+
32
+ def schedule_file_name
33
+ @schedule_file_name ||= yml_to_yaml_unless_file_exists(schedule_file_name_from_config)
34
+ end
35
+
36
+ def schedule_file_name_from_config
37
+ Sidekiq::Cron.configuration.cron_schedule_file
38
+ end
39
+
40
+ def yml_to_yaml_unless_file_exists(file_name)
41
+ if File.exist?(file_name)
42
+ file_name
43
+ else
44
+ file_name.sub(/\.yml$/, ".yaml")
45
+ end
13
46
  end
14
47
  end
15
48
  end
16
49
  end
50
+
51
+ Sidekiq.configure_server do |config|
52
+ schedule_loader = Sidekiq::Cron::ScheduleLoader.new
53
+ break unless schedule_loader.has_schedule_file?
54
+
55
+ config.on(:startup) { schedule_loader.load_schedule }
56
+ end
@@ -1,35 +1,10 @@
1
1
  module Sidekiq
2
2
  module Cron
3
3
  module Support
4
- # Inspired by Active Support Inflector
5
- def self.constantize(camel_cased_word)
6
- names = camel_cased_word.split("::".freeze)
7
-
8
- # Trigger a built-in NameError exception including the ill-formed constant in the message.
9
- Object.const_get(camel_cased_word) if names.empty?
10
-
11
- # Remove the first blank element in case of '::ClassName' notation.
12
- names.shift if names.size > 1 && names.first.empty?
13
-
14
- names.inject(Object) do |constant, name|
15
- if constant == Object
16
- constant.const_get(name)
17
- else
18
- candidate = constant.const_get(name)
19
- next candidate if constant.const_defined?(name, false)
20
- next candidate unless Object.const_defined?(name)
21
-
22
- # Go down the ancestors to check if it is owned directly. The check
23
- # stops when we reach Object or the end of ancestors tree.
24
- constant = constant.ancestors.inject(constant) do |const, ancestor|
25
- break const if ancestor == Object
26
- break ancestor if ancestor.const_defined?(name, false)
27
- const
28
- end
29
-
30
- constant.const_get(name, false)
31
- end
32
- end
4
+ def self.safe_constantize(klass_name)
5
+ Object.const_get(klass_name)
6
+ rescue NameError
7
+ nil
33
8
  end
34
9
 
35
10
  def self.load_yaml(src)
@@ -2,6 +2,6 @@
2
2
 
3
3
  module Sidekiq
4
4
  module Cron
5
- VERSION = "2.1.0"
5
+ VERSION = "2.2.0"
6
6
  end
7
7
  end
@@ -1,113 +1,103 @@
1
- <header class='row'>
2
- <div class='col-sm-5 pull-left'>
3
- <h3>
1
+ <section>
2
+ <header>
3
+ <h2>
4
4
  <%= t('CronJobs') %>
5
- <small><%= @current_namespace %></small>
6
- </h3>
7
- </div>
8
- <div class='col-sm-7 pull-right h2'>
5
+ <small>(<%= @current_namespace %>)</small>
6
+ </h2>
9
7
  <% if @cron_jobs.size > 0 %>
10
- <form action="<%= root_path %>cron/namespaces/<%= @current_namespace %>/all/delete" method="post" class="pull-right">
11
- <%= csrf_tag %>
12
- <input class="btn btn-danger" type="submit" name="delete" value="<%= t('DeleteAll') %>" data-confirm="<%= t('AreYouSureDeleteCronJobs') %>" />
13
- </form>
14
- <form action="<%= root_path %>cron/namespaces/<%= @current_namespace %>/all/disable" method="post" class="pull-right">
15
- <%= csrf_tag %>
16
- <input class="btn btn-warn" type="submit" name="enqueue" value="<%= t('DisableAll') %>" />
17
- </form>
18
- <form action="<%= root_path %>cron/namespaces/<%= @current_namespace %>/all/enable" method="post" class="pull-right">
19
- <%= csrf_tag %>
20
- <input class="btn btn-warn" type="submit" name="enqueue" value="<%= t('EnableAll') %>" />
21
- </form>
22
- <form action="<%= root_path %>cron/namespaces/<%= @current_namespace %>/all/enqueue" method="post" class="pull-right">
23
- <%= csrf_tag %>
24
- <input class="btn btn-warn" type="submit" name="enqueue" value="<%= t('EnqueueAll') %>" data-confirm="<%= t('AreYouSureEnqueueCronJobs') %>" />
8
+ <form class="filter">
9
+ <form action="<%= root_path %>cron/namespaces/<%= @current_namespace %>/all/delete" method="post">
10
+ <%= csrf_tag %>
11
+ <input class="btn btn-danger" type="submit" name="delete" value="<%= t('DeleteAll') %>" data-confirm="<%= t('AreYouSureDeleteCronJobs') %>" />
12
+ </form>
13
+ <form action="<%= root_path %>cron/namespaces/<%= @current_namespace %>/all/disable" method="post">
14
+ <%= csrf_tag %>
15
+ <input class="btn btn-primary" type="submit" name="enqueue" value="<%= t('DisableAll') %>" />
16
+ </form>
17
+ <form action="<%= root_path %>cron/namespaces/<%= @current_namespace %>/all/enable" method="post">
18
+ <%= csrf_tag %>
19
+ <input class="btn btn-primary" type="submit" name="enqueue" value="<%= t('EnableAll') %>" />
20
+ </form>
21
+ <form action="<%= root_path %>cron/namespaces/<%= @current_namespace %>/all/enqueue" method="post">
22
+ <%= csrf_tag %>
23
+ <input class="btn btn-primary" type="submit" name="enqueue" value="<%= t('EnqueueAll') %>" data-confirm="<%= t('AreYouSureEnqueueCronJobs') %>" />
24
+ </form>
25
25
  </form>
26
26
  <% end %>
27
+ </header>
28
+ <!-- Namespaces -->
29
+ <div class="cards-container">
30
+ <% Sidekiq::Cron::Namespace.all_with_count.sort_by { |namespace| namespace[:name] }.each do |namespace| %>
31
+ <article>
32
+ <a href="<%= root_path %>cron/namespaces/<%= namespace[:name] %>">
33
+ <span class="count"><%= namespace[:count] %></span>
34
+ <span class="desc"><%= namespace[:name] %></span>
35
+ </a>
36
+ </article>
37
+ <% end %>
27
38
  </div>
28
- </header>
29
-
30
- <!-- Namespaces -->
31
- <div class='row'>
32
- <div class="col-sm-12 summary_bar">
33
- <ul class="list-unstyled summary row">
34
- <% Sidekiq::Cron::Namespace.all_with_count.sort_by { |namespace| namespace[:name] }.each do |namespace| %>
35
- <li class="col-sm-1">
36
- <a href="<%= root_path %>cron/namespaces/<%= namespace[:name] %>">
37
- <span class="count"><%= namespace[:count] %></span>
38
- <span class="desc"><%= namespace[:name] %></span>
39
- </a>
40
- </li>
41
- <% end %>
42
- </ul>
43
- </div>
44
- </div>
45
- <!-- Namespaces -->
46
-
47
- <% if @cron_jobs.size > 0 %>
48
- <table class="table table-hover table-bordered table-striped table-white">
49
- <thead>
50
- <tr>
51
- <th><%= t('Status') %></th>
52
- <th width="50%"><%= t('Name') %></th>
53
- <th><%= t('CronString') %></th>
54
- <th><%= t('LastEnqueued') %></th>
55
- <th width="180"><%= t('Actions') %></th>
56
- </tr>
57
- </thead>
58
-
59
- <tbody>
60
- <% @cron_jobs.sort{ |a,b| a.sort_name <=> b.sort_name }.each do |job| %>
61
- <% klass = (job.status == 'disabled') ? 'bg-danger text-muted' : '' %>
62
- <% escaped_job_name = CGI.escape(job.name).gsub('+', '%20') %>
39
+ <!-- Namespaces -->
40
+ <% if @cron_jobs.size > 0 %>
41
+ <table class="table table-hover table-bordered table-striped table-white">
42
+ <thead>
63
43
  <tr>
64
- <td class="<%= klass %>"><%= t job.status %></td>
65
- <td class="<%= klass %>">
66
- <a href="<%= root_path %>cron/namespaces/<%= job.namespace %>/jobs/<%= escaped_job_name %>" title="<%= job.description %>">
67
- <b class="<%= klass %>"><%= job.name %></b>
68
- </a>
69
- <br/>
70
- <% if job.message and job.message.to_s.size > 100 %>
71
- <details>
72
- <summary class="btn btn-warn btn-xs">Show message</summary>
73
- <p><small><%= job.message %></small></p>
74
- </details>
75
- <% else %>
76
- <small><%= job.message %></small>
77
- <% end %>
78
- </td>
79
- <td class="<%= klass %>"><b><%= job.human_cron %><br/><small><%= job.cron.gsub(" ", "&nbsp;") %></small></b></td>
80
- <td class="<%= klass %>"><%= job.last_enqueue_time ? relative_time(job.last_enqueue_time) : "-" %></td>
81
- <td class="<%= klass %>">
82
- <% if job.status == 'enabled' %>
83
- <form action="<%= root_path %>cron/namespaces/<%= job.namespace %>/jobs/<%= escaped_job_name %>/enqueue" method="post">
84
- <%= csrf_tag %>
85
- <input class='btn btn-warn btn-xs pull-left' type="submit" name="enqueue" value="<%= t('EnqueueNow') %>" data-confirm="<%= t('AreYouSureEnqueueCronJob', :job => job.name) %>"/>
86
- </form>
87
- <form action="<%= root_path %>cron/namespaces/<%= job.namespace %>/jobs/<%= escaped_job_name %>/disable" method="post">
88
- <%= csrf_tag %>
89
- <input class='btn btn-warn btn-xs pull-left' type="submit" name="disable" value="<%= t('Disable') %>"/>
90
- </form>
91
- <% else %>
92
- <form action="<%= root_path %>cron/namespaces/<%= job.namespace %>/jobs/<%= escaped_job_name %>/enqueue" method="post">
93
- <%= csrf_tag %>
94
- <input class='btn btn-warn btn-xs pull-left' type="submit" name="enqueue" value="<%= t('EnqueueNow') %>" data-confirm="<%= t('AreYouSureEnqueueCronJob', :job => job.name) %>"/>
95
- </form>
96
- <form action="<%= root_path %>cron/namespaces/<%= job.namespace %>/jobs/<%= escaped_job_name %>/enable" method="post">
97
- <%= csrf_tag %>
98
- <input class='btn btn-warn btn-xs pull-left' type="submit" name="enable" value="<%= t('Enable') %>"/>
99
- </form>
100
- <form action="<%= root_path %>cron/namespaces/<%= job.namespace %>/jobs/<%= escaped_job_name %>/delete" method="post">
101
- <%= csrf_tag %>
102
- <input class='btn btn-xs btn-danger pull-left help-block' type="submit" name="delete" value="<%= t('Delete') %>" data-confirm="<%= t('AreYouSureDeleteCronJob', :job => job.name) %>"/>
103
- </form>
104
- <% end %>
105
- </td>
44
+ <th><%= t('Status') %></th>
45
+ <th width="50%"><%= t('Name') %></th>
46
+ <th><%= t('CronString') %></th>
47
+ <th><%= t('LastEnqueued') %></th>
48
+ <th width="180"><%= t('Actions') %></th>
106
49
  </tr>
107
- <% end %>
108
- </tbody>
109
- </table>
110
- <% else %>
111
- <div class='alert alert-success'><%= t('NoCronJobsWereFound') %></div>
112
- <% end %>
113
-
50
+ </thead>
51
+ <tbody>
52
+ <% @cron_jobs.sort{ |a,b| a.sort_name <=> b.sort_name }.each do |job| %>
53
+ <% klass = (job.status == 'disabled') ? 'bg-danger text-muted' : '' %>
54
+ <% escaped_job_name = CGI.escape(job.name).gsub('+', '%20') %>
55
+ <tr>
56
+ <td class="<%= klass %>"><%= t job.status %></td>
57
+ <td class="<%= klass %>">
58
+ <a href="<%= root_path %>cron/namespaces/<%= job.namespace %>/jobs/<%= escaped_job_name %>" title="<%= job.description %>">
59
+ <b class="<%= klass %>"><%= job.name %></b>
60
+ </a>
61
+ <br/>
62
+ <% if job.message and job.message.to_s.size > 100 %>
63
+ <details>
64
+ <p><small><%= job.message %></small></p>
65
+ </details>
66
+ <% else %>
67
+ <small><%= job.message %></small>
68
+ <% end %>
69
+ </td>
70
+ <td class="<%= klass %>"><b><%= job.human_cron %><br/>
71
+ <small><%= job.cron.gsub(" ", "&nbsp;") %></small></b></td>
72
+ <td class="<%= klass %>"><%= job.last_enqueue_time ? relative_time(job.last_enqueue_time) : "-" %></td>
73
+ <td class="<%= klass %>">
74
+ <div class="pagination" style="padding: 0px">
75
+ <form action="<%= root_path %>cron/namespaces/<%= job.namespace %>/jobs/<%= escaped_job_name %>/enqueue" method="post">
76
+ <%= csrf_tag %>
77
+ <input class='btn btn-warn' type="submit" name="enqueue" value="<%= t('EnqueueNow') %>" data-confirm="<%= t('AreYouSureEnqueueCronJob', :job => job.name) %>"/>
78
+ </form>
79
+ <% if job.status == 'enabled' %>
80
+ <form action="<%= root_path %>cron/namespaces/<%= job.namespace %>/jobs/<%= escaped_job_name %>/disable" method="post">
81
+ <%= csrf_tag %>
82
+ <input class='btn btn-warn' type="submit" name="disable" value="<%= t('Disable') %>"/>
83
+ </form>
84
+ <% else %>
85
+ <form action="<%= root_path %>cron/namespaces/<%= job.namespace %>/jobs/<%= escaped_job_name %>/enable" method="post">
86
+ <%= csrf_tag %>
87
+ <input class='btn btn-warn' type="submit" name="enable" value="<%= t('Enable') %>"/>
88
+ </form>
89
+ <form action="<%= root_path %>cron/namespaces/<%= job.namespace %>/jobs/<%= escaped_job_name %>/delete" method="post">
90
+ <%= csrf_tag %>
91
+ <input class='btn btn-danger' type="submit" name="delete" value="<%= t('Delete') %>" data-confirm="<%= t('AreYouSureDeleteCronJob', :job => job.name) %>"/>
92
+ </form>
93
+ <% end %>
94
+ </div>
95
+ </td>
96
+ </tr>
97
+ <% end %>
98
+ </tbody>
99
+ </table>
100
+ <% else %>
101
+ <div class='alert alert-success'><%= t('NoCronJobsWereFound') %></div>
102
+ <% end %>
103
+ </section>
@@ -1,92 +1,93 @@
1
- <header class="row">
2
- <div class="span col-sm-5 pull-left">
3
- <h3>
4
- <%= "#{t('Cron')} #{t('Job')}" %>
5
- <small><%= @job.name %></small>
6
- </h3>
7
- </div>
8
- <div class="span col-sm-7 pull-right h2">
9
- <% cron_job_path = "#{root_path}cron/namespaces/#{@current_namespace}/jobs/#{CGI.escape(@job.name).gsub('+', '%20')}" %>
10
- <form action="<%= cron_job_path %>/enqueue?redirect=<%= cron_job_path %>" class="pull-right" method="post">
11
- <%= csrf_tag %>
12
- <input class="btn btn-warn pull-left" name="enqueue" type="submit" value="<%= t('EnqueueNow') %>" data-confirm="<%= t('AreYouSureEnqueueCronJob', :job => @job.name) %>" />
13
- </form>
14
- <% if @job.status == 'enabled' %>
15
- <form action="<%= cron_job_path %>/disable?redirect=<%= cron_job_path %>" class="pull-right" method="post">
16
- <%= csrf_tag %>
17
- <input class="btn btn-warn pull-left" name="disable" type="submit" value="<%= t('Disable') %>" />
18
- </form>
19
- <% else %>
20
- <form action="<%= cron_job_path %>/enable?redirect=<%= cron_job_path %>" class="pull-right" method="post">
21
- <%= csrf_tag %>
22
- <input class="btn btn-warn pull-left" name="enable" type="submit" value="<%= t('Enable') %>" />
23
- </form>
24
- <form action="<%= cron_job_path %>/delete" class="pull-right" method="post">
1
+ <section>
2
+ <header>
3
+ <div>
4
+ <h2>
5
+ <%= "#{t('Cron')} #{t('Job')}" %>
6
+ <small><%= @job.name %></small>
7
+ </h2>
8
+ </div>
9
+ <form class="filter">
10
+ <% cron_job_path = "#{root_path}cron/namespaces/#{@current_namespace}/jobs/#{CGI.escape(@job.name).gsub('+', '%20')}" %>
11
+ <form action="<%= cron_job_path %>/enqueue?redirect=<%= cron_job_path %>" method="post">
25
12
  <%= csrf_tag %>
26
- <input class="btn btn-danger pull-left" data-confirm="<%= t('AreYouSureDeleteCronJob', :job => @job.name) %>" name="delete" type="submit" value="<%= t('Delete') %>" />
13
+ <input class="btn btn-primary" name="enqueue" type="submit" value="<%= t('EnqueueNow') %>" data-confirm="<%= t('AreYouSureEnqueueCronJob', :job => @job.name) %>" />
27
14
  </form>
28
- <% end %>
29
- </div>
30
- </header>
31
-
32
- <table class="table table-bordered table-striped">
33
- <tbody>
34
- <tr>
35
- <th><%= t 'Status' %></th>
36
- <td><%= @job.status %></td>
37
- </tr>
38
- <tr>
39
- <th><%= t 'Name' %></th>
40
- <td><%= @job.name %></td>
41
- </tr>
42
- <tr>
43
- <th><%= t 'Namespace' %></th>
44
- <td><%= @job.namespace %></td>
45
- </tr>
46
- <tr>
47
- <th><%= t 'Description' %></th>
48
- <td><%= @job.description %></td>
49
- </tr>
50
- <tr>
51
- <th><%= t 'Message' %></th>
52
- <td><pre><%= @job.pretty_message %></pre></td>
53
- </tr>
54
- <tr>
55
- <th><%= t 'Cron' %></th>
56
- <td><%= @job.cron.gsub(" ", "&nbsp;") %></td>
57
- </tr>
58
- <tr>
59
- <th><%= t 'Last enqueued' %></th>
60
- <td><%= @job.last_enqueue_time ? relative_time(@job.last_enqueue_time) : "-" %></td>
61
- </tr>
62
- </tbody>
63
- </table>
64
-
65
- <header class="row">
66
- <div class="col-sm-12">
67
- <h4>
68
- <%= t 'History' %>
69
- </h4>
70
- </div>
71
- </header>
72
-
73
- <% if @job.jid_history_from_redis.size > 0 %>
74
- <table class="table table-hover table-bordered table-striped">
75
- <thead>
76
- <tr>
77
- <th><%= t 'Enqueued' %></th>
78
- <th><%= t 'JID' %></th>
79
- </tr>
80
- </thead>
15
+ <% if @job.status == 'enabled' %>
16
+ <form action="<%= cron_job_path %>/disable?redirect=<%= cron_job_path %>" method="post">
17
+ <%= csrf_tag %>
18
+ <input class="btn btn-primary" name="disable" type="submit" value="<%= t('Disable') %>" />
19
+ </form>
20
+ <% else %>
21
+ <form action="<%= cron_job_path %>/enable?redirect=<%= cron_job_path %>" method="post">
22
+ <%= csrf_tag %>
23
+ <input class="btn btn-primary" name="enable" type="submit" value="<%= t('Enable') %>" />
24
+ </form>
25
+ <form action="<%= cron_job_path %>/delete" method="post">
26
+ <%= csrf_tag %>
27
+ <input class="btn btn-danger" data-confirm="<%= t('AreYouSureDeleteCronJob', :job => @job.name) %>" name="delete" type="submit" value="<%= t('Delete') %>" />
28
+ </form>
29
+ <% end %>
30
+ </form>
31
+ </header>
32
+ <table class="table table-bordered table-striped">
81
33
  <tbody>
82
- <% @job.jid_history_from_redis.each do |jid_history| %>
83
34
  <tr>
84
- <td><%= jid_history['enqueued'] %></td>
85
- <td><%= jid_history['jid'] %></td>
35
+ <th><%= t 'Status' %></th>
36
+ <td><%= @job.status %></td>
37
+ </tr>
38
+ <tr>
39
+ <th><%= t 'Name' %></th>
40
+ <td><%= @job.name %></td>
41
+ </tr>
42
+ <tr>
43
+ <th><%= t 'Namespace' %></th>
44
+ <td><%= @job.namespace %></td>
45
+ </tr>
46
+ <tr>
47
+ <th><%= t 'Description' %></th>
48
+ <td><%= @job.description %></td>
49
+ </tr>
50
+ <tr>
51
+ <th><%= t 'Message' %></th>
52
+ <td>
53
+ <pre><%= @job.pretty_message %></pre>
54
+ </td>
55
+ </tr>
56
+ <tr>
57
+ <th><%= t 'Cron' %></th>
58
+ <td><%= @job.cron.gsub(" ", "&nbsp;") %></td>
59
+ </tr>
60
+ <tr>
61
+ <th><%= t 'Last enqueued' %></th>
62
+ <td><%= @job.last_enqueue_time ? relative_time(@job.last_enqueue_time) : "-" %></td>
86
63
  </tr>
87
- <% end %>
88
64
  </tbody>
89
65
  </table>
90
- <% else %>
91
- <div class='alert alert-success'><%= t 'NoHistoryWereFound' %></div>
92
- <% end %>
66
+ <header>
67
+ <div>
68
+ <h4>
69
+ <%= t 'History' %>
70
+ </h4>
71
+ </div>
72
+ </header>
73
+ <% if @job.jid_history_from_redis.size > 0 %>
74
+ <table class="table table-hover table-bordered table-striped">
75
+ <thead>
76
+ <tr>
77
+ <th><%= t 'Enqueued' %></th>
78
+ <th><%= t 'JID' %></th>
79
+ </tr>
80
+ </thead>
81
+ <tbody>
82
+ <% @job.jid_history_from_redis.each do |jid_history| %>
83
+ <tr>
84
+ <td><%= jid_history['enqueued'] %></td>
85
+ <td><%= jid_history['jid'] %></td>
86
+ </tr>
87
+ <% end %>
88
+ </tbody>
89
+ </table>
90
+ <% else %>
91
+ <div class='alert alert-success'><%= t 'NoHistoryWereFound' %></div>
92
+ <% end %>
93
+ </section>
@@ -0,0 +1,113 @@
1
+ <header class='row'>
2
+ <div class='col-sm-5 pull-left'>
3
+ <h3>
4
+ <%= t('CronJobs') %>
5
+ <small><%= @current_namespace %></small>
6
+ </h3>
7
+ </div>
8
+ <div class='col-sm-7 pull-right h2'>
9
+ <% if @cron_jobs.size > 0 %>
10
+ <form action="<%= root_path %>cron/namespaces/<%= @current_namespace %>/all/delete" method="post" class="pull-right">
11
+ <%= csrf_tag %>
12
+ <input class="btn btn-danger" type="submit" name="delete" value="<%= t('DeleteAll') %>" data-confirm="<%= t('AreYouSureDeleteCronJobs') %>" />
13
+ </form>
14
+ <form action="<%= root_path %>cron/namespaces/<%= @current_namespace %>/all/disable" method="post" class="pull-right">
15
+ <%= csrf_tag %>
16
+ <input class="btn btn-warn" type="submit" name="enqueue" value="<%= t('DisableAll') %>" />
17
+ </form>
18
+ <form action="<%= root_path %>cron/namespaces/<%= @current_namespace %>/all/enable" method="post" class="pull-right">
19
+ <%= csrf_tag %>
20
+ <input class="btn btn-warn" type="submit" name="enqueue" value="<%= t('EnableAll') %>" />
21
+ </form>
22
+ <form action="<%= root_path %>cron/namespaces/<%= @current_namespace %>/all/enqueue" method="post" class="pull-right">
23
+ <%= csrf_tag %>
24
+ <input class="btn btn-warn" type="submit" name="enqueue" value="<%= t('EnqueueAll') %>" data-confirm="<%= t('AreYouSureEnqueueCronJobs') %>" />
25
+ </form>
26
+ <% end %>
27
+ </div>
28
+ </header>
29
+
30
+ <!-- Namespaces -->
31
+ <div class='row'>
32
+ <div class="col-sm-12 summary_bar">
33
+ <ul class="list-unstyled summary row">
34
+ <% Sidekiq::Cron::Namespace.all_with_count.sort_by { |namespace| namespace[:name] }.each do |namespace| %>
35
+ <li class="col-sm-1">
36
+ <a href="<%= root_path %>cron/namespaces/<%= namespace[:name] %>">
37
+ <span class="count"><%= namespace[:count] %></span>
38
+ <span class="desc"><%= namespace[:name] %></span>
39
+ </a>
40
+ </li>
41
+ <% end %>
42
+ </ul>
43
+ </div>
44
+ </div>
45
+ <!-- Namespaces -->
46
+
47
+ <% if @cron_jobs.size > 0 %>
48
+ <table class="table table-hover table-bordered table-striped table-white">
49
+ <thead>
50
+ <tr>
51
+ <th><%= t('Status') %></th>
52
+ <th width="50%"><%= t('Name') %></th>
53
+ <th><%= t('CronString') %></th>
54
+ <th><%= t('LastEnqueued') %></th>
55
+ <th width="180"><%= t('Actions') %></th>
56
+ </tr>
57
+ </thead>
58
+
59
+ <tbody>
60
+ <% @cron_jobs.sort{ |a,b| a.sort_name <=> b.sort_name }.each do |job| %>
61
+ <% klass = (job.status == 'disabled') ? 'bg-danger text-muted' : '' %>
62
+ <% escaped_job_name = CGI.escape(job.name).gsub('+', '%20') %>
63
+ <tr>
64
+ <td class="<%= klass %>"><%= t job.status %></td>
65
+ <td class="<%= klass %>">
66
+ <a href="<%= root_path %>cron/namespaces/<%= job.namespace %>/jobs/<%= escaped_job_name %>" title="<%= job.description %>">
67
+ <b class="<%= klass %>"><%= job.name %></b>
68
+ </a>
69
+ <br/>
70
+ <% if job.message and job.message.to_s.size > 100 %>
71
+ <details>
72
+ <summary class="btn btn-warn btn-xs">Show message</summary>
73
+ <p><small><%= job.message %></small></p>
74
+ </details>
75
+ <% else %>
76
+ <small><%= job.message %></small>
77
+ <% end %>
78
+ </td>
79
+ <td class="<%= klass %>"><b><%= job.human_cron %><br/><small><%= job.cron_expression_string.gsub(" ", "&nbsp;") %></small></b></td>
80
+ <td class="<%= klass %>"><%= job.last_enqueue_time ? relative_time(job.last_enqueue_time) : "-" %></td>
81
+ <td class="<%= klass %>">
82
+ <% if job.status == 'enabled' %>
83
+ <form action="<%= root_path %>cron/namespaces/<%= job.namespace %>/jobs/<%= escaped_job_name %>/enqueue" method="post">
84
+ <%= csrf_tag %>
85
+ <input class='btn btn-warn btn-xs pull-left' type="submit" name="enqueue" value="<%= t('EnqueueNow') %>" data-confirm="<%= t('AreYouSureEnqueueCronJob', :job => job.name) %>"/>
86
+ </form>
87
+ <form action="<%= root_path %>cron/namespaces/<%= job.namespace %>/jobs/<%= escaped_job_name %>/disable" method="post">
88
+ <%= csrf_tag %>
89
+ <input class='btn btn-warn btn-xs pull-left' type="submit" name="disable" value="<%= t('Disable') %>"/>
90
+ </form>
91
+ <% else %>
92
+ <form action="<%= root_path %>cron/namespaces/<%= job.namespace %>/jobs/<%= escaped_job_name %>/enqueue" method="post">
93
+ <%= csrf_tag %>
94
+ <input class='btn btn-warn btn-xs pull-left' type="submit" name="enqueue" value="<%= t('EnqueueNow') %>" data-confirm="<%= t('AreYouSureEnqueueCronJob', :job => job.name) %>"/>
95
+ </form>
96
+ <form action="<%= root_path %>cron/namespaces/<%= job.namespace %>/jobs/<%= escaped_job_name %>/enable" method="post">
97
+ <%= csrf_tag %>
98
+ <input class='btn btn-warn btn-xs pull-left' type="submit" name="enable" value="<%= t('Enable') %>"/>
99
+ </form>
100
+ <form action="<%= root_path %>cron/namespaces/<%= job.namespace %>/jobs/<%= escaped_job_name %>/delete" method="post">
101
+ <%= csrf_tag %>
102
+ <input class='btn btn-xs btn-danger pull-left help-block' type="submit" name="delete" value="<%= t('Delete') %>" data-confirm="<%= t('AreYouSureDeleteCronJob', :job => job.name) %>"/>
103
+ </form>
104
+ <% end %>
105
+ </td>
106
+ </tr>
107
+ <% end %>
108
+ </tbody>
109
+ </table>
110
+ <% else %>
111
+ <div class='alert alert-success'><%= t('NoCronJobsWereFound') %></div>
112
+ <% end %>
113
+
@@ -0,0 +1,92 @@
1
+ <header class="row">
2
+ <div class="span col-sm-5 pull-left">
3
+ <h3>
4
+ <%= "#{t('Cron')} #{t('Job')}" %>
5
+ <small><%= @job.name %></small>
6
+ </h3>
7
+ </div>
8
+ <div class="span col-sm-7 pull-right h2">
9
+ <% cron_job_path = "#{root_path}cron/namespaces/#{@current_namespace}/jobs/#{CGI.escape(@job.name).gsub('+', '%20')}" %>
10
+ <form action="<%= cron_job_path %>/enqueue?redirect=<%= cron_job_path %>" class="pull-right" method="post">
11
+ <%= csrf_tag %>
12
+ <input class="btn btn-warn pull-left" name="enqueue" type="submit" value="<%= t('EnqueueNow') %>" data-confirm="<%= t('AreYouSureEnqueueCronJob', :job => @job.name) %>" />
13
+ </form>
14
+ <% if @job.status == 'enabled' %>
15
+ <form action="<%= cron_job_path %>/disable?redirect=<%= cron_job_path %>" class="pull-right" method="post">
16
+ <%= csrf_tag %>
17
+ <input class="btn btn-warn pull-left" name="disable" type="submit" value="<%= t('Disable') %>" />
18
+ </form>
19
+ <% else %>
20
+ <form action="<%= cron_job_path %>/enable?redirect=<%= cron_job_path %>" class="pull-right" method="post">
21
+ <%= csrf_tag %>
22
+ <input class="btn btn-warn pull-left" name="enable" type="submit" value="<%= t('Enable') %>" />
23
+ </form>
24
+ <form action="<%= cron_job_path %>/delete" class="pull-right" method="post">
25
+ <%= csrf_tag %>
26
+ <input class="btn btn-danger pull-left" data-confirm="<%= t('AreYouSureDeleteCronJob', :job => @job.name) %>" name="delete" type="submit" value="<%= t('Delete') %>" />
27
+ </form>
28
+ <% end %>
29
+ </div>
30
+ </header>
31
+
32
+ <table class="table table-bordered table-striped">
33
+ <tbody>
34
+ <tr>
35
+ <th><%= t 'Status' %></th>
36
+ <td><%= @job.status %></td>
37
+ </tr>
38
+ <tr>
39
+ <th><%= t 'Name' %></th>
40
+ <td><%= @job.name %></td>
41
+ </tr>
42
+ <tr>
43
+ <th><%= t 'Namespace' %></th>
44
+ <td><%= @job.namespace %></td>
45
+ </tr>
46
+ <tr>
47
+ <th><%= t 'Description' %></th>
48
+ <td><%= @job.description %></td>
49
+ </tr>
50
+ <tr>
51
+ <th><%= t 'Message' %></th>
52
+ <td><pre><%= @job.pretty_message %></pre></td>
53
+ </tr>
54
+ <tr>
55
+ <th><%= t 'Cron' %></th>
56
+ <td><%= @job.cron.gsub(" ", "&nbsp;") %></td>
57
+ </tr>
58
+ <tr>
59
+ <th><%= t 'Last enqueued' %></th>
60
+ <td><%= @job.last_enqueue_time ? relative_time(@job.last_enqueue_time) : "-" %></td>
61
+ </tr>
62
+ </tbody>
63
+ </table>
64
+
65
+ <header class="row">
66
+ <div class="col-sm-12">
67
+ <h4>
68
+ <%= t 'History' %>
69
+ </h4>
70
+ </div>
71
+ </header>
72
+
73
+ <% if @job.jid_history_from_redis.size > 0 %>
74
+ <table class="table table-hover table-bordered table-striped">
75
+ <thead>
76
+ <tr>
77
+ <th><%= t 'Enqueued' %></th>
78
+ <th><%= t 'JID' %></th>
79
+ </tr>
80
+ </thead>
81
+ <tbody>
82
+ <% @job.jid_history_from_redis.each do |jid_history| %>
83
+ <tr>
84
+ <td><%= jid_history['enqueued'] %></td>
85
+ <td><%= jid_history['jid'] %></td>
86
+ </tr>
87
+ <% end %>
88
+ </tbody>
89
+ </table>
90
+ <% else %>
91
+ <div class='alert alert-success'><%= t 'NoHistoryWereFound' %></div>
92
+ <% end %>
@@ -3,7 +3,16 @@ require "sidekiq/cron/job"
3
3
  require "sidekiq/cron/namespace"
4
4
 
5
5
  if defined?(Sidekiq::Web)
6
- if Gem::Version.new(Sidekiq::VERSION) >= Gem::Version.new('7.3.0')
6
+ if Gem::Version.new(Sidekiq::VERSION) >= Gem::Version.new('8.0.0')
7
+ Sidekiq::Web.configure do |config|
8
+ config.register(
9
+ Sidekiq::Cron::WebExtension, # Class which contains the HTTP actions, required
10
+ name: "cron", # the name of the extension, used to namespace assets
11
+ tab: "Cron", # labels(s) of the UI tabs
12
+ index: "cron", # index route(s) for each tab
13
+ )
14
+ end
15
+ elsif Gem::Version.new(Sidekiq::VERSION) >= Gem::Version.new('7.3.0')
7
16
  Sidekiq::Web.register(
8
17
  Sidekiq::Cron::WebExtension, # Class which contains the HTTP actions, required
9
18
  name: "cron", # the name of the extension, used to namespace assets
@@ -1,25 +1,42 @@
1
1
  module Sidekiq
2
2
  module Cron
3
3
  module WebExtension
4
- def self.registered(app)
5
- app.settings.locales << File.join(File.expand_path("..", __FILE__), "locales")
6
-
7
- app.helpers do
8
- # This method constructs the URL for the cron jobs page within the specified namespace.
9
- def namespace_redirect_path
10
- "#{root_path}cron/namespaces/#{route_params[:namespace]}"
4
+ module Helpers
5
+ def cron_route_params(key)
6
+ if Gem::Version.new(Sidekiq::VERSION) >= Gem::Version.new("8.0.0")
7
+ route_params(key)
8
+ else
9
+ route_params[key]
11
10
  end
11
+ end
12
12
 
13
- def redirect_to_previous_or_default
14
- redirect params['redirect'] || namespace_redirect_path
15
- end
13
+ # This method constructs the URL for the cron jobs page within the specified namespace.
14
+ def namespace_redirect_path
15
+ "#{root_path}cron/namespaces/#{cron_route_params(:namespace)}"
16
+ end
16
17
 
17
- def render_erb(view)
18
- views_path = File.join(File.expand_path("..", __FILE__), "views")
19
- erb(File.read(File.join(views_path, "#{view}.erb")))
20
- end
18
+ def redirect_to_previous_or_default
19
+ redirect params['redirect'] || namespace_redirect_path
21
20
  end
22
21
 
22
+ def render_erb(view)
23
+ path = Gem::Version.new(Sidekiq::VERSION) >= Gem::Version.new("8.0.0") ? "views" : "views/legacy"
24
+ views_path = File.join(File.expand_path("..", __FILE__), path)
25
+ erb(File.read(File.join(views_path, "#{view}.erb")))
26
+ end
27
+ end
28
+
29
+ def self.registered(app)
30
+ locales = if Gem::Version.new(Sidekiq::VERSION) >= Gem::Version.new("8.0.0")
31
+ Sidekiq::Web.configure.locales
32
+ else
33
+ app.settings.locales
34
+ end
35
+
36
+ locales << File.join(File.expand_path("..", __FILE__), "locales")
37
+
38
+ app.helpers(Helpers)
39
+
23
40
  # Index page.
24
41
  app.get '/cron' do
25
42
  @current_namespace = 'default'
@@ -30,7 +47,7 @@ module Sidekiq
30
47
 
31
48
  # Detail page for a specific namespace.
32
49
  app.get '/cron/namespaces/:name' do
33
- @current_namespace = route_params[:name]
50
+ @current_namespace = cron_route_params(:name)
34
51
  @cron_jobs = Sidekiq::Cron::Job.all(@current_namespace)
35
52
 
36
53
  render_erb(:cron)
@@ -38,8 +55,8 @@ module Sidekiq
38
55
 
39
56
  # Display job detail + jid history.
40
57
  app.get '/cron/namespaces/:namespace/jobs/:name' do
41
- @current_namespace = route_params[:namespace]
42
- @job = Sidekiq::Cron::Job.find(route_params[:name], @current_namespace)
58
+ @current_namespace = cron_route_params(:namespace)
59
+ @job = Sidekiq::Cron::Job.find(cron_route_params(:name), @current_namespace)
43
60
 
44
61
  if @job
45
62
  render_erb(:cron_show)
@@ -50,14 +67,14 @@ module Sidekiq
50
67
 
51
68
  # Enqueue all cron jobs.
52
69
  app.post '/cron/namespaces/:namespace/all/enqueue' do
53
- Sidekiq::Cron::Job.all(route_params[:namespace]).each(&:enqueue!)
70
+ Sidekiq::Cron::Job.all(cron_route_params(:namespace)).each(&:enqueue!)
54
71
 
55
72
  redirect_to_previous_or_default
56
73
  end
57
74
 
58
75
  # Enqueue cron job.
59
76
  app.post '/cron/namespaces/:namespace/jobs/:name/enqueue' do
60
- if job = Sidekiq::Cron::Job.find(route_params[:name], route_params[:namespace])
77
+ if job = Sidekiq::Cron::Job.find(cron_route_params(:name), cron_route_params(:namespace))
61
78
  job.enqueue!
62
79
  end
63
80
 
@@ -66,14 +83,14 @@ module Sidekiq
66
83
 
67
84
  # Delete all schedules.
68
85
  app.post '/cron/namespaces/:namespace/all/delete' do
69
- Sidekiq::Cron::Job.all(route_params[:namespace]).each(&:destroy)
86
+ Sidekiq::Cron::Job.all(cron_route_params(:namespace)).each(&:destroy)
70
87
 
71
88
  redirect_to_previous_or_default
72
89
  end
73
90
 
74
91
  # Delete schedule.
75
92
  app.post '/cron/namespaces/:namespace/jobs/:name/delete' do
76
- if job = Sidekiq::Cron::Job.find(route_params[:name], route_params[:namespace])
93
+ if job = Sidekiq::Cron::Job.find(cron_route_params(:name), cron_route_params(:namespace))
77
94
  job.destroy
78
95
  end
79
96
 
@@ -82,14 +99,14 @@ module Sidekiq
82
99
 
83
100
  # Enable all jobs.
84
101
  app.post '/cron/namespaces/:namespace/all/enable' do
85
- Sidekiq::Cron::Job.all(route_params[:namespace]).each(&:enable!)
102
+ Sidekiq::Cron::Job.all(cron_route_params(:namespace)).each(&:enable!)
86
103
 
87
104
  redirect_to_previous_or_default
88
105
  end
89
106
 
90
107
  # Enable job.
91
108
  app.post '/cron/namespaces/:namespace/jobs/:name/enable' do
92
- if job = Sidekiq::Cron::Job.find(route_params[:name], route_params[:namespace])
109
+ if job = Sidekiq::Cron::Job.find(cron_route_params(:name), cron_route_params(:namespace))
93
110
  job.enable!
94
111
  end
95
112
 
@@ -98,14 +115,14 @@ module Sidekiq
98
115
 
99
116
  # Disable all jobs.
100
117
  app.post '/cron/namespaces/:namespace/all/disable' do
101
- Sidekiq::Cron::Job.all(route_params[:namespace]).each(&:disable!)
118
+ Sidekiq::Cron::Job.all(cron_route_params(:namespace)).each(&:disable!)
102
119
 
103
120
  redirect_to_previous_or_default
104
121
  end
105
122
 
106
123
  # Disable job.
107
124
  app.post '/cron/namespaces/:namespace/jobs/:name/disable' do
108
- if job = Sidekiq::Cron::Job.find(route_params[:name], route_params[:namespace])
125
+ if job = Sidekiq::Cron::Job.find(cron_route_params(:name), cron_route_params(:namespace))
109
126
  job.disable!
110
127
  end
111
128
 
data/lib/sidekiq/cron.rb CHANGED
@@ -28,6 +28,17 @@ module Sidekiq
28
28
  # The default namespace is used when no namespace is specified.
29
29
  attr_accessor :default_namespace
30
30
 
31
+ # List of available namespaces
32
+ #
33
+ # If not set, Sidekiq Cron will dynamically fetch available namespaces
34
+ # by retrieving existing jobs from Redis.
35
+ #
36
+ # This dynamic fetching can negatively impact performance in certain cases.
37
+ # To mitigate this, you can provide the list of namespaces explicitly.
38
+ # If a job specifies a namespace that is not included in the provided list,
39
+ # a warning will be logged, and the job will be assigned to the default namespace.
40
+ attr_accessor :available_namespaces
41
+
31
42
  # The parsing mode when using the natural language cron syntax from the `fugit` gem.
32
43
  #
33
44
  # :single -- use the first parsed cron line and ignore the rest (default)
@@ -42,25 +53,14 @@ module Sidekiq
42
53
  # jobs that missed their schedules during the deployment. E.g., jobs that run once a day.
43
54
  attr_accessor :reschedule_grace_period
44
55
 
45
- # List of available namespaces
46
- #
47
- # If not set, Sidekiq Cron will dynamically fetch available namespaces
48
- # by retrieving existing jobs from Redis.
49
- #
50
- # This dynamic fetching can negatively impact performance in certain cases.
51
- # To mitigate this, you can provide the list of namespaces explicitly.
52
- # If a job specifies a namespace that is not included in the provided list,
53
- # a warning will be logged, and the job will be assigned to the default namespace.
54
- attr_accessor :available_namespaces
55
-
56
56
  def initialize
57
57
  @cron_poll_interval = 30
58
58
  @cron_schedule_file = 'config/schedule.yml'
59
59
  @cron_history_size = 10
60
60
  @default_namespace = 'default'
61
+ @available_namespaces = nil
61
62
  @natural_cron_parsing_mode = :single
62
63
  @reschedule_grace_period = 60
63
- @available_namespaces = nil
64
64
  end
65
65
 
66
66
  def natural_cron_parsing_mode=(mode)
data/sidekiq-cron.gemspec CHANGED
@@ -33,8 +33,8 @@ Gem::Specification.new do |s|
33
33
 
34
34
  s.add_development_dependency("minitest", "~> 5.15")
35
35
  s.add_development_dependency("mocha", "~> 2.1")
36
- s.add_development_dependency("rack", "~> 2.2")
37
- s.add_development_dependency("rack-test", "~> 1.1")
36
+ s.add_development_dependency("rack", ">= 2.2")
37
+ s.add_development_dependency("rack-test", ">= 1.1")
38
38
  s.add_development_dependency("rake", "~> 13.0")
39
39
  s.add_development_dependency("simplecov", "~> 0.21")
40
40
  s.add_development_dependency("simplecov-cobertura", "~> 2.1")
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: sidekiq-cron
3
3
  version: !ruby/object:Gem::Version
4
- version: 2.1.0
4
+ version: 2.2.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Ondrej Bartas
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2025-01-20 00:00:00.000000000 Z
11
+ date: 2025-03-20 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: cronex
@@ -104,28 +104,28 @@ dependencies:
104
104
  name: rack
105
105
  requirement: !ruby/object:Gem::Requirement
106
106
  requirements:
107
- - - "~>"
107
+ - - ">="
108
108
  - !ruby/object:Gem::Version
109
109
  version: '2.2'
110
110
  type: :development
111
111
  prerelease: false
112
112
  version_requirements: !ruby/object:Gem::Requirement
113
113
  requirements:
114
- - - "~>"
114
+ - - ">="
115
115
  - !ruby/object:Gem::Version
116
116
  version: '2.2'
117
117
  - !ruby/object:Gem::Dependency
118
118
  name: rack-test
119
119
  requirement: !ruby/object:Gem::Requirement
120
120
  requirements:
121
- - - "~>"
121
+ - - ">="
122
122
  - !ruby/object:Gem::Version
123
123
  version: '1.1'
124
124
  type: :development
125
125
  prerelease: false
126
126
  version_requirements: !ruby/object:Gem::Requirement
127
127
  requirements:
128
- - - "~>"
128
+ - - ">="
129
129
  - !ruby/object:Gem::Version
130
130
  version: '1.1'
131
131
  - !ruby/object:Gem::Dependency
@@ -204,6 +204,8 @@ files:
204
204
  - lib/sidekiq/cron/version.rb
205
205
  - lib/sidekiq/cron/views/cron.erb
206
206
  - lib/sidekiq/cron/views/cron_show.erb
207
+ - lib/sidekiq/cron/views/legacy/cron.erb
208
+ - lib/sidekiq/cron/views/legacy/cron_show.erb
207
209
  - lib/sidekiq/cron/web.rb
208
210
  - lib/sidekiq/cron/web_extension.rb
209
211
  - lib/sidekiq/options.rb
@@ -227,7 +229,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
227
229
  - !ruby/object:Gem::Version
228
230
  version: '0'
229
231
  requirements: []
230
- rubygems_version: 3.4.10
232
+ rubygems_version: 3.5.16
231
233
  signing_key:
232
234
  specification_version: 4
233
235
  summary: Scheduler/Cron for Sidekiq jobs