sidekiq-cron 2.0.0.rc1 → 2.0.0.rc2

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: dce1f7b341e293e80c0b8981c03b24293c2922f4133f62882bcbee62fa3b12d6
4
- data.tar.gz: 210bcfa247b4801bdb86a0d1f5c0454721172abebf0c2e5354be24caee1d6628
3
+ metadata.gz: d2fa6abcb1076d5e510764b33d0cfdd18d18fd1e585d79c63d300e37a1e0e6db
4
+ data.tar.gz: 4a04a46b7444879c6291a52e783ece82fa3488fe042106eef525ac81cd6a2d72
5
5
  SHA512:
6
- metadata.gz: cd604c51a98b3b2d1a0af7fdf59afb599f9e9af717043bbbe2816a519be5824694415b59ebd8ec21fa09069798e71bb2d69ae9a62fbf177864f3adcf3c4fc1d3
7
- data.tar.gz: '08ebb6f111498fd8f9b377eed43f17be760caace33185fec69b68e7e5f8ef89d5ee0bd34fe91d714d2c4d5af995e7297909a14e827cf4dce43b7974a859ae50f'
6
+ metadata.gz: bfd60ceaa0999e67bcc3a123ea767c8ed222a70621f688b0456f189386065570160e53cae1810dcc045b33b03101af5d3f9255b3c8afe6d963255ea9004ead06
7
+ data.tar.gz: b08f12f1ce7ca1495013c9eae44b4469371b2d3aeb6e81675c044133391ce411c6f1f4e71206776632a37b58d7594842ea38a0e2cb94ee18f32a70409b20249a
data/CHANGELOG.md CHANGED
@@ -2,6 +2,17 @@
2
2
 
3
3
  All notable changes to this project will be documented in this file.
4
4
 
