sidekiq-cron 2.1.0 → 2.3.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 +16 -0
- data/Gemfile +2 -2
- data/README.md +55 -6
- data/lib/sidekiq/cron/job.rb +13 -17
- data/lib/sidekiq/cron/namespace.rb +16 -21
- data/lib/sidekiq/cron/schedule_loader.rb +53 -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 +45 -24
- 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: e256288ae9e2ffd550dfd47aa2d2776cb75edff89c2c7605bbd11685afba79b2
|
4
|
+
data.tar.gz: 84eded49d6d3e3da996a73902daf9f27010394b334c769fdebad789acdc006c9
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: a329899c823ee69c96a8849eddb5abcfac3d99d5ac0003e2066f7e919c3bc25fa071518d0fe98c308d75d9076925ca22ec77c1fbc66acd1d740f14086c4c6a97
|
7
|
+
data.tar.gz: 917fd615b9855cfa55a90624be4769febc0de1d7e0012f928471f1ba5fa1aa543a39a212b8cd725f6be8eeb7d7494df5a3fb74b532abb8a5d970563ceb3b8da6
|
data/CHANGELOG.md
CHANGED
@@ -2,6 +2,22 @@
|
|
2
2
|
|
3
3
|
All notable changes to this project will be documented in this file.
|
4
4
|
|
5
|
+
## 2.3.0
|
6
|
+
|
7
|
+
- **WARNING** The default value for `available_namespaces` has changed from `nil` to `[default_namespace]`. Please refer to the [migration guide](https://github.com/sidekiq-cron/sidekiq-cron/blob/master/README.md#migrating-to-23) for further details (https://github.com/sidekiq-cron/sidekiq-cron/pull/552)
|
8
|
+
- Fix deprecation warning for using raw params in WEB extension (https://github.com/sidekiq-cron/sidekiq-cron/pull/547)
|
9
|
+
- Allow for sidekiq embedded configuration (https://github.com/sidekiq-cron/sidekiq-cron/pull/549)
|
10
|
+
- Load schedule file within sidekiq callback (https://github.com/sidekiq-cron/sidekiq-cron/pull/550)
|
11
|
+
- Fix missing default namespace if namespaces are explicitly provided (https://github.com/sidekiq-cron/sidekiq-cron/pull/551)
|
12
|
+
|
13
|
+
## 2.2.0
|
14
|
+
|
15
|
+
- Add support for Sidekiq v8 (https://github.com/sidekiq-cron/sidekiq-cron/pull/531, https://github.com/sidekiq-cron/sidekiq-cron/pull/538)
|
16
|
+
- Always show parsed cron expression in web UI (https://github.com/sidekiq-cron/sidekiq-cron/pull/535)
|
17
|
+
- Add fallback to .yaml extension (https://github.com/sidekiq-cron/sidekiq-cron/pull/534)
|
18
|
+
- Refactor constantize helper to use Object.const_get (https://github.com/sidekiq-cron/sidekiq-cron/pull/541)
|
19
|
+
- Allow testing of schedule by library consumers (https://github.com/sidekiq-cron/sidekiq-cron/pull/543)
|
20
|
+
|
5
21
|
## 2.1.0
|
6
22
|
|
7
23
|
- 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
@@ -56,7 +56,7 @@ gem "sidekiq-cron"
|
|
56
56
|
'active_job' => true, # enqueue job through Active Job interface
|
57
57
|
'queue_name_prefix' => 'prefix', # Active Job queue with prefix
|
58
58
|
'queue_name_delimiter' => '.', # Active Job queue with custom delimiter (default: '_')
|
59
|
-
'description' => 'A sentence describing what work this job performs'
|
59
|
+
'description' => 'A sentence describing what work this job performs',
|
60
60
|
'status' => 'disabled' # default: enabled
|
61
61
|
}
|
62
62
|
```
|
@@ -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 `[config.default_namespace]`
|
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
|
|
@@ -163,7 +163,7 @@ In the case you'd like to change this value, you can change it via the following
|
|
163
163
|
|
164
164
|
```ruby
|
165
165
|
Sidekiq::Cron.configure do |config|
|
166
|
-
config.default_namespace = '
|
166
|
+
config.default_namespace = 'statistics'
|
167
167
|
end
|
168
168
|
```
|
169
169
|
|
@@ -179,11 +179,21 @@ Sidekiq::Cron::Job.all('YOUR_OLD_NAMESPACE_NAME').each { |job| job.destroy }
|
|
179
179
|
|
180
180
|
#### Available namespaces
|
181
181
|
|
182
|
-
By default, Sidekiq Cron
|
182
|
+
By default, Sidekiq Cron uses the available_namespaces configuration option to determine which namespaces your application utilizes. The default namespace (`"default"`, by default) is always included in the list of available namespaces.
|
183
183
|
|
184
|
-
If
|
184
|
+
If you want Sidekiq Cron to automatically detect existing namespaces from the Redis database, you can set `available_namespaces` to the special option `:auto`.
|
185
185
|
|
186
|
-
|
186
|
+
If available_namespaces is explicitly set and a job is created with an unexpected namespace, a warning will be printed, and the job will be assigned to the default namespace.
|
187
|
+
|
188
|
+
#### Migrating to 2.3
|
189
|
+
|
190
|
+
As discussed in [this issue](https://github.com/sidekiq-cron/sidekiq-cron/issues/516), the approach introduced in Sidekiq Cron 2.0 for determining available namespaces using the `KEYS` command is not acceptable. Therefore, starting from version 2.3, namespacing has been reworked:
|
191
|
+
|
192
|
+
- If you were not using the namespacing feature, no action is required. You can even remove `available_namespaces = %w[default]`, as it is now the default.
|
193
|
+
|
194
|
+
- If you were using the namespacing feature and explicitly specified available namespaces as a list, no changes are needed.
|
195
|
+
|
196
|
+
- If you were using the namespacing feature and relied on automatic namespace inference, you should either specify all used namespaces explicitly or set `available_namespaces` to `:auto` to maintain automatic detection. However, note that this approach does not scale well (see the referenced issue for details).
|
187
197
|
|
188
198
|
#### Usage
|
189
199
|
|
@@ -511,6 +521,45 @@ Sidekiq::Cron.configure do |config|
|
|
511
521
|
end
|
512
522
|
```
|
513
523
|
|
524
|
+
## Testing your configuration
|
525
|
+
|
526
|
+
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:
|
527
|
+
|
528
|
+
```ruby
|
529
|
+
# spec/cron_schedule_spec.rb
|
530
|
+
require "rails_helper"
|
531
|
+
|
532
|
+
RSpec.describe "Cron Schedule" do
|
533
|
+
let(:schedule_loader) { Sidekiq::Cron::ScheduleLoader.new }
|
534
|
+
let(:all_jobs) { Sidekiq::Cron::Job.all }
|
535
|
+
|
536
|
+
# Confirms that `config.cron_schedule_file` points to a real file.
|
537
|
+
it "has a schedule file" do
|
538
|
+
expect(schedule_loader).to have_schedule_file
|
539
|
+
end
|
540
|
+
|
541
|
+
# Confirms that no jobs in the schedule have an invalid cron string.
|
542
|
+
it "does not return any errors" do
|
543
|
+
expect(schedule_loader.load_schedule).to be_empty
|
544
|
+
end
|
545
|
+
|
546
|
+
# May be subject to churn, but adds confidence.
|
547
|
+
it "adds the expected number of jobs" do
|
548
|
+
schedule_loader.load_schedule
|
549
|
+
expect(all_jobs.size).to eq 5
|
550
|
+
end
|
551
|
+
|
552
|
+
# Confirms that all job classes exist.
|
553
|
+
it "has a valid class for each added job" do
|
554
|
+
schedule_loader.load_schedule
|
555
|
+
# Shows that all classes exist (as we can constantize the names without raising).
|
556
|
+
job_classes = all_jobs.map { |job| job.klass.constantize }
|
557
|
+
# Naive check that classes are sidekiq jobs (as they all have `.perfrom_async`).
|
558
|
+
expect(job_classes).to all(respond_to(:perform_async))
|
559
|
+
end
|
560
|
+
end
|
561
|
+
```
|
562
|
+
|
514
563
|
## Contributing
|
515
564
|
|
516
565
|
**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] }]
|
@@ -32,7 +32,7 @@ module Sidekiq
|
|
32
32
|
|
33
33
|
default_namespace = Sidekiq::Cron.configuration.default_namespace
|
34
34
|
@namespace = args["namespace"] || default_namespace
|
35
|
-
if Sidekiq::Cron::Namespace.available_namespaces_provided? && !Sidekiq::Cron::Namespace.all.include?(@namespace)
|
35
|
+
if Sidekiq::Cron::Namespace.available_namespaces_provided? && !Sidekiq::Cron::Namespace.all.include?(@namespace)
|
36
36
|
Sidekiq.logger.warn { "Cron Jobs - unexpected namespace #{@namespace} encountered. Assigning to default namespace." }
|
37
37
|
@namespace = default_namespace
|
38
38
|
end
|
@@ -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
|
@@ -693,7 +693,7 @@ module Sidekiq
|
|
693
693
|
def self.job_keys_from_namespace(namespace = Sidekiq::Cron.configuration.default_namespace)
|
694
694
|
Sidekiq.redis do |conn|
|
695
695
|
if namespace == '*'
|
696
|
-
namespaces = Sidekiq::Cron.
|
696
|
+
namespaces = Sidekiq::Cron::Namespace.all.map { jobs_key(_1) }
|
697
697
|
namespaces.flat_map { |name| conn.smembers(name) }
|
698
698
|
else
|
699
699
|
conn.smembers(jobs_key(namespace))
|
@@ -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
|
@@ -2,25 +2,20 @@ module Sidekiq
|
|
2
2
|
module Cron
|
3
3
|
class Namespace
|
4
4
|
def self.all
|
5
|
-
namespaces = Sidekiq::Cron.configuration.available_namespaces
|
6
|
-
|
7
|
-
|
8
|
-
|
9
|
-
|
10
|
-
|
5
|
+
namespaces = case (available_namespaces = Sidekiq::Cron.configuration.available_namespaces)
|
6
|
+
when NilClass then []
|
7
|
+
when Array then available_namespaces
|
8
|
+
when :auto
|
9
|
+
Sidekiq.redis do |conn|
|
10
|
+
conn.keys('cron_jobs:*').collect do |key|
|
11
|
+
key.split(':').last
|
12
|
+
end
|
13
|
+
end
|
14
|
+
else
|
15
|
+
raise ArgumentError, "Unexpected value provided for `available_namespaces`: #{available_namespaces.inspect}"
|
11
16
|
end
|
12
|
-
end
|
13
|
-
|
14
|
-
# Adds the default namespace if not present
|
15
|
-
has_default = namespaces.detect do |name|
|
16
|
-
name == Sidekiq::Cron.configuration.default_namespace
|
17
|
-
end
|
18
|
-
|
19
|
-
unless has_default
|
20
|
-
namespaces << Sidekiq::Cron.configuration.default_namespace
|
21
|
-
end
|
22
17
|
|
23
|
-
namespaces
|
18
|
+
namespaces | [Sidekiq::Cron.configuration.default_namespace]
|
24
19
|
end
|
25
20
|
|
26
21
|
def self.all_with_count
|
@@ -33,15 +28,15 @@ module Sidekiq
|
|
33
28
|
end
|
34
29
|
|
35
30
|
def self.count(name = Sidekiq::Cron.configuration.default_namespace)
|
36
|
-
out = 0
|
37
31
|
Sidekiq.redis do |conn|
|
38
|
-
|
32
|
+
conn.scard("cron_jobs:#{name}")
|
39
33
|
end
|
40
|
-
out
|
41
34
|
end
|
42
35
|
|
43
36
|
def self.available_namespaces_provided?
|
44
|
-
|
37
|
+
available_namespaces = Sidekiq::Cron.configuration.available_namespaces
|
38
|
+
|
39
|
+
available_namespaces != nil && available_namespaces != :auto
|
45
40
|
end
|
46
41
|
end
|
47
42
|
end
|
@@ -1,16 +1,57 @@
|
|
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
|
+
config.on(:startup) do
|
53
|
+
schedule_loader = Sidekiq::Cron::ScheduleLoader.new
|
54
|
+
next unless schedule_loader.has_schedule_file?
|
55
|
+
schedule_loader.load_schedule
|
56
|
+
end
|
57
|
+
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>
|