sidekiq-cron 1.9.1 → 2.4.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (42) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGELOG.md +98 -3
  3. data/Gemfile +6 -0
  4. data/README.md +320 -44
  5. data/lib/sidekiq/cron/job.rb +336 -176
  6. data/lib/sidekiq/cron/launcher.rb +4 -6
  7. data/lib/sidekiq/cron/locales/de.yml +15 -6
  8. data/lib/sidekiq/cron/locales/en.yml +14 -14
  9. data/lib/sidekiq/cron/locales/es.yml +22 -0
  10. data/lib/sidekiq/cron/locales/id.yml +22 -0
  11. data/lib/sidekiq/cron/locales/it.yml +15 -16
  12. data/lib/sidekiq/cron/locales/ja.yml +14 -10
  13. data/lib/sidekiq/cron/locales/pt.yml +14 -14
  14. data/lib/sidekiq/cron/locales/ru.yml +15 -7
  15. data/lib/sidekiq/cron/locales/zh-CN.yml +14 -11
  16. data/lib/sidekiq/cron/namespace.rb +43 -0
  17. data/lib/sidekiq/cron/poller.rb +16 -13
  18. data/lib/sidekiq/cron/schedule_loader.rb +56 -16
  19. data/lib/sidekiq/cron/support.rb +4 -30
  20. data/lib/sidekiq/cron/version.rb +1 -1
  21. data/lib/sidekiq/cron/views/cron.erb +98 -92
  22. data/lib/sidekiq/cron/views/cron_show.erb +87 -82
  23. data/lib/sidekiq/cron/views/legacy/cron.erb +114 -0
  24. data/lib/sidekiq/cron/views/legacy/cron_show.erb +92 -0
  25. data/lib/sidekiq/cron/web.rb +21 -2
  26. data/lib/sidekiq/cron/web_extension.rb +99 -31
  27. data/lib/sidekiq/cron.rb +95 -5
  28. data/lib/sidekiq/options.rb +9 -7
  29. data/lib/sidekiq-cron.rb +6 -0
  30. data/sidekiq-cron.gemspec +10 -7
  31. metadata +65 -23
  32. data/test/integration/performance_test.rb +0 -46
  33. data/test/test_helper.rb +0 -87
  34. data/test/unit/fixtures/schedule_array.yml +0 -13
  35. data/test/unit/fixtures/schedule_erb.yml +0 -6
  36. data/test/unit/fixtures/schedule_hash.yml +0 -12
  37. data/test/unit/fixtures/schedule_string.yml +0 -1
  38. data/test/unit/job_test.rb +0 -1258
  39. data/test/unit/launcher_test.rb +0 -33
  40. data/test/unit/poller_test.rb +0 -144
  41. data/test/unit/schedule_loader_test.rb +0 -58
  42. data/test/unit/web_extension_test.rb +0 -155
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 4d751ce0280b4d30f1f43a1e0ed973166c2f398d7ac976e6fea267e66e999bb8
4
- data.tar.gz: 352b64238d89eb4eedb0e9c046f9d54f6f298c376804de1066cbdad3481c43af
3
+ metadata.gz: 24a9263df38117d217eaff38d09f5cc69029d2998a3cc07fd5f21878b340305c
4
+ data.tar.gz: 9cf118cc907fd84abdc0c0123fb23d6745b9fee021557560e35c55f9ff99fd35
5
5
  SHA512:
6
- metadata.gz: ee7843b8dd62b31954de3db17c4cef76229050d2c4590bde276c77d6ad2c96bbb523620631ad41574d4b976ace4da6425130b1aa5c4a20986c4d42fdcdde1ef4
7
- data.tar.gz: 95e74c836bdae7eb10fe1fe540fdc91ecb730c3a73bc1dd7e578d9324cf448e32054e9ad1b487036119076e966b0df1011978aa34b9215a334d996759d4bb684
6
+ metadata.gz: 238cd9ccbf1f621090eca667e9e1b4c198589897869c7e8d89746886297bac0456dcd0452aa91f0e5e07af5e4e686d93f140089a44cd676cdf1711c45ced4e40
7
+ data.tar.gz: 404d91026a551fefd3e2a4c37bae8220e522b9a38a377cbbdc2f692331926495835feb2a4decf8dfe4a059e84ff6c45fc99e6c96c0f6156d53130586bf70b1bb
data/CHANGELOG.md CHANGED
@@ -2,6 +2,101 @@
2
2
 
3
3
  All notable changes to this project will be documented in this file.
4
4
 