5
+ ## 2.0.0.rc2
6
+
7
+ - Remove support for Sidekiq < 6.5 (https://github.com/sidekiq-cron/sidekiq-cron/pull/480)
8
+ - Require at least Fugit >= 1.11.1 (https://github.com/sidekiq-cron/sidekiq-cron/pull/475)
9
+ - Update how Redis values are stored on save (https://github.com/sidekiq-cron/sidekiq-cron/pull/479)
10
+ - Web extension: Add compatibility with Sidekiq 7.3+ and remove inline styles (https://github.com/sidekiq-cron/sidekiq-cron/pull/480)
11
+ - Remove support for old Redis (< 4.2) (https://github.com/sidekiq-cron/sidekiq-cron/pull/490)
12
+ - Ensure date_as_argument option can be set from true to false in Sidekiq Cron jobs (https://github.com/sidekiq-cron/sidekiq-cron/pull/485)
13
+ - Rename `enque!` to `enqueue!` (https://github.com/sidekiq-cron/sidekiq-cron/pull/494)
14
+ - Refactor gem configuration module (https://github.com/sidekiq-cron/sidekiq-cron/pull/495)
15
+
5
16
  ## 2.0.0.rc1
6
17
 
7
18
  - Introduce `Namespacing` (https://github.com/sidekiq-cron/sidekiq-cron/pull/268)
data/README.md CHANGED
@@ -8,7 +8,7 @@
8
8
 
9
9
  🎬 [Introduction video about Sidekiq-Cron by Drifting Ruby](https://www.driftingruby.com/episodes/periodic-tasks-with-sidekiq-cron)
10
10
 
11
- Sidekiq-Cron runs a thread alongside Sidekiq workers to schedule jobs at specified times (using cron notation `* * * * *` parsed by [Fugit](https://github.com/floraison/fugit)).
11
+ Sidekiq-Cron runs a thread alongside Sidekiq workers to schedule jobs at specified times (using cron notation `* * * * *` or natural language, powered by [Fugit](https://github.com/floraison/fugit)).
12
12
 
13
13
  Checks for new jobs to schedule every 30 seconds and doesn't schedule the same job multiple times when more than one Sidekiq process is running.
14
14
 
@@ -16,10 +16,6 @@ Scheduling jobs are added only when at least one Sidekiq process is running, but
16
16
 
17
17
  If you want to know how scheduling work, check out [under the hood](#under-the-hood).
18
18
 
19
- Works with ActiveJob (Rails 4.2+).
20
-
21
- You don't need Sidekiq PRO, you can use this gem with plain Sidekiq.
22
-
23
19
  ## Changelog
24
20
 
25
21
  Before upgrading to a new version, please read our [Changelog](CHANGELOG.md).
@@ -56,9 +52,9 @@ gem "sidekiq-cron"
56
52
  'queue' => 'name of queue',
57
53
  'args' => '[Array or Hash] of arguments which will be passed to perform method',
58
54
  'date_as_argument' => true, # add the time of execution as last argument of the perform method
59
- 'active_job' => true, # enqueue job through Rails 4.2+ Active Job interface
60
- 'queue_name_prefix' => 'prefix', # Rails 4.2+ Active Job queue with prefix
61
- 'queue_name_delimiter' => '.', # Rails 4.2+ Active Job queue with custom delimiter (default: '_')
55
+ 'active_job' => true, # enqueue job through Active Job interface
56
+ 'queue_name_prefix' => 'prefix', # Active Job queue with prefix
57
+ 'queue_name_delimiter' => '.', # Active Job queue with custom delimiter (default: '_')
62
58
  'description' => 'A sentence describing what work this job performs'
63
59
  'status' => 'disabled' # default: enabled
64
60
  }
@@ -66,6 +62,23 @@ gem "sidekiq-cron"
66
62
 
67
63
  **NOTE** The `status` of a job does not get changed in Redis when a job gets reloaded unless the `status` property is explicitly set.
68
64
 
65
+ ### Configuration
66
+
67
+ All configuration options:
68
+
69
+ ```ruby
70
+ Sidekiq::Cron.configure do |config|
71
+ config.cron_poll_interval = 10
72
+ config.cron_schedule_file = 'config/my_schedule.yml'
73
+ config.default_namespace = 'statistics'
74
+ config.natural_cron_parsing_mode = :single
75
+ config.reschedule_grace_period = 100
76
+ config.cron_history_size = 50
77
+ end
78
+ ```
79
+
80
+ If you are using Rails, add them inside an initializer (`config/initializers/sidekiq-cron.rb`).
81
+
69
82
  ### Time, cron and Sidekiq-Cron
70
83
 
71
84
  For testing your cron notation you can use [crontab.guru](https://crontab.guru).
@@ -79,9 +92,9 @@ like this `'0 22 * * 1-5 America/Chicago'`.
79
92
 
80
93
  #### Natural-language formats
81
94
 
82
- Since sidekiq-cron `v1.7.0`, you can use the natural-language formats supported by Fugit, such as:
95
+ Since Sidekiq-Cron `v1.7.0`, you can use the natural-language formats supported by Fugit, such as:
83
96
 
84
- ```rb
97
+ ```ruby
85
98
  "every day at five" # => '0 5 * * *'
86
99
  "every 3 hours" # => '0 */3 * * *'
87
100
  ```
@@ -122,7 +135,7 @@ Ex. `every day at 3:15 and 4:30`
122
135
 
123
136
  #### Second-precision (sub-minute) cronlines
124
137
 
125
- In addition to the standard 5-parameter cronline format, sidekiq-cron supports scheduling jobs with second-precision using a modified 6-parameter cronline format:
138
+ In addition to the standard 5-parameter cronline format, Sidekiq-Cron supports scheduling jobs with second-precision using a modified 6-parameter cronline format:
126
139
 
127
140
  `Seconds Minutes Hours Days Months DayOfWeek`
128
141
 
@@ -131,7 +144,9 @@ For example: `"*/30 * * * * *"` would schedule a job to run every 30 seconds.
131
144
  Note that if you plan to schedule jobs with second precision you may need to override the default schedule poll interval so it is lower than the interval of your jobs:
132
145
 
133
146
  ```ruby
134
- Sidekiq::Options[:cron_poll_interval] = 10
147
+ Sidekiq::Cron.configure do |config|
148
+ config.cron_poll_interval = 10
149
+ end
135
150
  ```
136
151
 
137
152
  The default value at time of writing is 30 seconds. See [under the hood](#under-the-hood) for more details.
@@ -142,9 +157,7 @@ The default value at time of writing is 30 seconds. See [under the hood](#under-
142
157
 
143
158
  When not giving a namespace, the `default` one will be used.
144
159
 
145
- In the case you'd like to change this value, create a new initializer like so:
146
-
147
- `config/initializers/sidekiq-cron.rb`:
160
+ In the case you'd like to change this value, you can change it via the following configuration flag:
148
161
 
149
162
  ```ruby
150
163
  Sidekiq::Cron.configure do |config|
@@ -222,7 +235,7 @@ class ExampleJob < ActiveJob::Base
222
235
  end
223
236
  ```
224
237
 
225
- For Active jobs you can use `symbolize_args: true` in `Sidekiq::Cron::Job.create` or in Hash configuration,
238
+ For Active Job you can use `symbolize_args: true` in `Sidekiq::Cron::Job.create` or in Hash configuration,
226
239
  which will ensure that arguments you are passing to it will be symbolized when passed back to `perform` method in worker.
227
240
 
228
241
  ### Adding Cron jobs
@@ -261,7 +274,7 @@ end
261
274
 
262
275
  Use ActiveRecord models as arguments:
263
276
 
264
- ```rb
277
+ ```ruby
265
278
  class Person < ApplicationRecord
266
279
  end
267
280
 
@@ -325,7 +338,7 @@ Sidekiq::Cron::Job.load_from_array! array
325
338
 
326
339
  ### Loading jobs from schedule file
327
340
 
328
- You can also load multiple jobs from a YAML (same notation as `Resque-scheduler`) file:
341
+ You can also load multiple jobs from a YAML file:
329
342
 
330
343
  ```yaml
331
344
  # config/schedule.yml
@@ -346,24 +359,31 @@ second_job:
346
359
  There are multiple ways to load the jobs from a YAML file
347
360
 
348
361
  1. The gem will automatically load the jobs mentioned in `config/schedule.yml` file (it supports ERB)
349
- 2. When you want to load jobs from a different filename, mention the filename in sidekiq configuration, i.e. `cron_schedule_file: "config/users_schedule.yml"`
362
+ 2. When you want to load jobs from a different filename, mention the filename in Sidekiq configuration as follows:
363
+
364
+ ```ruby
365
+ Sidekiq::Cron.configure do |config|
366
+ config.cron_schedule_file = "config/users_schedule.yml"
367
+ end
368
+ ```
369
+
350
370
  3. Load the file manually as follows:
351
371
 
352
- ```ruby
353
- # config/initializers/sidekiq.rb
372
+ ```ruby
373
+ # config/initializers/sidekiq.rb
354
374
 
355
- Sidekiq.configure_server do |config|
356
- config.on(:startup) do
357
- schedule_file = "config/users_schedule.yml"
375
+ Sidekiq.configure_server do |config|
376
+ config.on(:startup) do
377
+ schedule_file = "config/users_schedule.yml"
358
378
 
359
- if File.exist?(schedule_file)
360
- schedule = YAML.load_file(schedule_file)
379
+ if File.exist?(schedule_file)
380
+ schedule = YAML.load_file(schedule_file)
361
381
 
362
- Sidekiq::Cron::Job.load_from_hash!(schedule, source: "schedule")
382
+ Sidekiq::Cron::Job.load_from_hash!(schedule, source: "schedule")
383
+ end
384
+ end
363
385
  end
364
- end
365
- end
366
- ```
386
+ ```
367
387
 
368
388
  ### Finding jobs
369
389
 
@@ -409,7 +429,7 @@ job.status
409
429
  # => enabled/disabled
410
430
 
411
431
  # enqueue job right now!
412
- job.enque!
432
+ job.enqueue!
413
433
  ```
414
434
 
415
435
  ### Schedule vs Dynamic jobs
@@ -448,14 +468,14 @@ Sidekiq-Cron adds itself into this start procedure and starts another thread wit
448
468
  Sidekiq-Cron is checking jobs to be enqueued every 30s by default, you can change it by setting:
449
469
 
450
470
  ```ruby
451
- Sidekiq::Options[:cron_poll_interval] = 10
471
+ Sidekiq::Cron.configure do |config|
472
+ config.cron_poll_interval = 10
473
+ end
452
474
  ```
453
475
 
454
- When sidekiq (and sidekiq-cron) is not used in zero-downtime deployments, after the deployment is done sidekiq-cron starts to catch up. It will consider older jobs that missed their schedules during that time. By default, only jobs that should have started less than 1 minute ago are considered. This is problematic for some jobs, e.g., jobs that run once a day. If on average sidekiq is shut down for 10 minutes during deployments, you can configure sidekiq-cron to consider jobs that were about to be scheduled during that time:
476
+ When Sidekiq (and Sidekiq-Cron) is not used in zero-downtime deployments, after the deployment is done Sidekiq-Cron starts to catch up. It will consider older jobs that missed their schedules during that time. By default, only jobs that should have started less than 1 minute ago are considered. This is problematic for some jobs, e.g., jobs that run once a day. If on average Sidekiq is shut down for 10 minutes during deployments, you can configure Sidekiq-Cron to consider jobs that were about to be scheduled during that time:
455
477
 
456
478
  ```ruby
457
- # config/initializers/sidekiq-cron.rb
458
-
459
479
  Sidekiq::Cron.configure do |config|
460
480
  config.reschedule_grace_period = 600 # 10 minutes in seconds
461
481
  end
@@ -463,7 +483,13 @@ end
463
483
 
464
484
  Sidekiq-Cron is safe to use with multiple Sidekiq processes or nodes. It uses a Redis sorted set to determine that only the first process who asks can enqueue scheduled jobs into the queue.
465
485
 
466
- When running with many Sidekiq processes, the polling can add significant load to Redis. You can disable polling on some processes by setting `Sidekiq::Options[:cron_poll_interval] = 0` on these processes.
486
+ When running with many Sidekiq processes, the polling can add significant load to Redis. You can disable polling on some processes by setting:
487
+
488
+ ```ruby
489
+ Sidekiq::Cron.configure do |config|
490
+ config.cron_poll_interval = 0
491
+ end
492
+ ```
467
493
 
468
494
  ## Contributing
469
495
 
@@ -487,21 +513,21 @@ $ bundle exec rake test
487
513
 
488
514
  ### Using Docker
489
515
 
490
- [Docker](https://www.docker.com) allows you to run things in containers easing the development process.
491
-
492
516
  This project uses [Docker Compose](https://docs.docker.com/compose/) in order to orchestrate containers and get the test suite running on you local machine, and here you find the commands to run in order to get a complete environment to build and test this gem:
493
517
 
494
518
  1. Build the Docker image (only the first time):
495
519
  ```
496
520
  docker compose -f docker/docker-compose.yml build
497
521
  ```
522
+
498
523
  2. Run the test suite:
499
524
  ```
500
525
  docker compose -f docker/docker-compose.yml run --rm tests
501
526
  ```
527
+
502
528
  _This command will download the first time the project's dependencies (Redis so far), create the containers and run the default command to run the tests._
503
529
 
504
- #### Running other commands
530
+ **Running other commands**
505
531
 
506
532
  In the case you need to run a command in the gem's container, you would do it like so:
507
533
 
@@ -510,7 +536,7 @@ docker compose -f docker/docker-compose.yml run --rm tests <HERE IS YOUR COMMAND
510
536
  ```
511
537
  _Note that `tests` is the Docker Compose service name defined in the `docker/docker-compose.yml` file._
512
538
 
513
- #### Running a single test file
539
+ **Running a single test file**
514
540
 
515
541
  Given you only want to run the tests from the `test/unit/web_extension_test.rb` file, you need to pass its path with the `TEST` env variable, so here is the command:
516
542
 
@@ -3,9 +3,7 @@
3
3
  require 'fugit'
4
4
  require 'cronex'
5
5
  require 'globalid'
6
- require 'sidekiq'
7
6
  require 'sidekiq/cron/support'
8
- require 'sidekiq/options'
9
7
 
10
8
  module Sidekiq
11
9
  module Cron
@@ -16,9 +14,6 @@ module Sidekiq
16
14
  # Time format for enqueued jobs.
17
15
  LAST_ENQUEUE_TIME_FORMAT = '%Y-%m-%d %H:%M:%S %z'
18
16
 
19
- # Use the exists? method if we're on a newer version of Redis.
20
- REDIS_EXISTS_METHOD = Gem::Version.new(Sidekiq::VERSION) >= Gem::Version.new("7.0.0") || Gem.loaded_specs['redis'].version < Gem::Version.new('4.2') ? :exists : :exists?
21
-
22
17
  # Use serialize/deserialize key of GlobalID.
23
18
  GLOBALID_KEY = "_sc_globalid"
24
19
 
@@ -92,7 +87,7 @@ module Sidekiq
92
87
  end
93
88
 
94
89
  # Crucial part of whole enqueuing job.
95
- def should_enque? time
90
+ def should_enqueue? time
96
91
  return false unless status == "enabled"
97
92
  return false if past_scheduled_time?(time)
98
93
  return false if enqueued_after?(time)
@@ -105,23 +100,23 @@ module Sidekiq
105
100
 
106
101
  # Remove previous information about run times,
107
102
  # this will clear Redis and make sure that Redis will not overflow with memory.
108
- def remove_previous_enques time
103
+ def remove_previous_enqueues time
109
104
  Sidekiq.redis do |conn|
110
105
  conn.zremrangebyscore(job_enqueued_key, 0, "(#{(time.to_f - REMEMBER_THRESHOLD).to_s}")
111
106
  end
112
107
  end
113
108
 
114
109
  # Test if job should be enqueued.
115
- def test_and_enque_for_time! time
116
- if should_enque?(time)
117
- enque!
110
+ def test_and_enqueue_for_time! time
111
+ if should_enqueue?(time)
112
+ enqueue!
118
113
 
119
- remove_previous_enques(time)
114
+ remove_previous_enqueues(time)
120
115
  end
121
116
  end
122
117
 
123
118
  # Enqueue cron job to queue.
124
- def enque! time = Time.now.utc
119
+ def enqueue! time = Time.now.utc
125
120
  @last_enqueue_time = time
126
121
 
127
122
  klass_const =
@@ -413,7 +408,7 @@ module Sidekiq
413
408
 
414
409
  # Export job data to hash.
415
410
  def to_hash
416
- hash = {
411
+ {
417
412
  name: @name,
418
413
  namespace: @namespace,
419
414
  klass: @klass.to_s,
@@ -421,6 +416,7 @@ module Sidekiq
421
416
  description: @description,
422
417
  source: @source,
423
418
  args: @args.is_a?(String) ? @args : Sidekiq.dump_json(@args || []),
419
+ date_as_argument: date_as_argument? ? "1" : "0",
424
420
  message: @message.is_a?(String) ? @message : Sidekiq.dump_json(@message || {}),
425
421
  status: @status,
426
422
  active_job: @active_job ? "1" : "0",
@@ -429,12 +425,6 @@ module Sidekiq
429
425
  last_enqueue_time: serialized_last_enqueue_time,
430
426
  symbolize_args: symbolize_args? ? "1" : "0",
431
427
  }
432
-
433
- if date_as_argument?
434
- hash.merge!(date_as_argument: "1")
435
- end
436
-
437
- hash
438
428
  end
439
429
 
440
430
  def errors
@@ -447,6 +437,7 @@ module Sidekiq
447
437
 
448
438
  errors << "'name' must be set" if @name.nil? || @name.size == 0
449
439
  errors << "'namespace' must be set" if @namespace.nil? || @namespace.size == 0
440
+ errors << "'namespace' cannot be '*'" if @namespace == "*"
450
441
 
451
442
  if @cron.nil? || @cron.size == 0
452
443
  errors << "'cron' must be set"
@@ -482,14 +473,19 @@ module Sidekiq
482
473
  conn.sadd self.class.jobs_key(@namespace), [redis_key]
483
474
 
484
475
  # Add information for this job!
485
- conn.hset redis_key, to_hash.transform_values! { |v| v || '' }
476
+ conn.hset redis_key, to_hash.transform_values! { |v| v || '' }.flatten
486
477
 
487
- # Add information about last time! - don't enque right after scheduler poller starts!
478
+ # Add information about last time! - don't enqueue right after scheduler poller starts!
488
479
  time = Time.now.utc
489
- exists = conn.public_send(REDIS_EXISTS_METHOD, job_enqueued_key)
490
- conn.zadd(job_enqueued_key, time.to_f.to_s, formatted_last_time(time).to_s) unless exists == true || exists == 1
480
+ exists = conn.exists(job_enqueued_key)
481
+
482
+ unless exists == true || exists == 1
483
+ conn.zadd(job_enqueued_key, time.to_f.to_s, formatted_last_time(time).to_s)
484
+ Sidekiq.logger.info { "Cron Jobs - added job with name #{@name} in the namespace #{@namespace}" }
485
+ end
491
486
  end
492
- Sidekiq.logger.info { "Cron Jobs - added job with name #{@name} in the namespace #{@namespace}" }
487
+
488
+ true
493
489
  end
494
490
 
495
491
  def save_last_enqueue_time
@@ -505,7 +501,7 @@ module Sidekiq
505
501
  enqueued: @last_enqueue_time
506
502
  }
507
503
 
508
- @history_size ||= (Sidekiq::Options[:cron_history_size] || 10).to_i - 1
504
+ @history_size ||= Sidekiq::Cron.configuration.cron_history_size.to_i - 1
509
505
  Sidekiq.redis do |conn|
510
506
  conn.lpush jid_history_key,
511
507
  Sidekiq.dump_json(jid_history)
@@ -572,7 +568,7 @@ module Sidekiq
572
568
 
573
569
  def self.exists?(name, namespace = Sidekiq::Cron.configuration.default_namespace)
574
570
  out = Sidekiq.redis do |conn|
575
- conn.public_send(REDIS_EXISTS_METHOD, redis_key(name, namespace))
571
+ conn.exists(redis_key(name, namespace))
576
572
  end
577
573
 
578
574
  [true, 1].include?(out)
@@ -1,5 +1,3 @@
1
- require 'sidekiq/cron/poller'
2
-
3
1
  # For Cron we need to add some methods to Launcher
4
2
  # so look at the code below.
5
3
  #
@@ -8,14 +6,13 @@ require 'sidekiq/cron/poller'
8
6
  module Sidekiq
9
7
  module Cron
10
8
  module Launcher
11
- DEFAULT_POLL_INTERVAL = 30
12
9
 
13
10
  # Add cron poller to launcher.
14
11
  attr_reader :cron_poller
15
12
 
16
13
  # Add cron poller and execute normal initialize of Sidekiq launcher.
17
14
  def initialize(config, **kwargs)
18
- config[:cron_poll_interval] = DEFAULT_POLL_INTERVAL if config[:cron_poll_interval].nil?
15
+ config[:cron_poll_interval] = Sidekiq::Cron.configuration.cron_poll_interval.to_i
19
16
 
20
17
  @cron_poller = Sidekiq::Cron::Poller.new(config) if config[:cron_poll_interval] > 0
21
18
  super
@@ -1,5 +1,3 @@
1
- require 'sidekiq'
2
-
3
1
  module Sidekiq
4
2
  module Cron
5
3
  class Namespace
@@ -1,20 +1,12 @@
1
1
  # frozen_string_literal: true
2
2
 
3
- require 'sidekiq'
4
- require 'sidekiq/cron'
5
3
  require 'sidekiq/scheduled'
6
- require 'sidekiq/options'
7
4
 
8
5
  module Sidekiq
9
6
  module Cron
10
7
  # The Poller checks Redis every N seconds for scheduled cron jobs.
11
8
  class Poller < Sidekiq::Scheduled::Poller
12
9
  def initialize(config = nil)
13
- if Gem::Version.new(Sidekiq::VERSION) < Gem::Version.new('6.5.0')
14
- # Old version of Sidekiq does not accept a config argument.
15
- @config = config
16
- end
17
-
18
10
  super
19
11
  end
20
12
 
@@ -40,7 +32,7 @@ module Sidekiq
40
32
  private
41
33
 
42
34
  def enqueue_job(job, time = Time.now.utc)
43
- job.test_and_enque_for_time! time if job && job.valid?
35
+ job.test_and_enqueue_for_time! time if job && job.valid?
44
36
  rescue => ex
45
37
  # Problem somewhere in one job.
46
38
  Sidekiq.logger.error "CRON JOB: #{ex.message}"
@@ -1,9 +1,5 @@
1
- require 'sidekiq'
2
- require 'sidekiq/cron/job'
3
- require 'sidekiq/options'
4
-
5
1
  Sidekiq.configure_server do |config|
6
- schedule_file = Sidekiq::Options[:cron_schedule_file] || 'config/schedule.yml'
2
+ schedule_file = Sidekiq::Cron.configuration.cron_schedule_file
7
3
 
8
4
  if File.exist?(schedule_file)
9
5
  config.on(:startup) do
@@ -1,8 +1,7 @@
1
- # https://github.com/rails/rails/blob/352865d0f835c24daa9a2e9863dcc9dde9e5371a/activesupport/lib/active_support/inflector/methods.rb#L270
2
-
3
1
  module Sidekiq
4
2
  module Cron
5
3
  module Support
4
+ # Inspired by Active Support Inflector
6
5
  def self.constantize(camel_cased_word)
7
6
  names = camel_cased_word.split("::".freeze)
8
7
 
@@ -2,6 +2,6 @@
2
2
 
3
3
  module Sidekiq
4
4
  module Cron
5
- VERSION = "2.0.0.rc1"
5
+ VERSION = "2.0.0.rc2"
6
6
  end
7
7
  end
@@ -5,7 +5,7 @@
5
5
  <small><%= @current_namespace %></small>
6
6
  </h3>
7
7
  </div>
8
- <div class='col-sm-7 pull-right' style="margin-top: 20px; margin-bottom: 10px;">
8
+ <div class='col-sm-7 pull-right h2'>
9
9
  <% if @cron_jobs.size > 0 %>
10
10
  <form action="<%= root_path %>cron/namespaces/<%= @current_namespace %>/all/delete" method="post" class="pull-right">
11
11
  <%= csrf_tag if respond_to?(:csrf_tag) %>
@@ -31,7 +31,7 @@
31
31
  <div class='row'>
32
32
  <div class="col-sm-12 summary_bar">
33
33
  <ul class="list-unstyled summary row">
34
- <% @namespaces.sort_by { |namespace| namespace[:name] } .each do |namespace| %>
34
+ <% @namespaces.sort_by { |namespace| namespace[:name] }.each do |namespace| %>
35
35
  <li class="col-sm-1">
36
36
  <a href="<%= root_path %>cron/namespaces/<%= namespace[:name] %>">
37
37
  <span class="count"><%= namespace[:count] %></span>
@@ -47,63 +47,59 @@
47
47
  <% if @cron_jobs.size > 0 %>
48
48
  <table class="table table-hover table-bordered table-striped table-white">
49
49
  <thead>
50
+ <tr>
50
51
  <th><%= t('Status') %></th>
51
- <th><%= t('Name') %></th>
52
+ <th width="50%"><%= t('Name') %></th>
52
53
  <th><%= t('Cron string') %></th>
53
54
  <th><%= t('Last enqueued') %></th>
54
- <th width="180"><%= t('Actions')%></th>
55
+ <th width="180"><%= t('Actions') %></th>
56
+ </tr>
55
57
  </thead>
56
58
 
57
59
  <tbody>
58
- <% @cron_jobs.sort{|a,b| a.sort_name <=> b.sort_name }.each_with_index do |job, index| %>
59
- <% style = "#{job.status == 'disabled' ? "background: #ecc; color: #585454;": ""}" %>
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') %>
60
63
  <tr>
61
- <td style="<%= style %>"><%= t job.status %></td>
62
- <td style="<%= style %>">
63
- <a href="<%= root_path %>cron/namespaces/<%= @current_namespace %>/jobs/<%= CGI.escape(job.name).gsub('+', '%20') %>" title="<%= job.description %>">
64
- <b style="<%= style %>"><%= job.name %></b>
64
+ <td class="<%= klass %>"><%= t job.status %></td>
65
+ <td class="<%= klass %>">
66
+ <a href="<%= root_path %>cron/namespaces/<%= job.namespace %>/jobs/<%= escaped_job_name %>" title="<%= job.description %>">
67
+ <b class="<%= klass %>"><%= job.name %></b>
65
68
  </a>
66
- <hr style="margin:3px;border:0;">
67
- <small>
69
+ <br/>
68
70
  <% if job.message and job.message.to_s.size > 100 %>
69
- <% if Gem::Version.new(Sidekiq::VERSION) >= Gem::Version.new("6.3.0") %>
70
- <button data-toggle="job_<%= index %>" class="btn btn-warn btn-xs"><%= t('ShowAll')%></button>
71
- <div class="toggle" id="job_<%= index %>" style="display: inline;"><%= job.message[0..100] + "... " %></div>
72
- <div class="toggle" id="job_<%= index %>_full" style="display: none;"><%= job.message %></div>
73
- <% else %>
74
- <button data-toggle="collapse" data-target=".worker_<%= index %>" class="btn btn-warn btn-xs"><%= t('ShowAll')%></button>
75
- <div class="toggle worker_<%= index %>" style="display: inline;"><%= job.message[0..100] + "... " %></div>
76
- <div class="toggle worker_<%= index %>" style="display: none;"><%= job.message %></div>
77
- <% end %>
71
+ <details>
72
+ <summary class="btn btn-warn btn-xs">Show message</summary>
73
+ <p><small><%= job.message %></small></p>
74
+ </details>
78
75
  <% else %>
79
- <%= job.message %>
76
+ <small><%= job.message %></small>
80
77
  <% end %>
81
- </small>
82
78
  </td>
83
- <td style="<%= style %>"><b><%= job.human_cron %><br/><small><%= job.cron.gsub(" ", "&nbsp;") %></small></b></td>
84
- <td style="<%= style %>"><%= job.last_enqueue_time ? relative_time(job.last_enqueue_time) : "-" %></td>
85
- <td style="<%= style %>">
79
+ <td class="<%= klass %>"><b><%= job.human_cron %><br/><small><%= job.cron.gsub(" ", "&nbsp;") %></small></b></td>
80
+ <td class="<%= klass %>"><%= job.last_enqueue_time ? relative_time(job.last_enqueue_time) : "-" %></td>
81
+ <td class="<%= klass %>">
86
82
  <% if job.status == 'enabled' %>
87
- <form action="<%= root_path %>cron/namespaces/<%= @current_namespace %>/jobs/<%= CGI.escape(job.name).gsub('+', '%20') %>/enque" method="post">
83
+ <form action="<%= root_path %>cron/namespaces/<%= job.namespace %>/jobs/<%= escaped_job_name %>/enque" method="post">
88
84
  <%= csrf_tag if respond_to?(:csrf_tag) %>
89
85
  <input class='btn btn-warn btn-xs pull-left' type="submit" name="enque" value="<%= t('EnqueueNow') %>" data-confirm="<%= t('AreYouSureEnqueueCronJob', :job => job.name) %>"/>
90
86
  </form>
91
- <form action="<%= root_path %>cron/namespaces/<%= @current_namespace %>/jobs/<%= CGI.escape(job.name).gsub('+', '%20') %>/disable" method="post">
87
+ <form action="<%= root_path %>cron/namespaces/<%= job.namespace %>/jobs/<%= escaped_job_name %>/disable" method="post">
92
88
  <%= csrf_tag if respond_to?(:csrf_tag) %>
93
89
  <input class='btn btn-warn btn-xs pull-left' type="submit" name="disable" value="<%= t('Disable') %>"/>
94
90
  </form>
95
91
  <% else %>
96
- <form action="<%= root_path %>cron/namespaces/<%= @current_namespace %>/jobs/<%= CGI.escape(job.name).gsub('+', '%20') %>/enque" method="post">
92
+ <form action="<%= root_path %>cron/namespaces/<%= job.namespace %>/jobs/<%= escaped_job_name %>/enque" method="post">
97
93
  <%= csrf_tag if respond_to?(:csrf_tag) %>
98
- <input class='btn btn-warn btn-xs pull-left' type="submit" name="enque" value="<%= t('EnqueueNow') %>"/>
94
+ <input class='btn btn-warn btn-xs pull-left' type="submit" name="enque" value="<%= t('EnqueueNow') %>" data-confirm="<%= t('AreYouSureEnqueueCronJob', :job => job.name) %>"/>
99
95
  </form>
100
- <form action="<%= root_path %>cron/namespaces/<%= @current_namespace %>/jobs/<%= CGI.escape(job.name).gsub('+', '%20') %>/enable" method="post">
96
+ <form action="<%= root_path %>cron/namespaces/<%= job.namespace %>/jobs/<%= escaped_job_name %>/enable" method="post">
101
97
  <%= csrf_tag if respond_to?(:csrf_tag) %>
102
98
  <input class='btn btn-warn btn-xs pull-left' type="submit" name="enable" value="<%= t('Enable') %>"/>
103
99
  </form>
104
- <form action="<%= root_path %>cron/namespaces/<%= @current_namespace %>/jobs/<%= CGI.escape(job.name).gsub('+', '%20') %>/delete" method="post">
100
+ <form action="<%= root_path %>cron/namespaces/<%= job.namespace %>/jobs/<%= escaped_job_name %>/delete" method="post">
105
101
  <%= csrf_tag if respond_to?(:csrf_tag) %>
106
- <input class='btn btn-xs btn-danger pull-left' type="submit" name="delete" value="<%= t('Delete') %>" data-confirm="<%= t('AreYouSureDeleteCronJob', :job => job.name) %>"/>
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) %>"/>
107
103
  </form>
108
104
  <% end %>
109
105
  </td>
@@ -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;">
8
+ <div class="span col-sm-7 pull-right h2">
9
9
  <% cron_job_path = "#{root_path}cron/namespaces/#{@current_namespace}/jobs/#{CGI.escape(@job.name).gsub('+', '%20')}" %>
10
10
  <form action="<%= cron_job_path %>/enque?redirect=<%= cron_job_path %>" class="pull-right" method="post">
11
11
  <%= csrf_tag if respond_to?(:csrf_tag) %>
12
12
  <input class="btn btn-warn pull-left" name="enque" 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">
15
+ <form action="<%= cron_job_path %>/disable?redirect=<%= cron_job_path %>" class="pull-right" method="post">
16
16
  <%= csrf_tag if respond_to?(: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">
20
+ <form action="<%= cron_job_path %>/enable?redirect=<%= cron_job_path %>" class="pull-right" method="post">
21
21
  <%= csrf_tag if respond_to?(: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">
24
+ <form action="<%= cron_job_path %>/delete" class="pull-right" method="post">
25
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') %>" />
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>
@@ -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,6 +4,13 @@ module Sidekiq
4
4
  def self.registered(app)
5
5
  app.settings.locales << File.join(File.expand_path("..", __FILE__), "locales")
6
6
 
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
+ end
13
+
7
14
  # Index page of cron jobs.
8
15
  app.get '/cron' do
9
16
  view_path = File.join(File.expand_path("..", __FILE__), "views")
@@ -44,28 +51,28 @@ module Sidekiq
44
51
  if @job
45
52
  render(:erb, File.read(File.join(view_path, "cron_show.erb")))
46
53
  else
47
- redirect "#{root_path}cron/namespaces/#{route_params[:namespace]}"
54
+ redirect namespace_redirect_path
48
55
  end
49
56
  end
50
57
 
51
- # Enque all cron jobs.
58
+ # Enqueue all cron jobs.
52
59
  app.post '/cron/namespaces/:namespace/all/enque' do
53
- Sidekiq::Cron::Job.all(route_params[:namespace]).each(&:enque!)
54
- redirect params['redirect'] || "#{root_path}cron/namespaces/#{route_params[:namespace]}"
60
+ Sidekiq::Cron::Job.all(route_params[:namespace]).each(&:enqueue!)
61
+ redirect params['redirect'] || namespace_redirect_path
55
62
  end
56
63
 
57
64
  # Enqueue cron job.
58
65
  app.post '/cron/namespaces/:namespace/jobs/:name/enque' do
59
66
  if job = Sidekiq::Cron::Job.find(route_params[:name], route_params[:namespace])
60
- job.enque!
67
+ job.enqueue!
61
68
  end
62
- redirect params['redirect'] || "#{root_path}cron"
69
+ redirect params['redirect'] || namespace_redirect_path
63
70
  end
64
71
 
65
72
  # Delete all schedules.
66
73
  app.post '/cron/namespaces/:namespace/all/delete' do
67
74
  Sidekiq::Cron::Job.all(route_params[:namespace]).each(&:destroy)
68
- redirect "#{root_path}cron/namespaces/#{route_params[:namespace]}"
75
+ redirect params['redirect'] || namespace_redirect_path
69
76
  end
70
77
 
71
78
  # Delete schedule.
@@ -73,13 +80,13 @@ module Sidekiq
73
80
  if job = Sidekiq::Cron::Job.find(route_params[:name], route_params[:namespace])
74
81
  job.destroy
75
82
  end
76
- redirect "#{root_path}cron"
83
+ redirect params['redirect'] || namespace_redirect_path
77
84
  end
78
85
 
79
86
  # Enable all jobs.
80
87
  app.post '/cron/namespaces/:namespace/all/enable' do
81
88
  Sidekiq::Cron::Job.all(route_params[:namespace]).each(&:enable!)
82
- redirect params['redirect'] || "#{root_path}cron/namespaces/#{route_params[:namespace]}"
89
+ redirect params['redirect'] || namespace_redirect_path
83
90
  end
84
91
 
85
92
  # Enable job.
@@ -87,13 +94,13 @@ module Sidekiq
87
94
  if job = Sidekiq::Cron::Job.find(route_params[:name], route_params[:namespace])
88
95
  job.enable!
89
96
  end
90
- redirect params['redirect'] || "#{root_path}cron"
97
+ redirect params['redirect'] || namespace_redirect_path
91
98
  end
92
99
 
93
100
  # Disable all jobs.
94
101
  app.post '/cron/namespaces/:namespace/all/disable' do
95
102
  Sidekiq::Cron::Job.all(route_params[:namespace]).each(&:disable!)
96
- redirect params['redirect'] || "#{root_path}cron/namespaces/#{route_params[:namespace]}"
103
+ redirect params['redirect'] || namespace_redirect_path
97
104
  end
98
105
 
99
106
  # Disable job.
@@ -101,7 +108,7 @@ module Sidekiq
101
108
  if job = Sidekiq::Cron::Job.find(route_params[:name], route_params[:namespace])
102
109
  job.disable!
103
110
  end
104
- redirect params['redirect'] || "#{root_path}cron"
111
+ redirect params['redirect'] || namespace_redirect_path
105
112
  end
106
113
  end
107
114
  end
data/lib/sidekiq/cron.rb CHANGED
@@ -1,9 +1,3 @@
1
- require "sidekiq/cron/job"
2
- require "sidekiq/cron/namespace"
3
- require "sidekiq/cron/poller"
4
- require "sidekiq/cron/launcher"
5
- require "sidekiq/cron/schedule_loader"
6
-
7
1
  module Sidekiq
8
2
  module Cron
9
3
  class << self
@@ -15,6 +9,10 @@ module Sidekiq
15
9
  yield(configuration) if block_given?
16
10
  end
17
11
 
12
+ def self.reset!
13
+ self.configuration = Configuration.new
14
+ end
15
+
18
16
  class Configuration
19
17
  # The default namespace is used when no namespace is specified.
20
18
  attr_accessor :default_namespace
@@ -33,10 +31,24 @@ module Sidekiq
33
31
  # jobs that missed their schedules during the deployment. E.g., jobs that run once a day.
34
32
  attr_accessor :reschedule_grace_period
35
33
 
34
+ # The maximum number of recent cron job execution histories to retain.
35
+ # This value controls how many past job executions are stored.
36
+ attr_accessor :cron_history_size
37
+
38
+ # The interval, in seconds, at which to poll for scheduled cron jobs.
39
+ # This determines how frequently the scheduler checks for jobs to enqueue.
40
+ attr_accessor :cron_poll_interval
41
+
42
+ # The path to a YAML file containing multiple cron job schedules.
43
+ attr_accessor :cron_schedule_file
44
+
36
45
  def initialize
37
46
  @default_namespace = 'default'
38
47
  @natural_cron_parsing_mode = :single
39
48
  @reschedule_grace_period = 60
49
+ @cron_history_size = 10
50
+ @cron_poll_interval = 30
51
+ @cron_schedule_file = 'config/schedule.yml'
40
52
  end
41
53
 
42
54
  def natural_cron_parsing_mode=(mode)
@@ -1,5 +1,4 @@
1
- require 'sidekiq'
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
- :options
23
+ false
26
24
  end
27
25
  end
28
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
@@ -27,9 +27,9 @@ Gem::Specification.new do |s|
27
27
  s.required_ruby_version = ">= 2.7"
28
28
 
29
29
  s.add_dependency("cronex", ">= 0.13.0")
30
- s.add_dependency("fugit", "~> 1.8")
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")
32
+ s.add_dependency("sidekiq", ">= 6.5.0")
33
33
 
34
34
  s.add_development_dependency("minitest", "~> 5.15")
35
35
  s.add_development_dependency("mocha", "~> 2.1")
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: sidekiq-cron
3
3
  version: !ruby/object:Gem::Version
4
- version: 2.0.0.rc1
4
+ version: 2.0.0.rc2
5
5
  platform: ruby
6
6
  authors:
7
7
  - Ondrej Bartas
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2024-07-31 00:00:00.000000000 Z
11
+ date: 2024-10-19 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: cronex
@@ -31,6 +31,9 @@ dependencies:
31
31
  - - "~>"
32
32
  - !ruby/object:Gem::Version
33
33
  version: '1.8'
34
+ - - ">="
35
+ - !ruby/object:Gem::Version
36
+ version: 1.11.1
34
37
  type: :runtime
35
38
  prerelease: false
36
39
  version_requirements: !ruby/object:Gem::Requirement
@@ -38,6 +41,9 @@ dependencies:
38
41
  - - "~>"
39
42
  - !ruby/object:Gem::Version
40
43
  version: '1.8'
44
+ - - ">="
45
+ - !ruby/object:Gem::Version
46
+ version: 1.11.1
41
47
  - !ruby/object:Gem::Dependency
42
48
  name: globalid
43
49
  requirement: !ruby/object:Gem::Requirement
@@ -58,14 +64,14 @@ dependencies:
58
64
  requirements:
59
65
  - - ">="
60
66
  - !ruby/object:Gem::Version
61
- version: '6'
67
+ version: 6.5.0
62
68
  type: :runtime
63
69
  prerelease: false
64
70
  version_requirements: !ruby/object:Gem::Requirement
65
71
  requirements:
66
72
  - - ">="
67
73
  - !ruby/object:Gem::Version
68
- version: '6'
74
+ version: 6.5.0
69
75
  - !ruby/object:Gem::Dependency
70
76
  name: minitest
71
77
  requirement: !ruby/object:Gem::Requirement
@@ -216,11 +222,11 @@ required_ruby_version: !ruby/object:Gem::Requirement
216
222
  version: '2.7'
217
223
  required_rubygems_version: !ruby/object:Gem::Requirement
218
224
  requirements:
219
- - - ">"
225
+ - - ">="
220
226
  - !ruby/object:Gem::Version
221
- version: 1.3.1
227
+ version: '0'
222
228
  requirements: []
223
- rubygems_version: 3.4.10
229
+ rubygems_version: 3.5.16
224
230
  signing_key:
225
231
  specification_version: 4
226
232
  summary: Scheduler/Cron for Sidekiq jobs