sidekiq-cron 1.11.0 → 2.0.0

Sign up to get free protection for your applications and to get access to all the features.
@@ -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" style="margin-top: 20px; margin-bottom: 10px;">
9
- <% cron_job_path = "#{root_path}cron/#{CGI.escape(@job.name).gsub('+', '%20')}" %>
10
- <form action="<%= cron_job_path %>/enque?redirect=<%= cron_job_path %>" method="post">
11
- <%= csrf_tag if respond_to?(:csrf_tag) %>
12
- <input class="btn btn-warn pull-left" name="enque" type="submit" value="<%= t('EnqueueNow') %>" data-confirm="<%= t('AreYouSureEnqueueCronJob', :job => @job.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 if respond_to?(: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 if respond_to?(: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 if respond_to?(: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>
@@ -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
- Sidekiq::Web.register Sidekiq::Cron::WebExtension
6
- Sidekiq::Web.tabs["Cron"] = "cron"
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
- # Index page of cron jobs.
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
- view_path = File.join(File.expand_path("..", __FILE__), "views")
25
+ @current_namespace = 'default'
26
+ @cron_jobs = Sidekiq::Cron::Job.all(@current_namespace)
10
27
 
11
- @cron_jobs = Sidekiq::Cron::Job.all
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
- render(:erb, File.read(File.join(view_path, "cron.erb")))
36
+ render_erb(:cron)
14
37
  end
15
38
 
16
39
  # Display job detail + jid history.
17
- app.get '/cron/:name' do
18
- view_path = File.join(File.expand_path("..", __FILE__), "views")
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
- render(:erb, File.read(File.join(view_path, "cron_show.erb")))
45
+ render_erb(:cron_show)
23
46
  else
24
- redirect "#{root_path}cron"
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/enque' do
30
- if route_params[:name] === '__all__'
31
- Sidekiq::Cron::Job.all.each(&:enque!)
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
- redirect params['redirect'] || "#{root_path}cron"
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] === '__all__'
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
- redirect "#{root_path}cron"
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] === '__all__'
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
- redirect params['redirect'] || "#{root_path}cron"
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] === '__all__'
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
- redirect params['redirect'] || "#{root_path}cron"
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,65 @@
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
+ def initialize
46
+ @cron_poll_interval = 30
47
+ @cron_schedule_file = 'config/schedule.yml'
48
+ @cron_history_size = 10
49
+ @default_namespace = 'default'
50
+ @natural_cron_parsing_mode = :single
51
+ @reschedule_grace_period = 60
52
+ end
53
+
54
+ def natural_cron_parsing_mode=(mode)
55
+ unless %i[single strict].include?(mode)
56
+ raise ArgumentError, "Unknown natural cron parsing mode: #{mode.inspect}"
57
+ end
58
+
59
+ @natural_cron_parsing_mode = mode
60
+ end
61
+ end
8
62
  end
9
63
  end
64
+
65
+ Sidekiq::Cron.configure
@@ -1,24 +1,26 @@
1
- require 'sidekiq'
2
-
1
+ # Module to access Sidekiq config
3
2
  module Sidekiq
4
3
  module Options
5
4
  def self.[](key)
6
- options_field ? Sidekiq.public_send(options_field)[key] : Sidekiq[key]
5
+ self.config[key]
7
6
  end
8
7
 
9
8
  def self.[]=(key, value)
10
- options_field ? Sidekiq.public_send(options_field)[key] = value : Sidekiq[key] = value
9
+ self.config[key] = value
10
+ end
11
+
12
+ def self.config
13
+ options_field ? Sidekiq.public_send(options_field) : Sidekiq
11
14
  end
12
15
 
13
16
  def self.options_field
14
17
  return @options_field unless @options_field.nil?
18
+
15
19
  sidekiq_version = Gem::Version.new(Sidekiq::VERSION)
16
20
  @options_field = if sidekiq_version >= Gem::Version.new('7.0')
17
21
  :default_configuration
18
- elsif sidekiq_version >= Gem::Version.new('6.5')
19
- false
20
22
  else
21
- :options
23
+ false
22
24
  end
23
25
  end
24
26
  end
data/lib/sidekiq-cron.rb CHANGED
@@ -1,2 +1,8 @@
1
1
  require "sidekiq"
2
2
  require "sidekiq/cron"
3
+ require "sidekiq/options"
4
+ require "sidekiq/cron/job"
5
+ require "sidekiq/cron/namespace"
6
+ require "sidekiq/cron/poller"
7
+ require "sidekiq/cron/launcher"
8
+ require "sidekiq/cron/schedule_loader"
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("fugit", "~> 1.8")
30
- s.add_dependency("sidekiq", ">= 6")
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.11.0
4
+ version: 2.0.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: 2023-11-03 00:00:00.000000000 Z
11
+ date: 2024-11-11 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: sidekiq
48
+ name: globalid
29
49
  requirement: !ruby/object:Gem::Requirement
30
50
  requirements:
31
51
  - - ">="
32
52
  - !ruby/object:Gem::Version
33
- version: '6'
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: '6'
60
+ version: 1.0.1
41
61
  - !ruby/object:Gem::Dependency
42
- name: globalid
62
+ name: sidekiq
43
63
  requirement: !ruby/object:Gem::Requirement
44
64
  requirements:
45
65
  - - ">="
46
66
  - !ruby/object:Gem::Version
47
- version: 1.0.1
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: 1.0.1
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,13 @@ 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/id.yml
173
194
  - lib/sidekiq/cron/locales/it.yml
174
195
  - lib/sidekiq/cron/locales/ja.yml
175
196
  - lib/sidekiq/cron/locales/pt.yml
176
197
  - lib/sidekiq/cron/locales/ru.yml
177
198
  - lib/sidekiq/cron/locales/zh-CN.yml
199
+ - lib/sidekiq/cron/namespace.rb
178
200
  - lib/sidekiq/cron/poller.rb
179
201
  - lib/sidekiq/cron/schedule_loader.rb
180
202
  - lib/sidekiq/cron/support.rb
@@ -204,7 +226,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
204
226
  - !ruby/object:Gem::Version
205
227
  version: '0'
206
228
  requirements: []
207
- rubygems_version: 3.4.10
229
+ rubygems_version: 3.5.16
208
230
  signing_key:
209
231
  specification_version: 4
210
232
  summary: Scheduler/Cron for Sidekiq jobs