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 +4 -4
- data/CHANGELOG.md +8 -0
- data/Gemfile +2 -2
- data/README.md +40 -1
- data/lib/sidekiq/cron/job.rb +11 -15
- data/lib/sidekiq/cron/schedule_loader.rb +52 -12
- data/lib/sidekiq/cron/support.rb +4 -29
- data/lib/sidekiq/cron/version.rb +1 -1
- data/lib/sidekiq/cron/views/cron.erb +96 -106
- data/lib/sidekiq/cron/views/cron_show.erb +86 -85
- data/lib/sidekiq/cron/views/legacy/cron.erb +113 -0
- data/lib/sidekiq/cron/views/legacy/cron_show.erb +92 -0
- data/lib/sidekiq/cron/web.rb +10 -1
- data/lib/sidekiq/cron/web_extension.rb +42 -25
- data/lib/sidekiq/cron.rb +12 -12
- data/sidekiq-cron.gemspec +2 -2
- metadata +9 -7
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: fcff473f7500a6ff2d006bb8af760d697b93aec6090b18e891f63a7b491396e2
|
4
|
+
data.tar.gz: 03a0e5508ee4f31e9c437c253bef8411a25de83deeb6e8c5eb18ccf84e836b50
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
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
|
9
|
-
gem "
|
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!**
|
data/lib/sidekiq/cron/job.rb
CHANGED
@@ -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) &&
|
164
|
-
|
165
|
-
|
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 :
|
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
|
2
|
-
|
3
|
-
|
4
|
-
|
5
|
-
|
6
|
-
|
7
|
-
|
8
|
-
|
9
|
-
|
10
|
-
|
11
|
-
|
12
|
-
|
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
|
data/lib/sidekiq/cron/support.rb
CHANGED
@@ -1,35 +1,10 @@
|
|
1
1
|
module Sidekiq
|
2
2
|
module Cron
|
3
3
|
module Support
|
4
|
-
|
5
|
-
|
6
|
-
|
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)
|
data/lib/sidekiq/cron/version.rb
CHANGED
@@ -1,113 +1,103 @@
|
|
1
|
-
<
|
2
|
-
<
|
3
|
-
<
|
1
|
+
<section>
|
2
|
+
<header>
|
3
|
+
<h2>
|
4
4
|
<%= t('CronJobs') %>
|
5
|
-
<small
|
6
|
-
</
|
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
|
11
|
-
<%=
|
12
|
-
|
13
|
-
|
14
|
-
|
15
|
-
<%=
|
16
|
-
|
17
|
-
|
18
|
-
|
19
|
-
<%=
|
20
|
-
|
21
|
-
|
22
|
-
|
23
|
-
<%=
|
24
|
-
|
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
|
-
|
29
|
-
|
30
|
-
|
31
|
-
<
|
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
|
-
<
|
65
|
-
<
|
66
|
-
|
67
|
-
|
68
|
-
|
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(" ", " ") %></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
|
-
|
108
|
-
|
109
|
-
|
110
|
-
<%
|
111
|
-
|
112
|
-
|
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(" ", " ") %></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
|
-
<
|
2
|
-
<
|
3
|
-
<
|
4
|
-
|
5
|
-
|
6
|
-
|
7
|
-
|
8
|
-
|
9
|
-
|
10
|
-
|
11
|
-
<%=
|
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-
|
13
|
+
<input class="btn btn-primary" name="enqueue" type="submit" value="<%= t('EnqueueNow') %>" data-confirm="<%= t('AreYouSureEnqueueCronJob', :job => @job.name) %>" />
|
27
14
|
</form>
|
28
|
-
|
29
|
-
|
30
|
-
|
31
|
-
|
32
|
-
|
33
|
-
|
34
|
-
|
35
|
-
|
36
|
-
|
37
|
-
|
38
|
-
|
39
|
-
|
40
|
-
|
41
|
-
|
42
|
-
|
43
|
-
|
44
|
-
|
45
|
-
|
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(" ", " ") %></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
|
-
<
|
85
|
-
<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(" ", " ") %></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
|
-
|
91
|
-
|
92
|
-
|
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(" ", " ") %></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(" ", " ") %></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 %>
|
data/lib/sidekiq/cron/web.rb
CHANGED
@@ -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('
|
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
|
-
|
5
|
-
|
6
|
-
|
7
|
-
|
8
|
-
|
9
|
-
|
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
|
-
|
14
|
-
|
15
|
-
|
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
|
-
|
18
|
-
|
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 =
|
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 =
|
42
|
-
@job = Sidekiq::Cron::Job.find(
|
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(
|
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(
|
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(
|
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(
|
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(
|
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(
|
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(
|
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(
|
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", "
|
37
|
-
s.add_development_dependency("rack-test", "
|
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.
|
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-
|
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.
|
232
|
+
rubygems_version: 3.5.16
|
231
233
|
signing_key:
|
232
234
|
specification_version: 4
|
233
235
|
summary: Scheduler/Cron for Sidekiq jobs
|