5
+ ## 2.4.0
6
+
7
+ - Fix reflected XSS on Sidekiq-UI (https://github.com/sidekiq-cron/sidekiq-cron/pull/568)
8
+ - Add `cron_process_count_override` config option (https://github.com/sidekiq-cron/sidekiq-cron/pull/572)
9
+ - Fix Spanish translation for enabled/disabled states (https://github.com/sidekiq-cron/sidekiq-cron/pull/575)
10
+ - Allow to conditionally disable Sidekiq-Cron (https://github.com/sidekiq-cron/sidekiq-cron/pull/574)
11
+
12
+ ## 2.3.1
13
+
14
+ - Fix manually launch enqueue job not working from web UI (https://github.com/sidekiq-cron/sidekiq-cron/pull/564)
15
+
16
+ ## 2.3.0
17
+
18
+ - **WARNING** The default value for `available_namespaces` has changed from `nil` to `[default_namespace]`. Please refer to the [migration guide](https://github.com/sidekiq-cron/sidekiq-cron/blob/master/README.md#migrating-to-23) for further details (https://github.com/sidekiq-cron/sidekiq-cron/pull/552)
19
+ - Fix deprecation warning for using raw params in WEB extension (https://github.com/sidekiq-cron/sidekiq-cron/pull/547)
20
+ - Allow for sidekiq embedded configuration (https://github.com/sidekiq-cron/sidekiq-cron/pull/549)
21
+ - Load schedule file within sidekiq callback (https://github.com/sidekiq-cron/sidekiq-cron/pull/550)
22
+ - Fix missing default namespace if namespaces are explicitly provided (https://github.com/sidekiq-cron/sidekiq-cron/pull/551)
23
+
24
+ ## 2.2.0
25
+
26
+ - Add support for Sidekiq v8 (https://github.com/sidekiq-cron/sidekiq-cron/pull/531, https://github.com/sidekiq-cron/sidekiq-cron/pull/538)
27
+ - Always show parsed cron expression in web UI (https://github.com/sidekiq-cron/sidekiq-cron/pull/535)
28
+ - Add fallback to .yaml extension (https://github.com/sidekiq-cron/sidekiq-cron/pull/534)
29
+ - Refactor constantize helper to use Object.const_get (https://github.com/sidekiq-cron/sidekiq-cron/pull/541)
30
+ - Allow testing of schedule by library consumers (https://github.com/sidekiq-cron/sidekiq-cron/pull/543)
31
+
32
+ ## 2.1.0
33
+
34
+ - Add `available_namespaces` configuration option (https://github.com/sidekiq-cron/sidekiq-cron/pull/524)
35
+ - I18n fixes and enhancements (https://github.com/sidekiq-cron/sidekiq-cron/pull/520, https://github.com/sidekiq-cron/sidekiq-cron/pull/522)
36
+
37
+ ## 2.0.1
38
+
39
+ - Fix usage of ActiveJob::Base.queue_name (https://github.com/sidekiq-cron/sidekiq-cron/pull/517)
40
+ - Fix: Add quotes to Japanese translations containing multi-byte symbols (https://github.com/sidekiq-cron/sidekiq-cron/pull/515)
41
+
42
+ ## 2.0.0
43
+
44
+ Sidekiq-Cron v2 is here! In this release we refactored some internals, plus:
45
+
46
+ - Review web UI translations for all available locales (https://github.com/sidekiq-cron/sidekiq-cron/pull/506)
47
+ - Fix detection of ActiveJob in Sidekiq v7.3.3+ (https://github.com/sidekiq-cron/sidekiq-cron/pull/510)
48
+ - Add retry job configuration option to set Sidekiq retry job option (https://github.com/sidekiq-cron/sidekiq-cron/pull/509)
49
+
50
+ Please take a look to the RC1 and RC2 changes too if you are coming from the v1.X series.
51
+
52
+ ## 2.0.0.rc2
53
+
54
+ - Remove support for Sidekiq < 6.5 (https://github.com/sidekiq-cron/sidekiq-cron/pull/480)
55
+ - Require at least Fugit >= 1.11.1 (https://github.com/sidekiq-cron/sidekiq-cron/pull/475)
56
+ - Update how Redis values are stored on save (https://github.com/sidekiq-cron/sidekiq-cron/pull/479)
57
+ - Web extension: Add compatibility with Sidekiq 7.3+ and remove inline styles (https://github.com/sidekiq-cron/sidekiq-cron/pull/480)
58
+ - Remove support for old Redis (< 4.2) (https://github.com/sidekiq-cron/sidekiq-cron/pull/490)
59
+ - 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)
60
+ - Rename `enque!` to `enqueue!` (https://github.com/sidekiq-cron/sidekiq-cron/pull/494)
61
+ - Refactor gem configuration module (https://github.com/sidekiq-cron/sidekiq-cron/pull/495)
62
+
63
+ ## 2.0.0.rc1
64
+
65
+ - Introduce `Namespacing` (https://github.com/sidekiq-cron/sidekiq-cron/pull/268)
66
+ - Human readable cron format in UI (https://github.com/sidekiq-cron/sidekiq-cron/pull/445)
67
+ - Add Bahasa Indonesia locale (https://github.com/sidekiq-cron/sidekiq-cron/pull/446)
68
+ - Fetch queue name from ActiveJob class (https://github.com/sidekiq-cron/sidekiq-cron/pull/448)
69
+ - Allows symbol keys in `.load_from_array!` (https://github.com/sidekiq-cron/sidekiq-cron/pull/458)
70
+ - Add natural language parsing mode (https://github.com/sidekiq-cron/sidekiq-cron/pull/459)
71
+ - Add ability to configure the past scheduled time threshold (https://github.com/sidekiq-cron/sidekiq-cron/pull/465)
72
+ - Docs: clarify worker vs process terminology (https://github.com/sidekiq-cron/sidekiq-cron/issues/453)
73
+
74
+ ## 1.12.0
75
+
76
+ - Remove Sidekiq.server? check from schedule loader (https://github.com/sidekiq-cron/sidekiq-cron/pull/436)
77
+ - Parse arguments on `args=` method (https://github.com/sidekiq-cron/sidekiq-cron/pull/442)
78
+ - Only check out a Redis connection if necessary (https://github.com/sidekiq-cron/sidekiq-cron/pull/438)
79
+
80
+ ## 1.11.0
81
+
82
+ - Differentiates b/w "schedule" vs "dynamic" jobs (https://github.com/sidekiq-cron/sidekiq-cron/pull/431)
83
+ - Clears scheduled jobs upon schedule load (https://github.com/sidekiq-cron/sidekiq-cron/pull/431)
84
+ - Reduce gem size by excluding test files (https://github.com/sidekiq-cron/sidekiq-cron/pull/414)
85
+
86
+ ## 1.10.1
87
+
88
+ - Use `hset` instead of deprecated `hmset` (https://github.com/sidekiq-cron/sidekiq-cron/pull/410)
89
+
90
+ ## 1.10.0
91
+
92
+ - Remove EOL Ruby 2.6 support (https://github.com/sidekiq-cron/sidekiq-cron/pull/399)
93
+ - Add a logo for the project! (https://github.com/sidekiq-cron/sidekiq-cron/pull/402)
94
+ - Added support for ActiveRecord serialize/deserialize using GlobalID (https://github.com/sidekiq-cron/sidekiq-cron/pull/395)
95
+ - Allow for keyword args (`embedded: true`) in Poller (https://github.com/sidekiq-cron/sidekiq-cron/pull/398)
96
+ - Make last_enqueue_time be always an instance of Time (https://github.com/sidekiq-cron/sidekiq-cron/pull/354)
97
+ - Fix argument error problem update from 1.6.0 to newer (https://github.com/sidekiq-cron/sidekiq-cron/pull/392)
98
+ - Clear old jobs while loading the jobs from schedule via the schedule loader (https://github.com/sidekiq-cron/sidekiq-cron/pull/405)
99
+
5
100
  ## 1.9.1
6
101
 
7
102
  - Always enqueue via Active Job interface when defined in cron job config (https://github.com/sidekiq-cron/sidekiq-cron/pull/381)
@@ -35,7 +130,7 @@ All notable changes to this project will be documented in this file.
35
130
 
36
131
  ## 1.5.1
37
132
 
38
- - Fixes an issue that prevented the gem to work in previous Sidekiq versions (https://github.com/sidekiq-cron/sidekiq-cron/pull/335)
133
+ - Fixes an issue that prevented the gem to work in previous Sidekiq versions (https://github.com/sidekiq-cron/sidekiq-cron/pull/335)
39
134
 
40
135
  ## 1.5.0
41
136
 
@@ -45,7 +140,7 @@ All notable changes to this project will be documented in this file.
45
140
  ## 1.4.0
46
141
 
47
142
  - Fix buttons order in job show view (https://github.com/sidekiq-cron/sidekiq-cron/pull/302)
48
- - Dark Mode support in UI (https://github.com/sidekiq-cron/sidekiq-cron/pull/317/282)
143
+ - Dark Mode support in UI (https://github.com/sidekiq-cron/sidekiq-cron/pull/282)
49
144
  - Remove invocation of deprecated Redis functionality (https://github.com/sidekiq-cron/sidekiq-cron/pull/318)
50
145
  - Internal code cleanup (https://github.com/sidekiq-cron/sidekiq-cron/pull/317)
51
146
  - Optimize gem size (https://github.com/sidekiq-cron/sidekiq-cron/pull/322)
@@ -130,6 +225,6 @@ All notable changes to this project will be documented in this file.
130
225
 
131
226
  ## 0.3.0
132
227
 
133
- - Suport for Active Job
228
+ - Support for Active Job
134
229
  - Sidekiq cron web ui needs to be loaded by: require 'sidekiq/cron/web'
135
230
  - Add load_from_hash! and load_from_array! which cleanup jobs before adding new ones
data/Gemfile CHANGED
@@ -1,3 +1,9 @@
1
1
  source 'https://rubygems.org'
2
2
 
3
3
  gemspec
4
+
5
+ # To test different Sidekiq versions
6
+ gem "sidekiq", ENV.fetch("SIDEKIQ_VERSION", ">= 6")
7
+
8
+ # To test different Rails versions
9
+ gem "rails", ENV.fetch("RAILS_VERSION", "~> 7")
data/README.md CHANGED
@@ -1,37 +1,27 @@
1
- # Sidekiq-Cron
1
+ ![Sidekiq-Cron](logos/cover.png)
2
2
 
3
3
  [![Gem Version](https://badge.fury.io/rb/sidekiq-cron.svg)](https://badge.fury.io/rb/sidekiq-cron)
4
- [![Build Status](https://github.com/sidekiq-cron/sidekiq-cron/workflows/CI/badge.svg?branch=master)](https://github.com/sidekiq-cron/sidekiq-cron/actions)
5
- [![Coverage Status](https://coveralls.io/repos/github/ondrejbartas/sidekiq-cron/badge.svg?branch=master)](https://coveralls.io/github/ondrejbartas/sidekiq-cron?branch=master)
4
+ [![CI](https://github.com/sidekiq-cron/sidekiq-cron/actions/workflows/ci.yml/badge.svg)](https://github.com/sidekiq-cron/sidekiq-cron/actions/workflows/ci.yml)
5
+ [![codecov](https://codecov.io/gh/sidekiq-cron/sidekiq-cron/branch/master/graph/badge.svg?token=VK9IVLIaY8)](https://codecov.io/gh/sidekiq-cron/sidekiq-cron)
6
6
 
7
7
  > A scheduling add-on for [Sidekiq](https://sidekiq.org/)
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
- Checks for new jobs to schedule every 30 seconds and doesn't schedule the same job multiple times when more than one Sidekiq worker is running.
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
 
15
15
  Scheduling jobs are added only when at least one Sidekiq process is running, but it is safe to use Sidekiq-Cron in environments where multiple Sidekiq processes or nodes are running.
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).
26
22
 
27
23
  ## Installation
28
24
 
29
- ### Requirements
30
-
31
- - Redis 2.8 or greater is required (Redis 3.0.3 or greater is recommended for large scale use)
32
- - Sidekiq 4.2 or greater is required (for Sidekiq < 4 use version sidekiq-cron 0.3.1)
33
- - Sidekiq 6.5 requires Sidekiq-Cron 1.5+
34
-
35
25
  Install the gem:
36
26
 
37
27
  ```
@@ -48,7 +38,7 @@ gem "sidekiq-cron"
48
38
 
49
39
  ## Getting Started
50
40
 
51
- ### Job properties
41
+ ### Job properties
52
42
 
53
43
  ```ruby
54
44
  {
@@ -57,17 +47,41 @@ gem "sidekiq-cron"
57
47
  'cron' => '1 * * * *', # execute at 1 minute of every hour, ex: 12:01, 13:01, 14:01, ...
58
48
  'class' => 'MyClass',
59
49
  # OPTIONAL
50
+ 'namespace' => 'YourNamespace', # groups jobs together in a namespace (Default value is 'default'),
51
+ 'source' => 'dynamic', # source of the job, `schedule`/`dynamic` (default: `dynamic`)
60
52
  'queue' => 'name of queue',
53
+ 'retry' => '5', # Sidekiq (not supported by ActiveJob) number of retries, or false to discard on first failure
61
54
  'args' => '[Array or Hash] of arguments which will be passed to perform method',
62
55
  'date_as_argument' => true, # add the time of execution as last argument of the perform method
63
- 'active_job' => true, # enqueue job through Rails 4.2+ Active Job interface
64
- 'queue_name_prefix' => 'prefix', # Rails 4.2+ Active Job queue with prefix
65
- 'queue_name_delimiter' => '.', # Rails 4.2+ Active Job queue with custom delimiter
66
- 'description' => 'A sentence describing what work this job performs'
56
+ 'active_job' => true, # enqueue job through Active Job interface
57
+ 'queue_name_prefix' => 'prefix', # Active Job queue with prefix
58
+ 'queue_name_delimiter' => '.', # Active Job queue with custom delimiter (default: '_')
59
+ 'description' => 'A sentence describing what work this job performs',
67
60
  'status' => 'disabled' # default: enabled
68
61
  }
69
62
  ```
70
63
 
64
+ **NOTE** The `status` of a job does not get changed in Redis when a job gets reloaded unless the `status` property is explicitly set.
65
+
66
+ ### Configuration
67
+
68
+ All configuration options:
69
+
70
+ ```ruby
71
+ Sidekiq::Cron.configure do |config|
72
+ config.enabled = false # Default is true
73
+ config.cron_poll_interval = 10 # Default is 30
74
+ config.cron_schedule_file = 'config/my_schedule.yml' # Default is 'config/schedule.yml'
75
+ config.cron_history_size = 20 # Default is 10
76
+ config.default_namespace = 'statistics' # Default is 'default'
77
+ config.available_namespaces = %w[statistics maintenance billing] # Default is `[config.default_namespace]`
78
+ config.natural_cron_parsing_mode = :strict # Default is :single
79
+ config.reschedule_grace_period = 300 # Default is 60
80
+ end
81
+ ```
82
+
83
+ If you are using Rails, you should add the above block inside an initializer (`config/initializers/sidekiq-cron.rb`).
84
+
71
85
  ### Time, cron and Sidekiq-Cron
72
86
 
73
87
  For testing your cron notation you can use [crontab.guru](https://crontab.guru).
@@ -81,18 +95,50 @@ like this `'0 22 * * 1-5 America/Chicago'`.
81
95
 
82
96
  #### Natural-language formats
83
97
 
84
- Since sidekiq-cron `v1.7.0`, you can use the natural-language formats supported by Fugit, such as:
98
+ Since Sidekiq-Cron `v1.7.0`, you can use the natural-language formats supported by Fugit, such as:
85
99
 
86
- ```rb
100
+ ```ruby
87
101
  "every day at five" # => '0 5 * * *'
88
102
  "every 3 hours" # => '0 */3 * * *'
89
103
  ```
90
104
 
91
105
  See [the relevant part of Fugit documentation](https://github.com/floraison/fugit#fugitnat) for details.
92
106
 
107
+ There are multiple modes that determine how natural-language cron strings will be parsed.
108
+
109
+ 1. `:single` (default)
110
+
111
+ ```ruby
112
+ Sidekiq::Cron.configure do |config|
113
+ # Note: This doesn't need to be specified since it's the default.
114
+ config.natural_cron_parsing_mode = :single
115
+ end
116
+ ```
117
+
118
+ This parses the first possible cron line from the given string and then ignores any additional cron lines.
119
+
120
+ Ex. `every day at 3:15 and 4:30`
121
+
122
+ - Equivalent to `15 3 * * *`.
123
+ - `30 4 * * *` gets ignored.
124
+
125
+ 2. `:strict`
126
+
127
+ ```ruby
128
+ Sidekiq::Cron.configure do |config|
129
+ config.natural_cron_parsing_mode = :strict
130
+ end
131
+ ```
132
+
133
+ This throws an error if the given string would be parsed into multiple cron lines.
134
+
135
+ Ex. `every day at 3:15 and 4:30`
136
+
137
+ - Would throw an error and the associated cron job would be invalid
138
+
93
139
  #### Second-precision (sub-minute) cronlines
94
140
 
95
- In addition to the standard 5-parameter cronline format, sidekiq-cron supports scheduling jobs with second-precision using a modified 6-parameter cronline format:
141
+ In addition to the standard 5-parameter cronline format, Sidekiq-Cron supports scheduling jobs with second-precision using a modified 6-parameter cronline format:
96
142
 
97
143
  `Seconds Minutes Hours Days Months DayOfWeek`
98
144
 
@@ -101,11 +147,93 @@ For example: `"*/30 * * * * *"` would schedule a job to run every 30 seconds.
101
147
  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:
102
148
 
103
149
  ```ruby
104
- Sidekiq::Options[:cron_poll_interval] = 10
150
+ Sidekiq::Cron.configure do |config|
151
+ config.cron_poll_interval = 10
152
+ end
105
153
  ```
106
154
 
107
155
  The default value at time of writing is 30 seconds. See [under the hood](#under-the-hood) for more details.
108
156
 
157
+ ### Namespacing
158
+
159
+ #### Default namespace
160
+
161
+ When not giving a namespace, the `default` one will be used.
162
+
163
+ In the case you'd like to change this value, you can change it via the following configuration flag:
164
+
165
+ ```ruby
166
+ Sidekiq::Cron.configure do |config|
167
+ config.default_namespace = 'statistics'
168
+ end
169
+ ```
170
+
171
+ #### Renaming namespace
172
+
173
+ If you rename the namespace of a job that is already running, the gem will not automatically delete the cron job associated with the old namespace. This means you could end up with two cron jobs running simultaneously.
174
+
175
+ To avoid this, it is recommended to delete all existing cron jobs associated with the old namespace before making the change. You can achieve this with the following code:
176
+
177
+ ```ruby
178
+ Sidekiq::Cron::Job.all('YOUR_OLD_NAMESPACE_NAME').each { |job| job.destroy }
179
+ ```
180
+
181
+ #### Available namespaces
182
+
183
+ By default, Sidekiq Cron uses the available_namespaces configuration option to determine which namespaces your application utilizes. The default namespace (`"default"`, by default) is always included in the list of available namespaces.
184
+
185
+ If you want Sidekiq Cron to automatically detect existing namespaces from the Redis database, you can set `available_namespaces` to the special option `:auto`.
186
+
187
+ If available_namespaces is explicitly set and a job is created with an unexpected namespace, a warning will be printed, and the job will be assigned to the default namespace.
188
+
189
+ #### Migrating to 2.3
190
+
191
+ As discussed in [this issue](https://github.com/sidekiq-cron/sidekiq-cron/issues/516), the approach introduced in Sidekiq Cron 2.0 for determining available namespaces using the `KEYS` command is not acceptable. Therefore, starting from version 2.3, namespacing has been reworked:
192
+
193
+ - If you were not using the namespacing feature, no action is required. You can even remove `available_namespaces = %w[default]`, as it is now the default.
194
+
195
+ - If you were using the namespacing feature and explicitly specified available namespaces as a list, no changes are needed.
196
+
197
+ - If you were using the namespacing feature and relied on automatic namespace inference, you should either specify all used namespaces explicitly or set `available_namespaces` to `:auto` to maintain automatic detection. However, note that this approach does not scale well (see the referenced issue for details).
198
+
199
+ #### Usage
200
+
201
+ When creating a new job, you can optionally give a `namespace` attribute, and then you can pass it too in the `find` or `destroy` methods.
202
+
203
+ ```ruby
204
+ Sidekiq::Cron::Job.create(
205
+ name: 'Hard worker - every 5min',
206
+ namespace: 'Foo',
207
+ cron: '*/5 * * * *',
208
+ class: 'HardWorker'
209
+ )
210
+ # INFO: Cron Jobs - add job with name Hard worker - every 5min in the namespace Foo
211
+
212
+ # Without specifying the namespace, Sidekiq::Cron use the `default` one, therefore `count` return 0.
213
+ Sidekiq::Cron::Job.count
214
+ #=> 0
215
+
216
+ # Searching in the job's namespace returns 1.
217
+ Sidekiq::Cron::Job.count 'Foo'
218
+ #=> 1
219
+
220
+ # Same applies to `all`. Without a namespace, no jobs found.
221
+ Sidekiq::Cron::Job.all
222
+
223
+ # But giving the job's namespace returns it.
224
+ Sidekiq::Cron::Job.all 'Foo'
225
+ #=> [#<Sidekiq::Cron::Job:0x00007f7848a326a0 ... @name="Hard worker - every 5min", @namespace="Foo", @cron="*/5 * * * *", @klass="HardWorker", @status="enabled" ... >]
226
+
227
+ # If you'd like to get all the jobs across all the namespaces then pass an asterisk:
228
+ Sidekiq::Cron::Job.all '*'
229
+ #=> [#<Sidekiq::Cron::Job ...>]
230
+
231
+ job = Sidekiq::Cron::Job.find('Hard worker - every 5min', 'Foo').first
232
+ job.destroy
233
+ # INFO: Cron Jobs - deleted job with name Hard worker - every 5min from namespace Foo
234
+ #=> true
235
+ ```
236
+
109
237
  ### What objects/classes can be scheduled
110
238
 
111
239
  #### Sidekiq Worker
@@ -122,7 +250,9 @@ class HardWorker
122
250
  end
123
251
  ```
124
252
 
125
- #### Active Job Worker
253
+ For Sidekiq workers, `symbolize_args: true` in `Sidekiq::Cron::Job.create` or in Hash configuration is gonna be ignored as Sidekiq currently only allows for [simple JSON datatypes](https://github.com/sidekiq/sidekiq/wiki/The-Basics#:~:text=These%20two%20methods,not%20serialize%20properly.).
254
+
255
+ #### Active Job
126
256
 
127
257
  You can schedule `ExampleJob` which looks like:
128
258
 
@@ -136,10 +266,12 @@ class ExampleJob < ActiveJob::Base
136
266
  end
137
267
  ```
138
268
 
139
- For Active jobs you can use `symbolize_args: true` in `Sidekiq::Cron::Job.create` or in Hash configuration,
269
+ For Active Job you can use `symbolize_args: true` in `Sidekiq::Cron::Job.create` or in Hash configuration,
140
270
  which will ensure that arguments you are passing to it will be symbolized when passed back to `perform` method in worker.
141
271
 
142
- #### Adding Cron job
272
+ ### Adding Cron jobs
273
+
274
+ Refer to [Schedule vs Dynamic jobs](#schedule-vs-dynamic-jobs) to understand the difference.
143
275
 
144
276
  ```ruby
145
277
  class HardWorker
@@ -171,6 +303,25 @@ unless job.save
171
303
  end
172
304
  ```
173
305
 
306
+ Use ActiveRecord models as arguments:
307
+
308
+ ```ruby
309
+ class Person < ApplicationRecord
310
+ end
311
+
312
+ class HardWorker < ActiveJob::Base
313
+ queue_as :default
314
+
315
+ def perform(person)
316
+ puts "person: #{person}"
317
+ end
318
+ end
319
+
320
+ person = Person.create(id: 1)
321
+ Sidekiq::Cron::Job.create(name: 'Hard worker - every 5min', cron: '*/5 * * * *', class: 'HardWorker', args: person)
322
+ # => true
323
+ ```
324
+
174
325
  Load more jobs from hash:
175
326
 
176
327
  ```ruby
@@ -209,14 +360,16 @@ array = [
209
360
  Sidekiq::Cron::Job.load_from_array array
210
361
  ```
211
362
 
212
- Bang-suffixed methods will remove jobs that are not present in the given hash/array, update jobs that have the same names, and create new ones when the names are previously unknown.
363
+ Bang-suffixed methods will remove jobs where source is `schedule` and are not present in the given hash/array, update jobs that have the same names, and create new ones when the names are previously unknown.
213
364
 
214
365
  ```ruby
215
366
  Sidekiq::Cron::Job.load_from_hash! hash
216
367
  Sidekiq::Cron::Job.load_from_array! array
217
368
  ```
218
369
 
219
- Or from YAML (same notation as Resque-scheduler):
370
+ ### Loading jobs from schedule file
371
+
372
+ You can also load multiple jobs from a YAML file:
220
373
 
221
374
  ```yaml
222
375
  # config/schedule.yml
@@ -237,22 +390,31 @@ second_job:
237
390
  There are multiple ways to load the jobs from a YAML file
238
391
 
239
392
  1. The gem will automatically load the jobs mentioned in `config/schedule.yml` file (it supports ERB)
240
- 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"`
393
+ 2. When you want to load jobs from a different filename, mention the filename in Sidekiq configuration as follows:
394
+
395
+ ```ruby
396
+ Sidekiq::Cron.configure do |config|
397
+ config.cron_schedule_file = "config/users_schedule.yml"
398
+ end
399
+ ```
400
+
241
401
  3. Load the file manually as follows:
242
402
 
243
- ```ruby
244
- # config/initializers/sidekiq.rb
403
+ ```ruby
404
+ # config/initializers/sidekiq.rb
405
+
406
+ Sidekiq.configure_server do |config|
407
+ config.on(:startup) do
408
+ schedule_file = "config/users_schedule.yml"
245
409
 
246
- Sidekiq.configure_server do |config|
247
- config.on(:startup) do
248
- schedule_file = "config/users_schedule.yml"
410
+ if File.exist?(schedule_file)
411
+ schedule = YAML.load_file(schedule_file)
249
412
 
250
- if File.exist?(schedule_file)
251
- Sidekiq::Cron::Job.load_from_hash YAML.load_file(schedule_file)
413
+ Sidekiq::Cron::Job.load_from_hash!(schedule, source: "schedule")
414
+ end
415
+ end
252
416
  end
253
- end
254
- end
255
- ```
417
+ ```
256
418
 
257
419
  ### Finding jobs
258
420
 
@@ -298,9 +460,19 @@ job.status
298
460
  # => enabled/disabled
299
461
 
300
462
  # enqueue job right now!
301
- job.enque!
463
+ job.enqueue!
302
464
  ```
303
465
 
466
+ ### Schedule vs Dynamic jobs
467
+
468
+ There are two potential job sources: `schedule` and `dynamic`.
469
+ Jobs associated with schedule files are labeled as `schedule` as their source,
470
+ whereas jobs created at runtime without the `source=schedule` argument are classified as `dynamic`.
471
+
472
+ The key distinction lies in how these jobs are managed.
473
+ When a schedule is loaded, any stale `schedule` jobs are automatically removed to ensure synchronization within the schedule.
474
+ The `dynamic` jobs remain unaffected by this process.
475
+
304
476
  ### How to start scheduling?
305
477
 
306
478
  Just start Sidekiq workers by running:
@@ -316,7 +488,7 @@ add `require 'sidekiq/cron/web'` after `require 'sidekiq/web'`.
316
488
 
317
489
  With this, you will get:
318
490
 
319
- ![Web UI](examples/web-cron-ui.jpeg)
491
+ ![Web UI](docs/images/web-cron-ui.jpeg)
320
492
 
321
493
  ## Under the hood
322
494
 
@@ -327,12 +499,83 @@ Sidekiq-Cron adds itself into this start procedure and starts another thread wit
327
499
  Sidekiq-Cron is checking jobs to be enqueued every 30s by default, you can change it by setting:
328
500
 
329
501
  ```ruby
330
- Sidekiq::Options[:cron_poll_interval] = 10
502
+ Sidekiq::Cron.configure do |config|
503
+ config.cron_poll_interval = 10
504
+ end
505
+ ```
506
+
507
+ 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:
508
+
509
+ ```ruby
510
+ Sidekiq::Cron.configure do |config|
511
+ config.reschedule_grace_period = 600 # 10 minutes in seconds
512
+ end
331
513
  ```
332
514
 
333
515
  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.
334
516
 
335
- 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.
517
+ When running with many Sidekiq processes, the polling can add significant load to Redis. You can disable polling on some processes by setting:
518
+
519
+ ```ruby
520
+ Sidekiq::Cron.configure do |config|
521
+ config.cron_poll_interval = 0
522
+ end
523
+ ```
524
+
525
+ You can also disable the entire engine by setting `enabled` to `false`. When disabled, Sidekiq-Cron will skip loading the schedule file on startup, which is useful for environments or specific Sidekiq processes where you don't need cron job scheduling at all:
526
+
527
+ ```ruby
528
+ Sidekiq::Cron.configure do |config|
529
+ config.enabled = false
530
+ end
531
+ ```
532
+
533
+ Sidekiq will internally determine the process count by checking Redis but if polling has been disabled from some Sidekiq processes by setting the cron poll interval to zero, as explained above, that count might be incorrect. In that case, it is possible to override the default process count for Sidekiq Cron. This affects the way the random poll interval is calculated internally.
534
+
535
+ ```ruby
536
+ Sidekiq::Cron.configure do |config|
537
+ config.cron_poll_process_count = 2
538
+ end
539
+ ```
540
+
541
+ ## Testing your configuration
542
+
543
+ You can test your application's configuration by loading the schedule in your test suite. Below is an example using RSpec in a Rails project:
544
+
545
+ ```ruby
546
+ # spec/cron_schedule_spec.rb
547
+ require "rails_helper"
548
+
549
+ RSpec.describe "Cron Schedule" do
550
+ let(:schedule_loader) { Sidekiq::Cron::ScheduleLoader.new }
551
+ let(:all_jobs) { Sidekiq::Cron::Job.all }
552
+
553
+ # Confirms that `config.cron_schedule_file` points to a real file.
554
+ it "has a schedule file" do
555
+ expect(schedule_loader).to have_schedule_file
556
+ end
557
+
558
+ # Confirms that no jobs in the schedule have an invalid cron string.
559
+ it "does not return any errors" do
560
+ expect(schedule_loader.load_schedule).to be_empty
561
+ end
562
+
563
+ # May be subject to churn, but adds confidence.
564
+ it "adds the expected number of jobs" do
565
+ schedule_loader.load_schedule
566
+ expect(all_jobs.size).to eq 5
567
+ end
568
+
569
+ # Confirms that all job classes exist.
570
+ it "has a valid class for each added job" do
571
+ schedule_loader.load_schedule
572
+ # Shows that all classes exist (as we can constantize the names without raising).
573
+ job_classes = all_jobs.map { |job| job.klass.constantize }
574
+ # Naive check that classes are sidekiq jobs (as they all have `.perfrom_async`).
575
+ expect(job_classes).to all(respond_to(:perform_async))
576
+ end
577
+ end
578
+ ```
336
579
 
337
580
  ## Contributing
338
581
 
@@ -354,6 +597,39 @@ You can execute the test suite by running:
354
597
  $ bundle exec rake test
355
598
  ```
356
599
 
600
+ ### Using Docker
601
+
602
+ 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:
603
+
604
+ 1. Build the Docker image (only the first time):
605
+ ```
606
+ docker compose -f docker/docker-compose.yml build
607
+ ```
608
+
609
+ 2. Run the test suite:
610
+ ```
611
+ docker compose -f docker/docker-compose.yml run --rm tests
612
+ ```
613
+
614
+ _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._
615
+
616
+ **Running other commands**
617
+
618
+ In the case you need to run a command in the gem's container, you would do it like so:
619
+
620
+ ```
621
+ docker compose -f docker/docker-compose.yml run --rm tests <HERE IS YOUR COMMAND>
622
+ ```
623
+ _Note that `tests` is the Docker Compose service name defined in the `docker/docker-compose.yml` file._
624
+
625
+ **Running a single test file**
626
+
627
+ 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:
628
+
629
+ ```
630
+ docker compose -f docker/docker-compose.yml run --rm --env TEST=test/unit/web_extension_test.rb tests
631
+ ```
632
+
357
633
  ## License
358
634
 
359
635
  Copyright (c) 2013 Ondrej Bartas. See [LICENSE](LICENSE.txt) for further details.