sidekiq-scheduler 4.0.2 → 4.0.3

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: 46f14eafd933ccc91c36ba3b52babf250a9d17723d8a321b016bad2caaf36262
4
- data.tar.gz: d285ce8992b380f98c05860883c54aa504c83df31aeba252297b1c02d35590a6
3
+ metadata.gz: c16869144651f4193112eb896e092d382af94340b373f11ba92cefbdcc8fa875
4
+ data.tar.gz: 00b8efaca9cfcfe0379b633f5ca8aa215fa1f382fcd86fd29910b7ac64e6db7f
5
5
  SHA512:
6
- metadata.gz: fe3a692c9419fe21b60333f4801c519fa9eb96b2c49f4f7ad9f6bb41001ac8c0b9884ffa01c19018fe5101e2419f09af3df93f3efcd4de11b87b108d785a5047
7
- data.tar.gz: 264780676f625a002b67b88eb03ee12981a2e222889334799e76c1aefde9ec3d35fad50d645233bd27c195113ea14e5af68ad3d82b4f853e7342f6ae2c3d08c3
6
+ metadata.gz: 5afc74e4fa2a54d2b00e9d1a1343f64f242d217bee9c0ec170a4fd502cc7d7233598123c769034b7ad830c75eecab1f9aa99513bcac0d42bcaef91d771ddf7d0
7
+ data.tar.gz: 2e096c861063f78ce359807fd6e58477ca3e8489d645dca3a5c188e5713ed07b61392ddc96ec0d0eb6f5c0c6b3da91aec3c9cf3e27dcd9f4094f37b3185352b1
data/CHANGELOG.md CHANGED
@@ -1,3 +1,12 @@
1
+ # 4.0.3
2
+
3
+ - [**GH Actions**] Add dependabot for GitHub Actions [#390](https://github.com/sidekiq-scheduler/sidekiq-scheduler/pull/390)
4
+ - [**ENHANCEMENT**] Add «Enable all» and «Disable all» buttons [#398](https://github.com/sidekiq-scheduler/sidekiq-scheduler/pull/398)
5
+ - [**ENHANCEMENT**] Allow for multiple applications to share a Redis DB [#401](https://github.com/sidekiq-scheduler/sidekiq-scheduler/pull/401)
6
+ - [**FIX**] Fix metadata for Sidekiq strict_args! [#403](https://github.com/sidekiq-scheduler/sidekiq-scheduler/pull/403)
7
+ - [**FIX**] Redis 5.0 compatibility [#404](https://github.com/sidekiq-scheduler/sidekiq-scheduler/pull/404)
8
+ - [**FIX**] Fix the constantize method [#408](https://github.com/sidekiq-scheduler/sidekiq-scheduler/pull/408)
9
+
1
10
  # 4.0.2
2
11
 
3
12
  - [**FIX**] Fix sidekiq deprecation warning when Sidekiq 6.5+ [#385](https://github.com/sidekiq-scheduler/sidekiq-scheduler/pull/385)
data/README.md CHANGED
@@ -316,6 +316,47 @@ Non-normal conditions that could push a specific job multiple times are:
316
316
 
317
317
  `every`, `interval` and `in` jobs will be pushed once per host.
318
318
 
319
+ ### Suggested setup for Multiple Hosts using Heroku and Rails
320
+
321
+ Configuration options `every`, `interval` and `in` will push once per host. This may be undesirable. One way to achieve single jobs per the schedule would be to manually designate a host as the scheduler. The goal is to have a single scheduler process running across all your hosts.
322
+
323
+ This can be achieved by using an environment variable and controlling the number of dynos. In Rails, you can read this variable during initialization and then conditionally load your config file.
324
+
325
+ Suppose we are using Rails and have the following schedule:
326
+
327
+ ```yaml
328
+ # config/scheduler.yml
329
+ MyRegularJob:
330
+ description: "We want this job to run very often, but we do not want to run more of them as we scale"
331
+ interval: ["1m"]
332
+ queue: default
333
+ ```
334
+
335
+ Then we can conditionally load it via an initializer:
336
+
337
+ ```ruby
338
+ # config/initializer/sidekiq.rb
339
+ if ENV.fetch("IS_SCHEDULER", false)
340
+ Sidekiq.configure_server do |config|
341
+ config.on(:startup) do
342
+ Sidekiq.schedule = YAML.load_file(File.expand_path("../scheduler.yml", File.dirname(__FILE__)))
343
+ Sidekiq::Scheduler.reload_schedule!
344
+ end
345
+ end
346
+ end
347
+ ```
348
+
349
+ Then you would just need to flag the scheduler process when you start it. If you are using a Procfile, it would look like this:
350
+
351
+ ```yaml
352
+ # Procfile
353
+ web: bin/rails server
354
+ worker: bundle exec sidekiq -q default
355
+ scheduler: IS_SCHEDULER=true bundle exec sidekiq -q default
356
+ ```
357
+
358
+ When running via Heroku, you set your `scheduler` process to have 1 dyno. This will ensure you have at most 1 worker loading the schedule.
359
+
319
360
  ## Notes on when Sidekiq worker is down
320
361
 
321
362
  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.
@@ -377,6 +418,22 @@ Redis.
377
418
 
378
419
  See https://github.com/sidekiq-scheduler/sidekiq-scheduler/issues/361 for a more details.
379
420
 
421
+ ## Notes when running multiple applications in the same Redis database
422
+
423
+ _NOTE_: **Although we support this option, we recommend having separate redis databases for each application. Choosing this option is at your own risk.**
424
+
425
+ If you need to run multiple applications with differing schedules, the easiest way is to use a different Redis database per application. Doing that will ensure that each application will have its own schedule, web interface and statistics.
426
+
427
+ However, you may want to have a set of related applications share the same Redis database in order to aggregate statistics and manage them all in a single web interface. To do this while maintaining a different schedule for each application, you can configure each application to use a different `key_prefix` in Redis. This prevents the applications overwriting each others' schedules and schedule data.
428
+
429
+ ```ruby
430
+ Rails.application.reloader.to_prepare do
431
+ SidekiqScheduler::RedisManager.key_prefix = "my-app"
432
+ end
433
+ ```
434
+
435
+ Note that this must be set before the schedule is loaded (or it will go into the wrong key). If you are using the web integration, make sure that the prefix is set in the web process so that you see the correct schedule.
436
+
380
437
  ## Sidekiq Web Integration
381
438
 
382
439
  sidekiq-scheduler provides an extension to the Sidekiq web interface that adds a `Recurring Jobs` page.
@@ -7,7 +7,7 @@ Sidekiq::Web.tabs['recurring_jobs'] = 'recurring-jobs'
7
7
  Sidekiq::Web.locales << File.expand_path("#{File.dirname(__FILE__)}/../../../web/locales")
8
8
 
9
9
  if Sidekiq::VERSION >= '6.0.0'
10
- Sidekiq::Web.use Rack::Static, urls: ['/stylesheets'],
10
+ Sidekiq::Web.use Rack::Static, urls: ['/stylesheets-scheduler'],
11
11
  root: ASSETS_PATH,
12
12
  cascade: true,
13
13
  header_rules: [[:all, { 'Cache-Control' => 'public, max-age=86400' }]]
@@ -9,7 +9,7 @@ module SidekiqScheduler
9
9
  #
10
10
  # @return [String] schedule in JSON format
11
11
  def self.get_job_schedule(name)
12
- hget('schedules', name)
12
+ hget(schedules_key, name)
13
13
  end
14
14
 
15
15
  # Returns the state of a given job
@@ -44,7 +44,7 @@ module SidekiqScheduler
44
44
  # @param [String] name The name of the job
45
45
  # @param [Hash] config The new schedule for the job
46
46
  def self.set_job_schedule(name, config)
47
- hset('schedules', name, JSON.generate(config))
47
+ hset(schedules_key, name, JSON.generate(config))
48
48
  end
49
49
 
50
50
  # Sets the state for a given job
@@ -60,7 +60,7 @@ module SidekiqScheduler
60
60
  # @param [String] name The name of the job
61
61
  # @param [String] next_time The next time the job has to be executed
62
62
  def self.set_job_next_time(name, next_time)
63
- hset(next_times_key, name, next_time)
63
+ hset(next_times_key, name, String(next_time))
64
64
  end
65
65
 
66
66
  # Sets the last execution time for a given job
@@ -68,14 +68,14 @@ module SidekiqScheduler
68
68
  # @param [String] name The name of the job
69
69
  # @param [String] last_time The last time the job was executed
70
70
  def self.set_job_last_time(name, last_time)
71
- hset(last_times_key, name, last_time)
71
+ hset(last_times_key, name, String(last_time))
72
72
  end
73
73
 
74
74
  # Removes the schedule for a given job
75
75
  #
76
76
  # @param [String] name The name of the job
77
77
  def self.remove_job_schedule(name)
78
- hdel('schedules', name)
78
+ hdel(schedules_key, name)
79
79
  end
80
80
 
81
81
  # Removes the next execution time for a given job
@@ -89,14 +89,14 @@ module SidekiqScheduler
89
89
  #
90
90
  # @return [Hash] hash with all the job schedules
91
91
  def self.get_all_schedules
92
- Sidekiq.redis { |r| r.hgetall('schedules') }
92
+ Sidekiq.redis { |r| r.hgetall(schedules_key) }
93
93
  end
94
94
 
95
95
  # Returns boolean value that indicates if the schedules value exists
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 { |r| r.exists?(schedules_key) }
100
100
  end
101
101
 
102
102
  # Returns all the schedule changes for a given time range.
@@ -106,19 +106,19 @@ module SidekiqScheduler
106
106
  #
107
107
  # @return [Array] array with all the changed job names
108
108
  def self.get_schedule_changes(from, to)
109
- Sidekiq.redis { |r| r.zrangebyscore('schedules_changed', from, "(#{to}") }
109
+ Sidekiq.redis { |r| r.zrangebyscore(schedules_changed_key, from, "(#{to}") }
110
110
  end
111
111
 
112
112
  # Register a schedule change for a given job
113
113
  #
114
114
  # @param [String] name The name of the job
115
115
  def self.add_schedule_change(name)
116
- Sidekiq.redis { |r| r.zadd('schedules_changed', Time.now.to_f, name) }
116
+ Sidekiq.redis { |r| r.zadd(schedules_changed_key, Time.now.to_f, name) }
117
117
  end
118
118
 
119
119
  # Remove all the schedule changes records
120
120
  def self.clean_schedules_changed
121
- Sidekiq.redis { |r| r.del('schedules_changed') unless r.type('schedules_changed') == 'zset' }
121
+ Sidekiq.redis { |r| r.del(schedules_changed_key) unless r.type(schedules_changed_key) == 'zset' }
122
122
  end
123
123
 
124
124
  # Removes a queued job instance
@@ -156,28 +156,57 @@ module SidekiqScheduler
156
156
  #
157
157
  # @return [String] the pushed job key
158
158
  def self.pushed_job_key(job_name)
159
- "sidekiq-scheduler:pushed:#{job_name}"
159
+ "#{key_prefix}sidekiq-scheduler:pushed:#{job_name}"
160
160
  end
161
161
 
162
162
  # Returns the key of the Redis hash for job's execution times hash
163
163
  #
164
164
  # @return [String] with the key
165
165
  def self.next_times_key
166
- 'sidekiq-scheduler:next_times'
166
+ "#{key_prefix}sidekiq-scheduler:next_times"
167
167
  end
168
168
 
169
169
  # Returns the key of the Redis hash for job's last execution times hash
170
170
  #
171
171
  # @return [String] with the key
172
172
  def self.last_times_key
173
- 'sidekiq-scheduler:last_times'
173
+ "#{key_prefix}sidekiq-scheduler:last_times"
174
174
  end
175
175
 
176
176
  # Returns the Redis's key for saving schedule states.
177
177
  #
178
178
  # @return [String] with the key
179
179
  def self.schedules_state_key
180
- 'sidekiq-scheduler:states'
180
+ "#{key_prefix}sidekiq-scheduler:states"
181
+ end
182
+
183
+ # Returns the Redis's key for saving schedules.
184
+ #
185
+ # @return [String] with the key
186
+ def self.schedules_key
187
+ "#{key_prefix}schedules"
188
+ end
189
+
190
+ # Returns the Redis's key for saving schedule changes.
191
+ #
192
+ # @return [String] with the key
193
+ def self.schedules_changed_key
194
+ "#{key_prefix}schedules_changed"
195
+ end
196
+
197
+ # Returns the key prefix used to generate all scheduler keys
198
+ #
199
+ # @return [String] with the key prefix
200
+ def self.key_prefix
201
+ @key_prefix
202
+ end
203
+
204
+ # Sets the key prefix used to scope all scheduler keys
205
+ #
206
+ # @param [String] value The string to use as the prefix. A ":" will be appended as a delimiter if needed.
207
+ def self.key_prefix=(value)
208
+ value = "#{value}:" if value && !%w[. :].include?(value[-1])
209
+ @key_prefix = value
181
210
  end
182
211
 
183
212
  private
@@ -148,9 +148,7 @@ module SidekiqScheduler
148
148
  end
149
149
 
150
150
  def try_to_constantize(klass)
151
- klass.is_a?(String) ? klass.constantize : klass
152
- rescue NameError
153
- klass
151
+ SidekiqScheduler::Utils.try_to_constantize(klass)
154
152
  end
155
153
  end
156
154
  end
@@ -158,7 +158,7 @@ module SidekiqScheduler
158
158
  config = prepare_arguments(job_config.dup)
159
159
 
160
160
  if config.delete('include_metadata')
161
- config['args'] = arguments_with_metadata(config['args'], scheduled_at: time.to_f)
161
+ config['args'] = arguments_with_metadata(config['args'], "scheduled_at" => time.to_f)
162
162
  end
163
163
 
164
164
  if SidekiqScheduler::Utils.active_job_enqueue?(config['class'])
@@ -228,6 +228,14 @@ module SidekiqScheduler
228
228
  set_schedule_state(name, state)
229
229
  end
230
230
 
231
+ def toggle_all_jobs(new_state)
232
+ Sidekiq.schedule!.keys.each do |name|
233
+ state = schedule_state(name)
234
+ state['enabled'] = new_state
235
+ set_schedule_state(name, state)
236
+ end
237
+ end
238
+
231
239
  private
232
240
 
233
241
  def new_job(name, interval_type, config, schedule, options)
@@ -49,7 +49,7 @@ module SidekiqScheduler
49
49
  #
50
50
  # @return [Class] the class corresponding to the klass param
51
51
  def self.try_to_constantize(klass)
52
- klass.is_a?(String) ? klass.constantize : klass
52
+ klass.is_a?(String) ? Object.const_get(klass) : klass
53
53
  rescue NameError
54
54
  klass
55
55
  end
@@ -112,8 +112,10 @@ module SidekiqScheduler
112
112
  def self.new_rufus_scheduler(options = {})
113
113
  Rufus::Scheduler.new(options).tap do |scheduler|
114
114
  scheduler.define_singleton_method(:on_post_trigger) do |job, triggered_time|
115
- SidekiqScheduler::Utils.update_job_last_time(job.tags[0], triggered_time)
116
- SidekiqScheduler::Utils.update_job_next_time(job.tags[0], job.next_time)
115
+ if (job_name = job.tags[0])
116
+ SidekiqScheduler::Utils.update_job_last_time(job_name, triggered_time)
117
+ SidekiqScheduler::Utils.update_job_next_time(job_name, job.next_time)
118
+ end
117
119
  end
118
120
  end
119
121
  end
@@ -1,3 +1,3 @@
1
1
  module SidekiqScheduler
2
- VERSION = "4.0.2"
2
+ VERSION = "4.0.3"
3
3
  end
@@ -27,6 +27,11 @@ module SidekiqScheduler
27
27
  SidekiqScheduler::Scheduler.instance.toggle_job_enabled(params[:name])
28
28
  redirect "#{root_path}recurring-jobs"
29
29
  end
30
+
31
+ app.post '/recurring-jobs/toggle-all' do
32
+ SidekiqScheduler::Scheduler.instance.toggle_all_jobs(params[:action] == 'enable')
33
+ redirect "#{root_path}recurring-jobs"
34
+ end
30
35
  end
31
36
  end
32
37
  end
@@ -25,3 +25,18 @@
25
25
  border: 1px solid #555;
26
26
  }
27
27
  }
28
+
29
+ .toggle-all-buttons {
30
+ margin-top: 20px;
31
+ margin-bottom: 10px;
32
+ line-height: 45px;
33
+ text-align: right;
34
+ }
35
+
36
+ @media (max-width: 768px) {
37
+ .toggle-all-buttons {
38
+ margin-top: 0;
39
+ text-align: left;
40
+ line-height: inherit;
41
+ }
42
+ }
data/web/locales/de.yml CHANGED
@@ -12,3 +12,5 @@ de:
12
12
  no_next_time: Keine zukünftige Ausführung für diesen Job
13
13
  disable: Deaktivieren
14
14
  enable: Aktivieren
15
+ disable_all: Alle deaktivieren
16
+ enable_all: Alle aktivieren
data/web/locales/en.yml CHANGED
@@ -12,3 +12,5 @@ en:
12
12
  no_next_time: no next execution for this job
13
13
  disable: Disable
14
14
  enable: Enable
15
+ disable_all: Disable all
16
+ enable_all: Enable all
data/web/locales/ru.yml CHANGED
@@ -12,3 +12,5 @@ ru:
12
12
  no_next_time: выполнение задачи не запланировано
13
13
  disable: Выключить
14
14
  enable: Включить
15
+ disable_all: Выключить все
16
+ enable_all: Включить все
@@ -1,5 +1,5 @@
1
1
  <% if Sidekiq::VERSION >= '6.0.0' %>
2
- <link href="<%= root_path %>stylesheets/recurring_jobs.css" media="screen" rel="stylesheet" type="text/css" />
2
+ <link href="<%= root_path %>stylesheets-scheduler/recurring_jobs.css" media="screen" rel="stylesheet" type="text/css" />
3
3
  <% else %>
4
4
  <style>
5
5
  .recurring-jobs { border-top-left-radius: 4px; border-top-right-radius: 4px; }
@@ -21,10 +21,36 @@
21
21
  .list-group-item-disabled {
22
22
  background-color: #f3d3d3;
23
23
  }
24
+
25
+ .toggle-all-buttons {
26
+ margin-top: 20px;
27
+ margin-bottom: 10px;
28
+ line-height: 45px;
29
+ text-align: right;
30
+ }
31
+
32
+ @media (max-width: 768px) {
33
+ .toggle-all-buttons {
34
+ margin-top: 0;
35
+ text-align: left;
36
+ line-height: inherit;
37
+ }
38
+ }
24
39
  </style>
25
40
  <% end %>
26
41
 
27
- <h3><%= t('recurring_jobs') %></h3>
42
+ <div class="row">
43
+ <div class="col-sm-6">
44
+ <h3><%= t('recurring_jobs') %></h3>
45
+ </div>
46
+ <div class="col-sm-6 toggle-all-buttons">
47
+ <form action="<%= root_path %>recurring-jobs/toggle-all" method="post">
48
+ <%= csrf_tag %>
49
+ <button type="submit" class="btn btn-warn btn-xs" name="action" value="enable"><%= t('enable_all') %></button>
50
+ <button type="submit" class="btn btn-warn btn-xs" name="action" value="disable"><%= t('disable_all') %></button>
51
+ </form>
52
+ </div>
53
+ </div>
28
54
 
29
55
  <div class="recurring-jobs">
30
56
  <ul class="list-group">
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: 4.0.2
4
+ version: 4.0.3
5
5
  platform: ruby
6
6
  authors:
7
7
  - Morton Jonuschat
@@ -10,7 +10,7 @@ authors:
10
10
  autorequire:
11
11
  bindir: bin
12
12
  cert_chain: []
13
- date: 2022-06-27 00:00:00.000000000 Z
13
+ date: 2022-10-05 00:00:00.000000000 Z
14
14
  dependencies:
15
15
  - !ruby/object:Gem::Dependency
16
16
  name: sidekiq
@@ -19,6 +19,9 @@ dependencies:
19
19
  - - ">="
20
20
  - !ruby/object:Gem::Version
21
21
  version: '4'
22
+ - - "<"
23
+ - !ruby/object:Gem::Version
24
+ version: '7'
22
25
  type: :runtime
23
26
  prerelease: false
24
27
  version_requirements: !ruby/object:Gem::Requirement
@@ -26,6 +29,9 @@ dependencies:
26
29
  - - ">="
27
30
  - !ruby/object:Gem::Version
28
31
  version: '4'
32
+ - - "<"
33
+ - !ruby/object:Gem::Version
34
+ version: '7'
29
35
  - !ruby/object:Gem::Dependency
30
36
  name: redis
31
37
  requirement: !ruby/object:Gem::Requirement
@@ -124,20 +130,6 @@ dependencies:
124
130
  - - ">="
125
131
  - !ruby/object:Gem::Version
126
132
  version: '0'
127
- - !ruby/object:Gem::Dependency
128
- name: mock_redis
129
- requirement: !ruby/object:Gem::Requirement
130
- requirements:
131
- - - "~>"
132
- - !ruby/object:Gem::Version
133
- version: 0.28.0
134
- type: :development
135
- prerelease: false
136
- version_requirements: !ruby/object:Gem::Requirement
137
- requirements:
138
- - - "~>"
139
- - !ruby/object:Gem::Version
140
- version: 0.28.0
141
133
  - !ruby/object:Gem::Dependency
142
134
  name: simplecov
143
135
  requirement: !ruby/object:Gem::Requirement
@@ -234,7 +226,7 @@ files:
234
226
  - lib/sidekiq-scheduler/version.rb
235
227
  - lib/sidekiq-scheduler/web.rb
236
228
  - lib/sidekiq/scheduler.rb
237
- - web/assets/stylesheets/recurring_jobs.css
229
+ - web/assets/stylesheets-scheduler/recurring_jobs.css
238
230
  - web/locales/cs.yml
239
231
  - web/locales/de.yml
240
232
  - web/locales/en.yml
@@ -268,7 +260,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
268
260
  - !ruby/object:Gem::Version
269
261
  version: '0'
270
262
  requirements: []
271
- rubygems_version: 3.2.19
263
+ rubygems_version: 3.1.6
272
264
  signing_key:
273
265
  specification_version: 4
274
266
  summary: Light weight job scheduling extension for Sidekiq