sidekiq-cron 1.12.0 → 2.1.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 +44 -2
- data/Gemfile +3 -0
- data/README.md +217 -36
- data/lib/sidekiq/cron/job.rb +258 -160
- data/lib/sidekiq/cron/launcher.rb +2 -5
- data/lib/sidekiq/cron/locales/de.yml +15 -6
- data/lib/sidekiq/cron/locales/en.yml +14 -14
- data/lib/sidekiq/cron/locales/es.yml +22 -0
- data/lib/sidekiq/cron/locales/id.yml +22 -0
- data/lib/sidekiq/cron/locales/it.yml +15 -16
- data/lib/sidekiq/cron/locales/ja.yml +14 -10
- data/lib/sidekiq/cron/locales/pt.yml +14 -14
- data/lib/sidekiq/cron/locales/ru.yml +15 -7
- data/lib/sidekiq/cron/locales/zh-CN.yml +14 -11
- data/lib/sidekiq/cron/namespace.rb +48 -0
- data/lib/sidekiq/cron/poller.rb +12 -13
- data/lib/sidekiq/cron/schedule_loader.rb +1 -5
- data/lib/sidekiq/cron/support.rb +1 -2
- data/lib/sidekiq/cron/version.rb +1 -1
- data/lib/sidekiq/cron/views/cron.erb +68 -53
- data/lib/sidekiq/cron/views/cron_show.erb +16 -12
- data/lib/sidekiq/cron/web.rb +12 -2
- data/lib/sidekiq/cron/web_extension.rb +77 -30
- data/lib/sidekiq/cron.rb +73 -5
- data/lib/sidekiq/options.rb +3 -5
- data/lib/sidekiq-cron.rb +6 -0
- data/sidekiq-cron.gemspec +3 -2
- metadata +31 -8
@@ -5,25 +5,25 @@
|
|
5
5
|
<small><%= @job.name %></small>
|
6
6
|
</h3>
|
7
7
|
</div>
|
8
|
-
<div class="span col-sm-7 pull-right
|
9
|
-
<% cron_job_path = "#{root_path}cron/#{CGI.escape(@job.name).gsub('+', '%20')}" %>
|
10
|
-
<form action="<%= cron_job_path %>/
|
11
|
-
<%= csrf_tag
|
12
|
-
<input class="btn btn-warn pull-left" name="
|
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
13
|
</form>
|
14
14
|
<% if @job.status == 'enabled' %>
|
15
|
-
<form action="<%= cron_job_path %>/disable?redirect=<%= cron_job_path %>" method="post">
|
16
|
-
<%= csrf_tag
|
15
|
+
<form action="<%= cron_job_path %>/disable?redirect=<%= cron_job_path %>" class="pull-right" method="post">
|
16
|
+
<%= csrf_tag %>
|
17
17
|
<input class="btn btn-warn pull-left" name="disable" type="submit" value="<%= t('Disable') %>" />
|
18
18
|
</form>
|
19
19
|
<% else %>
|
20
|
-
<form action="<%= cron_job_path %>/enable?redirect=<%= cron_job_path %>" method="post">
|
21
|
-
<%= csrf_tag
|
20
|
+
<form action="<%= cron_job_path %>/enable?redirect=<%= cron_job_path %>" class="pull-right" method="post">
|
21
|
+
<%= csrf_tag %>
|
22
22
|
<input class="btn btn-warn pull-left" name="enable" type="submit" value="<%= t('Enable') %>" />
|
23
23
|
</form>
|
24
|
-
<form action="<%= cron_job_path %>/delete" method="post">
|
25
|
-
<%= csrf_tag
|
26
|
-
<input class="btn btn-danger" data-confirm="<%= t('AreYouSureDeleteCronJob', :job => @job.name) %>" name="delete" type="submit" value="<%= t('Delete') %>" />
|
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
27
|
</form>
|
28
28
|
<% end %>
|
29
29
|
</div>
|
@@ -39,6 +39,10 @@
|
|
39
39
|
<th><%= t 'Name' %></th>
|
40
40
|
<td><%= @job.name %></td>
|
41
41
|
</tr>
|
42
|
+
<tr>
|
43
|
+
<th><%= t 'Namespace' %></th>
|
44
|
+
<td><%= @job.namespace %></td>
|
45
|
+
</tr>
|
42
46
|
<tr>
|
43
47
|
<th><%= t 'Description' %></th>
|
44
48
|
<td><%= @job.description %></td>
|
data/lib/sidekiq/cron/web.rb
CHANGED
@@ -1,7 +1,17 @@
|
|
1
1
|
require "sidekiq/cron/web_extension"
|
2
2
|
require "sidekiq/cron/job"
|
3
|
+
require "sidekiq/cron/namespace"
|
3
4
|
|
4
5
|
if defined?(Sidekiq::Web)
|
5
|
-
|
6
|
-
|
6
|
+
if Gem::Version.new(Sidekiq::VERSION) >= Gem::Version.new('7.3.0')
|
7
|
+
Sidekiq::Web.register(
|
8
|
+
Sidekiq::Cron::WebExtension, # Class which contains the HTTP actions, required
|
9
|
+
name: "cron", # the name of the extension, used to namespace assets
|
10
|
+
tab: "Cron", # labels(s) of the UI tabs
|
11
|
+
index: "cron", # index route(s) for each tab
|
12
|
+
)
|
13
|
+
else
|
14
|
+
Sidekiq::Web.register Sidekiq::Cron::WebExtension
|
15
|
+
Sidekiq::Web.tabs["Cron"] = "cron"
|
16
|
+
end
|
7
17
|
end
|
@@ -4,65 +4,112 @@ module Sidekiq
|
|
4
4
|
def self.registered(app)
|
5
5
|
app.settings.locales << File.join(File.expand_path("..", __FILE__), "locales")
|
6
6
|
|
7
|
-
|
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]}"
|
11
|
+
end
|
12
|
+
|
13
|
+
def redirect_to_previous_or_default
|
14
|
+
redirect params['redirect'] || namespace_redirect_path
|
15
|
+
end
|
16
|
+
|
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
|
21
|
+
end
|
22
|
+
|
23
|
+
# Index page.
|
8
24
|
app.get '/cron' do
|
9
|
-
|
25
|
+
@current_namespace = 'default'
|
26
|
+
@cron_jobs = Sidekiq::Cron::Job.all(@current_namespace)
|
10
27
|
|
11
|
-
|
28
|
+
render_erb(:cron)
|
29
|
+
end
|
30
|
+
|
31
|
+
# Detail page for a specific namespace.
|
32
|
+
app.get '/cron/namespaces/:name' do
|
33
|
+
@current_namespace = route_params[:name]
|
34
|
+
@cron_jobs = Sidekiq::Cron::Job.all(@current_namespace)
|
12
35
|
|
13
|
-
|
36
|
+
render_erb(:cron)
|
14
37
|
end
|
15
38
|
|
16
39
|
# Display job detail + jid history.
|
17
|
-
app.get '/cron/:name' do
|
18
|
-
|
40
|
+
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)
|
19
43
|
|
20
|
-
@job = Sidekiq::Cron::Job.find(route_params[:name])
|
21
44
|
if @job
|
22
|
-
|
45
|
+
render_erb(:cron_show)
|
23
46
|
else
|
24
|
-
redirect
|
47
|
+
redirect namespace_redirect_path
|
25
48
|
end
|
26
49
|
end
|
27
50
|
|
51
|
+
# Enqueue all cron jobs.
|
52
|
+
app.post '/cron/namespaces/:namespace/all/enqueue' do
|
53
|
+
Sidekiq::Cron::Job.all(route_params[:namespace]).each(&:enqueue!)
|
54
|
+
|
55
|
+
redirect_to_previous_or_default
|
56
|
+
end
|
57
|
+
|
28
58
|
# Enqueue cron job.
|
29
|
-
app.post '/cron/:name/
|
30
|
-
if route_params[:name]
|
31
|
-
|
32
|
-
elsif job = Sidekiq::Cron::Job.find(route_params[:name])
|
33
|
-
job.enque!
|
59
|
+
app.post '/cron/namespaces/:namespace/jobs/:name/enqueue' do
|
60
|
+
if job = Sidekiq::Cron::Job.find(route_params[:name], route_params[:namespace])
|
61
|
+
job.enqueue!
|
34
62
|
end
|
35
|
-
|
63
|
+
|
64
|
+
redirect_to_previous_or_default
|
65
|
+
end
|
66
|
+
|
67
|
+
# Delete all schedules.
|
68
|
+
app.post '/cron/namespaces/:namespace/all/delete' do
|
69
|
+
Sidekiq::Cron::Job.all(route_params[:namespace]).each(&:destroy)
|
70
|
+
|
71
|
+
redirect_to_previous_or_default
|
36
72
|
end
|
37
73
|
|
38
74
|
# Delete schedule.
|
39
|
-
app.post '/cron/:name/delete' do
|
40
|
-
if route_params[:name]
|
41
|
-
Sidekiq::Cron::Job.all.each(&:destroy)
|
42
|
-
elsif job = Sidekiq::Cron::Job.find(route_params[:name])
|
75
|
+
app.post '/cron/namespaces/:namespace/jobs/:name/delete' do
|
76
|
+
if job = Sidekiq::Cron::Job.find(route_params[:name], route_params[:namespace])
|
43
77
|
job.destroy
|
44
78
|
end
|
45
|
-
|
79
|
+
|
80
|
+
redirect_to_previous_or_default
|
81
|
+
end
|
82
|
+
|
83
|
+
# Enable all jobs.
|
84
|
+
app.post '/cron/namespaces/:namespace/all/enable' do
|
85
|
+
Sidekiq::Cron::Job.all(route_params[:namespace]).each(&:enable!)
|
86
|
+
|
87
|
+
redirect_to_previous_or_default
|
46
88
|
end
|
47
89
|
|
48
90
|
# Enable job.
|
49
|
-
app.post '/cron/:name/enable' do
|
50
|
-
if route_params[:name]
|
51
|
-
Sidekiq::Cron::Job.all.each(&:enable!)
|
52
|
-
elsif job = Sidekiq::Cron::Job.find(route_params[:name])
|
91
|
+
app.post '/cron/namespaces/:namespace/jobs/:name/enable' do
|
92
|
+
if job = Sidekiq::Cron::Job.find(route_params[:name], route_params[:namespace])
|
53
93
|
job.enable!
|
54
94
|
end
|
55
|
-
|
95
|
+
|
96
|
+
redirect_to_previous_or_default
|
97
|
+
end
|
98
|
+
|
99
|
+
# Disable all jobs.
|
100
|
+
app.post '/cron/namespaces/:namespace/all/disable' do
|
101
|
+
Sidekiq::Cron::Job.all(route_params[:namespace]).each(&:disable!)
|
102
|
+
|
103
|
+
redirect_to_previous_or_default
|
56
104
|
end
|
57
105
|
|
58
106
|
# Disable job.
|
59
|
-
app.post '/cron/:name/disable' do
|
60
|
-
if route_params[:name]
|
61
|
-
Sidekiq::Cron::Job.all.each(&:disable!)
|
62
|
-
elsif job = Sidekiq::Cron::Job.find(route_params[:name])
|
107
|
+
app.post '/cron/namespaces/:namespace/jobs/:name/disable' do
|
108
|
+
if job = Sidekiq::Cron::Job.find(route_params[:name], route_params[:namespace])
|
63
109
|
job.disable!
|
64
110
|
end
|
65
|
-
|
111
|
+
|
112
|
+
redirect_to_previous_or_default
|
66
113
|
end
|
67
114
|
end
|
68
115
|
end
|
data/lib/sidekiq/cron.rb
CHANGED
@@ -1,9 +1,77 @@
|
|
1
|
-
require "sidekiq/cron/job"
|
2
|
-
require "sidekiq/cron/poller"
|
3
|
-
require "sidekiq/cron/launcher"
|
4
|
-
require "sidekiq/cron/schedule_loader"
|
5
|
-
|
6
1
|
module Sidekiq
|
7
2
|
module Cron
|
3
|
+
class << self
|
4
|
+
attr_accessor :configuration
|
5
|
+
end
|
6
|
+
|
7
|
+
def self.configure
|
8
|
+
self.configuration ||= Configuration.new
|
9
|
+
yield(configuration) if block_given?
|
10
|
+
end
|
11
|
+
|
12
|
+
def self.reset!
|
13
|
+
self.configuration = Configuration.new
|
14
|
+
end
|
15
|
+
|
16
|
+
class Configuration
|
17
|
+
# The interval, in seconds, at which to poll for scheduled cron jobs.
|
18
|
+
# This determines how frequently the scheduler checks for jobs to enqueue.
|
19
|
+
attr_accessor :cron_poll_interval
|
20
|
+
|
21
|
+
# The path to a YAML file containing multiple cron job schedules.
|
22
|
+
attr_accessor :cron_schedule_file
|
23
|
+
|
24
|
+
# The maximum number of recent cron job execution histories to retain.
|
25
|
+
# This value controls how many past job executions are stored.
|
26
|
+
attr_accessor :cron_history_size
|
27
|
+
|
28
|
+
# The default namespace is used when no namespace is specified.
|
29
|
+
attr_accessor :default_namespace
|
30
|
+
|
31
|
+
# The parsing mode when using the natural language cron syntax from the `fugit` gem.
|
32
|
+
#
|
33
|
+
# :single -- use the first parsed cron line and ignore the rest (default)
|
34
|
+
# :strict -- raise an error if multiple cron lines are parsed from one string
|
35
|
+
attr_reader :natural_cron_parsing_mode
|
36
|
+
|
37
|
+
# The poller will not enqueue jobs that are late by more than this amount of seconds.
|
38
|
+
# Defaults to 60 seconds.
|
39
|
+
#
|
40
|
+
# This is useful when Sidekiq (and Sidekiq-Cron) is not used in zero downtime deployments and
|
41
|
+
# when the deployment is done and Sidekiq-Cron starts to catch up, it will consider older
|
42
|
+
# jobs that missed their schedules during the deployment. E.g., jobs that run once a day.
|
43
|
+
attr_accessor :reschedule_grace_period
|
44
|
+
|
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
|
+
def initialize
|
57
|
+
@cron_poll_interval = 30
|
58
|
+
@cron_schedule_file = 'config/schedule.yml'
|
59
|
+
@cron_history_size = 10
|
60
|
+
@default_namespace = 'default'
|
61
|
+
@natural_cron_parsing_mode = :single
|
62
|
+
@reschedule_grace_period = 60
|
63
|
+
@available_namespaces = nil
|
64
|
+
end
|
65
|
+
|
66
|
+
def natural_cron_parsing_mode=(mode)
|
67
|
+
unless %i[single strict].include?(mode)
|
68
|
+
raise ArgumentError, "Unknown natural cron parsing mode: #{mode.inspect}"
|
69
|
+
end
|
70
|
+
|
71
|
+
@natural_cron_parsing_mode = mode
|
72
|
+
end
|
73
|
+
end
|
8
74
|
end
|
9
75
|
end
|
76
|
+
|
77
|
+
Sidekiq::Cron.configure
|
data/lib/sidekiq/options.rb
CHANGED
@@ -1,5 +1,4 @@
|
|
1
|
-
|
2
|
-
|
1
|
+
# Module to access Sidekiq config
|
3
2
|
module Sidekiq
|
4
3
|
module Options
|
5
4
|
def self.[](key)
|
@@ -16,13 +15,12 @@ module Sidekiq
|
|
16
15
|
|
17
16
|
def self.options_field
|
18
17
|
return @options_field unless @options_field.nil?
|
18
|
+
|
19
19
|
sidekiq_version = Gem::Version.new(Sidekiq::VERSION)
|
20
20
|
@options_field = if sidekiq_version >= Gem::Version.new('7.0')
|
21
21
|
:default_configuration
|
22
|
-
elsif sidekiq_version >= Gem::Version.new('6.5')
|
23
|
-
false
|
24
22
|
else
|
25
|
-
|
23
|
+
false
|
26
24
|
end
|
27
25
|
end
|
28
26
|
end
|
data/lib/sidekiq-cron.rb
CHANGED
data/sidekiq-cron.gemspec
CHANGED
@@ -26,9 +26,10 @@ Gem::Specification.new do |s|
|
|
26
26
|
|
27
27
|
s.required_ruby_version = ">= 2.7"
|
28
28
|
|
29
|
-
s.add_dependency("
|
30
|
-
s.add_dependency("
|
29
|
+
s.add_dependency("cronex", ">= 0.13.0")
|
30
|
+
s.add_dependency("fugit", "~> 1.8", ">= 1.11.1")
|
31
31
|
s.add_dependency("globalid", ">= 1.0.1")
|
32
|
+
s.add_dependency("sidekiq", ">= 6.5.0")
|
32
33
|
|
33
34
|
s.add_development_dependency("minitest", "~> 5.15")
|
34
35
|
s.add_development_dependency("mocha", "~> 2.1")
|
metadata
CHANGED
@@ -1,15 +1,29 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: sidekiq-cron
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 1.
|
4
|
+
version: 2.1.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:
|
11
|
+
date: 2025-01-20 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
|
+
- !ruby/object:Gem::Dependency
|
14
|
+
name: cronex
|
15
|
+
requirement: !ruby/object:Gem::Requirement
|
16
|
+
requirements:
|
17
|
+
- - ">="
|
18
|
+
- !ruby/object:Gem::Version
|
19
|
+
version: 0.13.0
|
20
|
+
type: :runtime
|
21
|
+
prerelease: false
|
22
|
+
version_requirements: !ruby/object:Gem::Requirement
|
23
|
+
requirements:
|
24
|
+
- - ">="
|
25
|
+
- !ruby/object:Gem::Version
|
26
|
+
version: 0.13.0
|
13
27
|
- !ruby/object:Gem::Dependency
|
14
28
|
name: fugit
|
15
29
|
requirement: !ruby/object:Gem::Requirement
|
@@ -17,6 +31,9 @@ dependencies:
|
|
17
31
|
- - "~>"
|
18
32
|
- !ruby/object:Gem::Version
|
19
33
|
version: '1.8'
|
34
|
+
- - ">="
|
35
|
+
- !ruby/object:Gem::Version
|
36
|
+
version: 1.11.1
|
20
37
|
type: :runtime
|
21
38
|
prerelease: false
|
22
39
|
version_requirements: !ruby/object:Gem::Requirement
|
@@ -24,34 +41,37 @@ dependencies:
|
|
24
41
|
- - "~>"
|
25
42
|
- !ruby/object:Gem::Version
|
26
43
|
version: '1.8'
|
44
|
+
- - ">="
|
45
|
+
- !ruby/object:Gem::Version
|
46
|
+
version: 1.11.1
|
27
47
|
- !ruby/object:Gem::Dependency
|
28
|
-
name:
|
48
|
+
name: globalid
|
29
49
|
requirement: !ruby/object:Gem::Requirement
|
30
50
|
requirements:
|
31
51
|
- - ">="
|
32
52
|
- !ruby/object:Gem::Version
|
33
|
-
version:
|
53
|
+
version: 1.0.1
|
34
54
|
type: :runtime
|
35
55
|
prerelease: false
|
36
56
|
version_requirements: !ruby/object:Gem::Requirement
|
37
57
|
requirements:
|
38
58
|
- - ">="
|
39
59
|
- !ruby/object:Gem::Version
|
40
|
-
version:
|
60
|
+
version: 1.0.1
|
41
61
|
- !ruby/object:Gem::Dependency
|
42
|
-
name:
|
62
|
+
name: sidekiq
|
43
63
|
requirement: !ruby/object:Gem::Requirement
|
44
64
|
requirements:
|
45
65
|
- - ">="
|
46
66
|
- !ruby/object:Gem::Version
|
47
|
-
version:
|
67
|
+
version: 6.5.0
|
48
68
|
type: :runtime
|
49
69
|
prerelease: false
|
50
70
|
version_requirements: !ruby/object:Gem::Requirement
|
51
71
|
requirements:
|
52
72
|
- - ">="
|
53
73
|
- !ruby/object:Gem::Version
|
54
|
-
version:
|
74
|
+
version: 6.5.0
|
55
75
|
- !ruby/object:Gem::Dependency
|
56
76
|
name: minitest
|
57
77
|
requirement: !ruby/object:Gem::Requirement
|
@@ -170,11 +190,14 @@ files:
|
|
170
190
|
- lib/sidekiq/cron/launcher.rb
|
171
191
|
- lib/sidekiq/cron/locales/de.yml
|
172
192
|
- lib/sidekiq/cron/locales/en.yml
|
193
|
+
- lib/sidekiq/cron/locales/es.yml
|
194
|
+
- lib/sidekiq/cron/locales/id.yml
|
173
195
|
- lib/sidekiq/cron/locales/it.yml
|
174
196
|
- lib/sidekiq/cron/locales/ja.yml
|
175
197
|
- lib/sidekiq/cron/locales/pt.yml
|
176
198
|
- lib/sidekiq/cron/locales/ru.yml
|
177
199
|
- lib/sidekiq/cron/locales/zh-CN.yml
|
200
|
+
- lib/sidekiq/cron/namespace.rb
|
178
201
|
- lib/sidekiq/cron/poller.rb
|
179
202
|
- lib/sidekiq/cron/schedule_loader.rb
|
180
203
|
- lib/sidekiq/cron/support.rb
|