sidekiq-scheduler 3.0.1 → 3.2.2

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 6a5dc23147c3734bd7b7a0e4807c6dcf6ed445bf556fbfd8a467f00995df3464
4
- data.tar.gz: a4cb767f222114219389a01741a6fb9f62f6b9bc5a1621eb6e6da653c2e0c179
3
+ metadata.gz: b7d47069eda4c979115cb594aa870a55546a7fe1b895053fb2df69b0962163eb
4
+ data.tar.gz: e966ab0f5aa48ec3fef2adfe4327e8b72b38f1c4f8da593052e9227e3396b69c
5
5
  SHA512:
6
- metadata.gz: 5b0e12484ddb14ba56b003176a664815982529823068753a32cadb8a19eb6b7eb6b6b15ce439ffef8186f02f259b444cab253dc1e0e2bad20deaed1325def388
7
- data.tar.gz: 3fe2d0ca59b5eaf22898082cb287daec90b89a9f63364419a9c07b1359f5f748ce90ce81cd2806d4083e672e9cc546e90b8a07d289cc15b6107149c73c459447
6
+ metadata.gz: f45636415dac48c0882d75449475d10de07beb6d1f1bfe2873d71f0264f65f2cb58a7a5dd42ff5bd784d79f46f2bd4f00ceb2d27bae47fcc80796b5dbcd22be8
7
+ data.tar.gz: e338d8ff6767dbe7ea21a22fd23d702d49b7095a64be296843d97dcaa415b9c73867edd0601dd4839ccce91bdf271aabaa458d9954b6cb2e42273dd460428383
data/CHANGELOG.md ADDED
@@ -0,0 +1,11 @@
1
+ # 3.2.2
2
+
3
+ - [FIX] Add support for sidekiq 6.5 #382
4
+
5
+ # 3.2.1
6
+ - Fix CSS not loading on Rails app when Sidekiq < 6 https://github.com/moove-it/sidekiq-scheduler/pull/377
7
+ # 3.2.0
8
+
9
+ - Fix deprecated uses of Redis#pipelined https://github.com/moove-it/sidekiq-scheduler/pull/357
10
+ - Prevent sidekiq_options from overriding ActiveJob queue settings https://github.com/moove-it/sidekiq-scheduler/pull/367
11
+ - Highlight disabled jobs https://github.com/moove-it/sidekiq-scheduler/pull/369
data/README.md CHANGED
@@ -179,6 +179,14 @@ Cron, every, and interval types push jobs into sidekiq in a recurrent manner.
179
179
  every: '45m' # Runs every 45 minutes
180
180
  ```
181
181
 
182
+ The value is parsed by [`Fugit::Duration.parse`](https://github.com/floraison/fugit#fugitduration). It understands quite a number of formats, including human-readable ones:
183
+
184
+ ``` yaml
185
+ every: 45 minutes
186
+ every: 2 hours and 30 minutes
187
+ every: 1.5 hours
188
+ ```
189
+
182
190
  `interval` is similar to `every`, the difference between them is that `interval` type schedules the
183
191
  next execution after the interval has elapsed counting from its last job enqueue.
184
192
 
@@ -272,8 +280,9 @@ Sidekiq.get_schedule
272
280
 
273
281
  ## Time zones
274
282
 
275
- Note that if you use the cron syntax, this will be interpreted as in the server time zone
276
- rather than the `config.time_zone` specified in Rails.
283
+ Note that if you use the cron syntax and are not running a Rails app, this will be interpreted in the server time zone.
284
+
285
+ In a Rails app, [rufus-scheduler](https://github.com/jmettraux/rufus-scheduler) (>= 3.3.3) will use the `config.time_zone` specified in Rails.
277
286
 
278
287
  You can explicitly specify the time zone that rufus-scheduler will use:
279
288
 
@@ -312,6 +321,19 @@ Non-normal conditions that could push a specific job multiple times are:
312
321
 
313
322
  `every`, `interval` and `in` jobs will be pushed once per host.
314
323
 
324
+ ## Notes on when sidekiq worker is down
325
+
326
+ For a `cron`/`at` (and all other) job to be successfully enqueued, you need at least one sidekiq worker with scheduler to be up at that moment. Handling this is up to you and depends on your application.
327
+
328
+ Possible solutions include:
329
+ - Simply ignoring this fact, if you only run frequent periodic jobs, that can tolerate some increased interval
330
+ - Abstaining from deploys/restarts during time when critical jobs are usually scheduled
331
+ - Making your infrequent jobs idempotent (so that they can be enqueued multiple times but still produce result as if was run once) and scheduling them multiple times to reduce likelihood of not being run
332
+ - Zero downtime deploy for sidekiq workers: keep at least one worker up during whole deploy and only restart/shut it down after when new one has started
333
+ - Running scheduler inside your unicorn/rails processes (if you already have zero downtime deploy set up for these)
334
+
335
+ Each option has it's own pros and cons.
336
+
315
337
  ## Sidekiq Web Integration
316
338
 
317
339
  sidekiq-scheduler provides an extension to the Sidekiq web interface that adds a `Recurring Jobs` page.
@@ -1,5 +1,14 @@
1
1
  require 'sidekiq/web' unless defined?(Sidekiq::Web)
2
2
 
3
+ ASSETS_PATH = File.expand_path('../../../web/assets', __dir__)
4
+
3
5
  Sidekiq::Web.register(SidekiqScheduler::Web)
4
6
  Sidekiq::Web.tabs['recurring_jobs'] = 'recurring-jobs'
5
- Sidekiq::Web.locales << File.expand_path(File.dirname(__FILE__) + '/../../../web/locales')
7
+ Sidekiq::Web.locales << File.expand_path("#{File.dirname(__FILE__)}/../../../web/locales")
8
+
9
+ if Sidekiq::VERSION >= '6.0.0'
10
+ Sidekiq::Web.use Rack::Static, urls: ['/stylesheets'],
11
+ root: ASSETS_PATH,
12
+ cascade: true,
13
+ header_rules: [[:all, { 'Cache-Control' => 'public, max-age=86400' }]]
14
+ end
@@ -1,7 +1,5 @@
1
1
  require 'redis'
2
2
 
3
- require 'sidekiq/util'
4
-
5
3
  require 'sidekiq-scheduler/schedule'
6
4
  require 'sidekiq-scheduler/scheduler'
7
5
 
@@ -12,8 +10,6 @@ module SidekiqScheduler
12
10
  # from Redis onto the work queues
13
11
  #
14
12
  class Manager
15
- include Sidekiq::Util
16
-
17
13
  DEFAULT_SCHEDULER_OPTIONS = {
18
14
  enabled: true,
19
15
  dynamic: false,
@@ -37,10 +33,6 @@ module SidekiqScheduler
37
33
  @scheduler_instance.load_schedule!
38
34
  end
39
35
 
40
- def reset
41
- clear_scheduled_work
42
- end
43
-
44
36
  private
45
37
 
46
38
  def load_scheduler_options(options)
@@ -96,7 +96,14 @@ module SidekiqScheduler
96
96
  #
97
97
  # @return [Boolean] true if the schedules key is set, false otherwise
98
98
  def self.schedule_exist?
99
- Sidekiq.redis { |r| r.exists(:schedules) }
99
+ Sidekiq.redis do |r|
100
+ case r.exists(:schedules)
101
+ when true, 1
102
+ true
103
+ else
104
+ false
105
+ end
106
+ end
100
107
  end
101
108
 
102
109
  # Returns all the schedule changes for a given time range.
@@ -130,9 +137,9 @@ module SidekiqScheduler
130
137
  def self.register_job_instance(job_name, time)
131
138
  job_key = pushed_job_key(job_name)
132
139
  registered, _ = Sidekiq.redis do |r|
133
- r.pipelined do
134
- r.zadd(job_key, time.to_i, time.to_i)
135
- r.expire(job_key, REGISTERED_JOBS_THRESHOLD_IN_SECONDS)
140
+ r.pipelined do |pipeline|
141
+ pipeline.zadd(job_key, time.to_i, time.to_i)
142
+ pipeline.expire(job_key, REGISTERED_JOBS_THRESHOLD_IN_SECONDS)
136
143
  end
137
144
  end
138
145
 
@@ -140,7 +140,9 @@ module SidekiqScheduler
140
140
  def infer_queue(klass)
141
141
  klass = try_to_constantize(klass)
142
142
 
143
- if klass.respond_to?(:sidekiq_options)
143
+ # ActiveJob uses queue_as when the job is created
144
+ # to determine the queue
145
+ if klass.respond_to?(:sidekiq_options) && !SidekiqScheduler::Utils.active_job_enqueue?(klass)
144
146
  klass.sidekiq_options['queue']
145
147
  end
146
148
  end
@@ -1,15 +1,11 @@
1
1
  require 'rufus/scheduler'
2
2
  require 'thwait'
3
- require 'sidekiq/util'
4
3
  require 'json'
5
- require 'sidekiq-scheduler/manager'
6
4
  require 'sidekiq-scheduler/rufus_utils'
7
5
  require 'sidekiq-scheduler/redis_manager'
8
6
 
9
7
  module SidekiqScheduler
10
8
  class Scheduler
11
- extend Sidekiq::Util
12
-
13
9
  # We expect rufus jobs to have #params
14
10
  Rufus::Scheduler::Job.module_eval do
15
11
  alias_method :params, :opts
@@ -162,7 +158,7 @@ module SidekiqScheduler
162
158
  config['args'] = arguments_with_metadata(config['args'], scheduled_at: time.to_f)
163
159
  end
164
160
 
165
- if active_job_enqueue?(config['class'])
161
+ if SidekiqScheduler::Utils.active_job_enqueue?(config['class'])
166
162
  SidekiqScheduler::Utils.enqueue_with_active_job(config)
167
163
  else
168
164
  SidekiqScheduler::Utils.enqueue_with_sidekiq(config)
@@ -308,17 +304,6 @@ module SidekiqScheduler
308
304
  queues.empty? || queues.include?(job_queue)
309
305
  end
310
306
 
311
- # Returns true if the enqueuing needs to be done for an ActiveJob
312
- # class false otherwise.
313
- #
314
- # @param [Class] klass the class to check is decendant from ActiveJob
315
- #
316
- # @return [Boolean]
317
- def active_job_enqueue?(klass)
318
- klass.is_a?(Class) && defined?(ActiveJob::Enqueuing) &&
319
- klass.included_modules.include?(ActiveJob::Enqueuing)
320
- end
321
-
322
307
  # Convert the given arguments in the format expected to be enqueued.
323
308
  #
324
309
  # @param [Hash] config the options to be converted
@@ -68,6 +68,17 @@ module SidekiqScheduler
68
68
  end
69
69
  end
70
70
 
71
+ # Returns true if the enqueuing needs to be done for an ActiveJob
72
+ # class false otherwise.
73
+ #
74
+ # @param [Class] klass the class to check is decendant from ActiveJob
75
+ #
76
+ # @return [Boolean]
77
+ def self.active_job_enqueue?(klass)
78
+ klass.is_a?(Class) && defined?(ActiveJob::Enqueuing) &&
79
+ klass.included_modules.include?(ActiveJob::Enqueuing)
80
+ end
81
+
71
82
  # Enqueues the job using the Sidekiq client.
72
83
  #
73
84
  # @param [Hash] config The job configuration
@@ -1,5 +1,3 @@
1
1
  module SidekiqScheduler
2
-
3
- VERSION = '3.0.1'
4
-
2
+ VERSION = '3.2.2'
5
3
  end
@@ -15,13 +15,13 @@ module SidekiqScheduler
15
15
  erb File.read(File.join(VIEW_PATH, 'recurring_jobs.erb'))
16
16
  end
17
17
 
18
- app.get '/recurring-jobs/:name/enqueue' do
18
+ app.post '/recurring-jobs/:name/enqueue' do
19
19
  schedule = Sidekiq.get_schedule(params[:name])
20
20
  SidekiqScheduler::Scheduler.instance.enqueue_job(schedule)
21
21
  redirect "#{root_path}recurring-jobs"
22
22
  end
23
23
 
24
- app.get '/recurring-jobs/:name/toggle' do
24
+ app.post '/recurring-jobs/:name/toggle' do
25
25
  Sidekiq.reload_schedule!
26
26
 
27
27
  SidekiqScheduler::Scheduler.instance.toggle_job_enabled(params[:name])
@@ -0,0 +1,27 @@
1
+ .recurring-jobs { border-top-left-radius: 4px; border-top-right-radius: 4px; }
2
+ .recurring-jobs .title { margin-bottom: 5px; }
3
+ .recurring-jobs .title .name { font-weight: bold;}
4
+ .recurring-jobs .info,
5
+ .recurring-jobs .description { margin-bottom: 5px; }
6
+ .recurring-jobs .actions { margin-bottom: 5px; }
7
+ .recurring-jobs .status,
8
+ .recurring-jobs .description { font-size: 12px; }
9
+ .recurring-jobs .enqueue { margin-bottom: 0.5rem }
10
+
11
+ .list-group-item {
12
+ background-color: #f3f3f3;
13
+ color: #585454;
14
+ border: 1px solid rgba(0, 0, 0, 0.1);
15
+ }
16
+
17
+ .list-group-item-disabled {
18
+ background-color: #f3d3d3;
19
+ }
20
+
21
+ @media (prefers-color-scheme: dark) {
22
+ .list-group-item {
23
+ background-color: #222;
24
+ color: white;
25
+ border: 1px solid #555;
26
+ }
27
+ }
@@ -1,48 +1,74 @@
1
- <h3><%= t('recurring_jobs') %></h3>
1
+ <% if Sidekiq::VERSION >= '6.0.0' %>
2
+ <link href="<%= root_path %>stylesheets/recurring_jobs.css" media="screen" rel="stylesheet" type="text/css" />
3
+ <% else %>
4
+ <style>
5
+ .recurring-jobs { border-top-left-radius: 4px; border-top-right-radius: 4px; }
6
+ .recurring-jobs .title { margin-bottom: 5px; }
7
+ .recurring-jobs .title .name { font-weight: bold;}
8
+ .recurring-jobs .info,
9
+ .recurring-jobs .description { margin-bottom: 5px; }
10
+ .recurring-jobs .actions { margin-bottom: 5px; }
11
+ .recurring-jobs .status,
12
+ .recurring-jobs .description { font-size: 12px; }
13
+ .recurring-jobs .enqueue { margin-bottom: 0.5rem }
14
+
15
+ .list-group-item {
16
+ background-color: #f3f3f3;
17
+ color: #585454;
18
+ border: 1px solid rgba(0, 0, 0, 0.1);
19
+ }
2
20
 
3
- <div class="table_container">
4
- <table class="table table-hover table-bordered table-striped table-white">
5
- <thead>
6
- <tr>
7
- <th><%= t('name') %></th>
8
- <th><%= t('description') %></th>
9
- <th><%= t('interval') %></th>
10
- <th><%= t('class') %></th>
11
- <th><%= t('queue') %></th>
12
- <th><%= t('arguments') %></th>
13
- <th><%= t('last_time') %></th>
14
- <th><%= t('next_time') %></th>
15
- <th></th>
16
- </tr>
17
- </thead>
21
+ .list-group-item-disabled {
22
+ background-color: #f3d3d3;
23
+ }
24
+ </style>
25
+ <% end %>
26
+
27
+ <h3><%= t('recurring_jobs') %></h3>
18
28
 
19
- <tbody>
20
- <% @presented_jobs.each do |job| %>
21
- <tr>
22
- <td><%= job.name %></td>
23
- <td><%= job['description'] %></td>
24
- <td><%= job.interval %></td>
25
- <td><%= job['class'] %></td>
26
- <td>
27
- <a href="<%= root_path %>queues/<%= job.queue %>"><%= job.queue %></a>
28
- </td>
29
- <td><%= job['args'] %></td>
30
- <td><%= job.last_time %></td>
31
- <td>
32
- <span style="<%= 'text-decoration:line-through' unless job.enabled? %>">
33
- <%= job.next_time || t('no_next_time') %>
29
+ <div class="recurring-jobs">
30
+ <ul class="list-group">
31
+ <% @presented_jobs.each do |job| %>
32
+ <li class="list-group-item <%= !job.enabled? && "list-group-item-disabled" %>">
33
+ <div class="title">
34
+ <div class="row">
35
+ <div class="col-xs-6">
36
+ <span class="name"><%= job.name %></span>
37
+ </div>
38
+ <div class="col-xs-6 text-right">
39
+ <a href="<%= root_path %>queues/<%= job.queue %>"><%= job.queue %></a>
40
+ </div>
41
+ </div>
42
+ </div>
43
+ <div class="description"><%= job['description'] %></div>
44
+ <div class="info">
45
+ <div class="row">
46
+ <div class="col-md-4 class"><%= job['class'] %></div>
47
+ <div class="col-md-4 interval text-left"><%= t('interval') %>: <%= job.interval %></div>
48
+ <div class="col-md-4 args"><%= t('arguments') %>: <%= job['args'] %></div>
49
+ </div>
50
+ </div>
51
+ <div class="status row">
52
+ <div class="col-md-4 actions">
53
+ <form action="<%= root_path %>recurring-jobs/<%= ERB::Util.url_encode(job.name) %>/enqueue" method="post" class="enqueue">
54
+ <%= csrf_tag %>
55
+ <input type="submit" class="btn btn-warn btn-xs" value="<%= t('enqueue_now') %>" />
56
+ </form>
57
+ <form action="<%= root_path %>recurring-jobs/<%= ERB::Util.url_encode(job.name) %>/toggle" method="post">
58
+ <%= csrf_tag %>
59
+ <input type="submit" class="btn <%= job.enabled? ? "btn-primary" : "btn-warn"%> btn-xs" value="<%= job.enabled? ? t('disable') : t('enable') %>" />
60
+ </form>
61
+ </div>
62
+ <div class="col-md-4">
63
+ <span class="last_time"><%= t('last_time') %>: <%= job.last_time %></span>
64
+ </div>
65
+ <div class="col-md-4">
66
+ <span class="next_time text-right" style="<%= 'text-decoration:line-through' unless job.enabled? %>">
67
+ <%= t('next_time') %>: <%= job.next_time || t('no_next_time') %>
34
68
  </span>
35
- </td>
36
- <td class="text-center">
37
- <a class="btn btn-warn btn-xs" href="<%= root_path %>recurring-jobs/<%= URI.escape(job.name) %>/enqueue">
38
- <%= t('enqueue_now') %>
39
- </a>
40
- <a class="btn <%= job.enabled? ? "btn-primary" : "btn-warn"%> btn-xs" href="<%= root_path %>recurring-jobs/<%= URI.escape(job.name) %>/toggle">
41
- <%= job.enabled? ? t('disable') : t('enable') %>
42
- </a>
43
- </td>
44
- </tr>
45
- <% end %>
46
- </tbody>
47
- </table>
69
+ </div>
70
+ </div>
71
+ </li>
72
+ <% end %>
73
+ </ul>
48
74
  </div>
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: sidekiq-scheduler
3
3
  version: !ruby/object:Gem::Version
4
- version: 3.0.1
4
+ version: 3.2.2
5
5
  platform: ruby
6
6
  authors:
7
7
  - Morton Jonuschat
@@ -9,7 +9,7 @@ authors:
9
9
  autorequire:
10
10
  bindir: bin
11
11
  cert_chain: []
12
- date: 2020-02-03 00:00:00.000000000 Z
12
+ date: 2022-06-08 00:00:00.000000000 Z
13
13
  dependencies:
14
14
  - !ruby/object:Gem::Dependency
15
15
  name: sidekiq
@@ -263,6 +263,7 @@ executables: []
263
263
  extensions: []
264
264
  extra_rdoc_files: []
265
265
  files:
266
+ - CHANGELOG.md
266
267
  - MIT-LICENSE
267
268
  - README.md
268
269
  - Rakefile
@@ -279,6 +280,7 @@ files:
279
280
  - lib/sidekiq-scheduler/version.rb
280
281
  - lib/sidekiq-scheduler/web.rb
281
282
  - lib/sidekiq/scheduler.rb
283
+ - web/assets/stylesheets/recurring_jobs.css
282
284
  - web/locales/cs.yml
283
285
  - web/locales/de.yml
284
286
  - web/locales/en.yml
@@ -312,7 +314,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
312
314
  - !ruby/object:Gem::Version
313
315
  version: '0'
314
316
  requirements: []
315
- rubygems_version: 3.1.2
317
+ rubygems_version: 3.2.19
316
318
  signing_key:
317
319
  specification_version: 4
318
320
  summary: Light weight job scheduling extension for Sidekiq