sidekiq-scheduler 3.1.0 → 4.0.0.alpha1
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/README.md +84 -7
- data/lib/sidekiq-scheduler/extensions/web.rb +7 -1
- data/lib/sidekiq-scheduler/manager.rb +0 -4
- data/lib/sidekiq-scheduler/redis_manager.rb +12 -18
- data/lib/sidekiq-scheduler/schedule.rb +3 -1
- data/lib/sidekiq-scheduler/scheduler.rb +5 -21
- data/lib/sidekiq-scheduler/utils.rb +11 -0
- data/lib/sidekiq-scheduler/version.rb +1 -3
- data/lib/sidekiq-scheduler/web.rb +2 -2
- data/web/assets/stylesheets/recurring_jobs.css +27 -0
- data/web/views/recurring_jobs.erb +46 -44
- metadata +22 -67
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 2a45a1821398ad12b4ebc760efb1ac6aec3c62d38a1176f2a9c804a2dbf08fab
|
4
|
+
data.tar.gz: 5a9a8cb6e9c7a8262829c9f53a5aacb7ae91e5ae411627da1c189a471b803e12
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 9772349882c5194d63775696468722b637dd1ec6c420027ef25107a0821c073e6440fa797d41432e4b93c1da9964f03a3032eb3853b57fa23525a08ba606b68d
|
7
|
+
data.tar.gz: 4d424d7826176deb095cfa9450392eb3aa0b8630ee446a7dc0daf917e4ddd6c77c2bc8f7259bcb2450554bbdc77ecf3772dfbdd4f757eff1be7c7661c9bab392
|
data/README.md
CHANGED
@@ -30,7 +30,7 @@
|
|
30
30
|
`sidekiq-scheduler` is an extension to [Sidekiq](http://github.com/mperham/sidekiq) that
|
31
31
|
pushes jobs in a scheduled way, mimicking cron utility.
|
32
32
|
|
33
|
-
__Note:__
|
33
|
+
__Note:__ Current branch contains work for a V4 release, if you are looking for version 2.2.* or 3.*, go to [2.2-stable branch](https://github.com/moove-it/sidekiq-scheduler/tree/2.2-stable) / [v3-stable](https://github.com/moove-it/sidekiq-scheduler/tree/v3-stable).
|
34
34
|
|
35
35
|
## Installation
|
36
36
|
|
@@ -100,6 +100,7 @@ Available options are:
|
|
100
100
|
:enabled: <enables scheduler if true [true by default]>
|
101
101
|
:scheduler:
|
102
102
|
:listened_queues_only: <push jobs whose queue is being listened by sidekiq [false by default]>
|
103
|
+
:rufus_scheduler_options: <Set custom options for rufus scheduler, like max_work_threads [{} by default]>
|
103
104
|
```
|
104
105
|
|
105
106
|
## Schedule configuration
|
@@ -179,6 +180,14 @@ Cron, every, and interval types push jobs into sidekiq in a recurrent manner.
|
|
179
180
|
every: '45m' # Runs every 45 minutes
|
180
181
|
```
|
181
182
|
|
183
|
+
The value is parsed by [`Fugit::Duration.parse`](https://github.com/floraison/fugit#fugitduration). It understands quite a number of formats, including human-readable ones:
|
184
|
+
|
185
|
+
``` yaml
|
186
|
+
every: 45 minutes
|
187
|
+
every: 2 hours and 30 minutes
|
188
|
+
every: 1.5 hours
|
189
|
+
```
|
190
|
+
|
182
191
|
`interval` is similar to `every`, the difference between them is that `interval` type schedules the
|
183
192
|
next execution after the interval has elapsed counting from its last job enqueue.
|
184
193
|
|
@@ -296,10 +305,16 @@ If you're configuring your own Redis connection pool, you need to make sure the
|
|
296
305
|
|
297
306
|
That's a minimum of `concurrency` + 5 (per the [Sidekiq wiki](https://github.com/mperham/sidekiq/wiki/Using-Redis#complete-control)) + `Rufus::Scheduler::MAX_WORK_THREADS` (28 as of this writing; per the [Rufus README](https://github.com/jmettraux/rufus-scheduler#max_work_threads)), for a total of 58 with the default `concurrency` of 25.
|
298
307
|
|
299
|
-
You can also override the thread pool size in Rufus Scheduler by setting
|
308
|
+
You can also override the thread pool size in Rufus Scheduler by setting the following in your `sidekiq.yml` config:
|
300
309
|
|
301
|
-
```
|
302
|
-
|
310
|
+
```yaml
|
311
|
+
---
|
312
|
+
...
|
313
|
+
|
314
|
+
rufus_scheduler_options:
|
315
|
+
max_work_threads: 5
|
316
|
+
|
317
|
+
...
|
303
318
|
```
|
304
319
|
|
305
320
|
## Notes about running on Multiple Hosts
|
@@ -313,6 +328,67 @@ Non-normal conditions that could push a specific job multiple times are:
|
|
313
328
|
|
314
329
|
`every`, `interval` and `in` jobs will be pushed once per host.
|
315
330
|
|
331
|
+
## Notes on when Sidekiq worker is down
|
332
|
+
|
333
|
+
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.
|
334
|
+
|
335
|
+
Possible solutions include:
|
336
|
+
- Simply ignoring this fact, if you only run frequent periodic jobs, that can tolerate some increased interval
|
337
|
+
- Abstaining from deploys/restarts during time when critical jobs are usually scheduled
|
338
|
+
- Making your infrequent jobs idempotent (so that they can be enqueued multiple times but still produce result as if was run once) and scheduling them multiple times to reduce likelihood of not being run
|
339
|
+
- Zero downtime deploy for sidekiq workers: keep at least one worker up during whole deploy and only restart/shut it down after when new one has started
|
340
|
+
- Running scheduler inside your unicorn/rails processes (if you already have zero downtime deploy set up for these)
|
341
|
+
|
342
|
+
Each option has it's own pros and cons.
|
343
|
+
|
344
|
+
## Notes when running multiple Sidekiq processors on the same Redis
|
345
|
+
|
346
|
+
### TL;DR
|
347
|
+
|
348
|
+
Be **sure** to include the `:enabled: false` top-level key on any additional
|
349
|
+
configurations to avoid any possibility of the `schedules` definition being
|
350
|
+
wiped by the second Sidekiq process.
|
351
|
+
|
352
|
+
To illustrate what we mean:
|
353
|
+
|
354
|
+
Say you have one process with the schedule:
|
355
|
+
```yaml
|
356
|
+
# e.g., config/sidekiq.yml
|
357
|
+
|
358
|
+
:queues:
|
359
|
+
- default
|
360
|
+
:schedule:
|
361
|
+
do_something_every_minute:
|
362
|
+
class: DoSomethingJob
|
363
|
+
args: matey
|
364
|
+
queue: :scheduler
|
365
|
+
cron: '0 * * * * * America/Los_Angeles'
|
366
|
+
```
|
367
|
+
|
368
|
+
And a separate separate configured process without one:
|
369
|
+
```yaml
|
370
|
+
# e.g., config/sidekiq_other.yml
|
371
|
+
:queues:
|
372
|
+
- scheduler
|
373
|
+
|
374
|
+
## NOTE Disable the Scheduler
|
375
|
+
:enabled: false
|
376
|
+
```
|
377
|
+
|
378
|
+
### Details
|
379
|
+
|
380
|
+
This gem stores the configured schedule in Redis on boot. It's used, primarily,
|
381
|
+
to display in the Web Integration, and allow you to interact with that schedule
|
382
|
+
via that integration.
|
383
|
+
|
384
|
+
If you're running multiple Sidekiq processes on the same Redis namespace with
|
385
|
+
different configurations, **you'll want to explicitly _disable_ Sidekiq
|
386
|
+
Scheduler** for the other processes not responsible for the schedule. If you
|
387
|
+
don't, the last booted Sidekiq processes' schedule will be what is stored in
|
388
|
+
Redis.
|
389
|
+
|
390
|
+
See https://github.com/moove-it/sidekiq-scheduler/issues/361 for a more details.
|
391
|
+
|
316
392
|
## Sidekiq Web Integration
|
317
393
|
|
318
394
|
sidekiq-scheduler provides an extension to the Sidekiq web interface that adds a `Recurring Jobs` page.
|
@@ -387,6 +463,7 @@ MIT License
|
|
387
463
|
|
388
464
|
## Copyright
|
389
465
|
|
390
|
-
Copyright
|
391
|
-
Copyright
|
392
|
-
|
466
|
+
- Copyright 2021 - 2022 Marcelo Lauxen.
|
467
|
+
- Copyright 2013 - 2022 Moove-IT.
|
468
|
+
- Copyright 2012 Morton Jonuschat.
|
469
|
+
- Some parts copyright 2010 Ben VandenBos.
|
@@ -1,5 +1,11 @@
|
|
1
1
|
require 'sidekiq/web' unless defined?(Sidekiq::Web)
|
2
2
|
|
3
|
+
ASSETS_PATH = File.expand_path('../../../web/assets', __dir__)
|
4
|
+
|
3
5
|
Sidekiq::Web.register(SidekiqScheduler::Web)
|
4
6
|
Sidekiq::Web.tabs['recurring_jobs'] = 'recurring-jobs'
|
5
|
-
Sidekiq::Web.locales << File.expand_path(File.dirname(__FILE__)
|
7
|
+
Sidekiq::Web.locales << File.expand_path("#{File.dirname(__FILE__)}/../../../web/locales")
|
8
|
+
Sidekiq::Web.use Rack::Static, urls: ['/stylesheets'],
|
9
|
+
root: ASSETS_PATH,
|
10
|
+
cascade: true,
|
11
|
+
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(
|
12
|
+
hget('schedules', 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(
|
47
|
+
hset('schedules', name, JSON.generate(config))
|
48
48
|
end
|
49
49
|
|
50
50
|
# Sets the state for a given job
|
@@ -75,7 +75,7 @@ module SidekiqScheduler
|
|
75
75
|
#
|
76
76
|
# @param [String] name The name of the job
|
77
77
|
def self.remove_job_schedule(name)
|
78
|
-
hdel(
|
78
|
+
hdel('schedules', name)
|
79
79
|
end
|
80
80
|
|
81
81
|
# Removes the next execution time for a given job
|
@@ -89,20 +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(
|
92
|
+
Sidekiq.redis { |r| r.hgetall('schedules') }
|
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
|
100
|
-
if r.respond_to?(:exists?)
|
101
|
-
r.exists?(:schedules)
|
102
|
-
else
|
103
|
-
!!r.exists(:schedules)
|
104
|
-
end
|
105
|
-
end
|
99
|
+
Sidekiq.redis { |r| r.exists?('schedules') }
|
106
100
|
end
|
107
101
|
|
108
102
|
# Returns all the schedule changes for a given time range.
|
@@ -112,19 +106,19 @@ module SidekiqScheduler
|
|
112
106
|
#
|
113
107
|
# @return [Array] array with all the changed job names
|
114
108
|
def self.get_schedule_changes(from, to)
|
115
|
-
Sidekiq.redis { |r| r.zrangebyscore(
|
109
|
+
Sidekiq.redis { |r| r.zrangebyscore('schedules_changed', from, "(#{to}") }
|
116
110
|
end
|
117
111
|
|
118
112
|
# Register a schedule change for a given job
|
119
113
|
#
|
120
114
|
# @param [String] name The name of the job
|
121
115
|
def self.add_schedule_change(name)
|
122
|
-
Sidekiq.redis { |r| r.zadd(
|
116
|
+
Sidekiq.redis { |r| r.zadd('schedules_changed', Time.now.to_f, name) }
|
123
117
|
end
|
124
118
|
|
125
119
|
# Remove all the schedule changes records
|
126
120
|
def self.clean_schedules_changed
|
127
|
-
Sidekiq.redis { |r| r.del(
|
121
|
+
Sidekiq.redis { |r| r.del('schedules_changed') unless r.type('schedules_changed') == 'zset' }
|
128
122
|
end
|
129
123
|
|
130
124
|
# Removes a queued job instance
|
@@ -136,9 +130,9 @@ module SidekiqScheduler
|
|
136
130
|
def self.register_job_instance(job_name, time)
|
137
131
|
job_key = pushed_job_key(job_name)
|
138
132
|
registered, _ = Sidekiq.redis do |r|
|
139
|
-
r.pipelined do
|
140
|
-
|
141
|
-
|
133
|
+
r.pipelined do |pipeline|
|
134
|
+
pipeline.zadd(job_key, time.to_i, time.to_i)
|
135
|
+
pipeline.expire(job_key, REGISTERED_JOBS_THRESHOLD_IN_SECONDS)
|
142
136
|
end
|
143
137
|
end
|
144
138
|
|
@@ -187,7 +181,7 @@ module SidekiqScheduler
|
|
187
181
|
end
|
188
182
|
|
189
183
|
private
|
190
|
-
|
184
|
+
|
191
185
|
# Returns the value of a Redis stored hash field
|
192
186
|
#
|
193
187
|
# @param [String] hash_key The key name of the hash
|
@@ -140,7 +140,9 @@ module SidekiqScheduler
|
|
140
140
|
def infer_queue(klass)
|
141
141
|
klass = try_to_constantize(klass)
|
142
142
|
|
143
|
-
|
143
|
+
# ActiveJob uses queue_as when the job is created
|
144
|
+
# to determine the queue
|
145
|
+
if klass.respond_to?(:sidekiq_options) && !SidekiqScheduler::Utils.active_job_enqueue?(klass)
|
144
146
|
klass.sidekiq_options['queue']
|
145
147
|
end
|
146
148
|
end
|
@@ -1,5 +1,4 @@
|
|
1
1
|
require 'rufus/scheduler'
|
2
|
-
require 'thwait'
|
3
2
|
require 'sidekiq/util'
|
4
3
|
require 'json'
|
5
4
|
require 'sidekiq-scheduler/rufus_utils'
|
@@ -26,6 +25,9 @@ module SidekiqScheduler
|
|
26
25
|
# Set to schedule jobs only when will be pushed to queues listened by sidekiq
|
27
26
|
attr_accessor :listened_queues_only
|
28
27
|
|
28
|
+
# Set custom options for rufus scheduler, like max_work_threads.
|
29
|
+
attr_accessor :rufus_scheduler_options
|
30
|
+
|
29
31
|
class << self
|
30
32
|
|
31
33
|
def instance
|
@@ -47,6 +49,7 @@ module SidekiqScheduler
|
|
47
49
|
self.dynamic = options[:dynamic]
|
48
50
|
self.dynamic_every = options[:dynamic_every]
|
49
51
|
self.listened_queues_only = options[:listened_queues_only]
|
52
|
+
self.rufus_scheduler_options = options[:rufus_scheduler_options] || {}
|
50
53
|
end
|
51
54
|
|
52
55
|
# the Rufus::Scheduler jobs that are scheduled
|
@@ -161,21 +164,13 @@ module SidekiqScheduler
|
|
161
164
|
config['args'] = arguments_with_metadata(config['args'], scheduled_at: time.to_f)
|
162
165
|
end
|
163
166
|
|
164
|
-
if active_job_enqueue?(config['class'])
|
167
|
+
if SidekiqScheduler::Utils.active_job_enqueue?(config['class'])
|
165
168
|
SidekiqScheduler::Utils.enqueue_with_active_job(config)
|
166
169
|
else
|
167
170
|
SidekiqScheduler::Utils.enqueue_with_sidekiq(config)
|
168
171
|
end
|
169
172
|
end
|
170
173
|
|
171
|
-
def rufus_scheduler_options
|
172
|
-
@rufus_scheduler_options ||= {}
|
173
|
-
end
|
174
|
-
|
175
|
-
def rufus_scheduler_options=(options)
|
176
|
-
@rufus_scheduler_options = options
|
177
|
-
end
|
178
|
-
|
179
174
|
def rufus_scheduler
|
180
175
|
@rufus_scheduler ||= SidekiqScheduler::Utils.new_rufus_scheduler(rufus_scheduler_options)
|
181
176
|
end
|
@@ -307,17 +302,6 @@ module SidekiqScheduler
|
|
307
302
|
queues.empty? || queues.include?(job_queue)
|
308
303
|
end
|
309
304
|
|
310
|
-
# Returns true if the enqueuing needs to be done for an ActiveJob
|
311
|
-
# class false otherwise.
|
312
|
-
#
|
313
|
-
# @param [Class] klass the class to check is decendant from ActiveJob
|
314
|
-
#
|
315
|
-
# @return [Boolean]
|
316
|
-
def active_job_enqueue?(klass)
|
317
|
-
klass.is_a?(Class) && defined?(ActiveJob::Enqueuing) &&
|
318
|
-
klass.included_modules.include?(ActiveJob::Enqueuing)
|
319
|
-
end
|
320
|
-
|
321
305
|
# Convert the given arguments in the format expected to be enqueued.
|
322
306
|
#
|
323
307
|
# @param [Hash] config the options to be converted
|
@@ -68,6 +68,17 @@ module SidekiqScheduler
|
|
68
68
|
end
|
69
69
|
end
|
70
70
|
|
71
|
+
# Returns true if the enqueuing needs to be done for an ActiveJob
|
72
|
+
# class false otherwise.
|
73
|
+
#
|
74
|
+
# @param [Class] klass the class to check is decendant from ActiveJob
|
75
|
+
#
|
76
|
+
# @return [Boolean]
|
77
|
+
def self.active_job_enqueue?(klass)
|
78
|
+
klass.is_a?(Class) && defined?(ActiveJob::Enqueuing) &&
|
79
|
+
klass.included_modules.include?(ActiveJob::Enqueuing)
|
80
|
+
end
|
81
|
+
|
71
82
|
# Enqueues the job using the Sidekiq client.
|
72
83
|
#
|
73
84
|
# @param [Hash] config The job configuration
|
@@ -15,13 +15,13 @@ module SidekiqScheduler
|
|
15
15
|
erb File.read(File.join(VIEW_PATH, 'recurring_jobs.erb'))
|
16
16
|
end
|
17
17
|
|
18
|
-
app.
|
18
|
+
app.post '/recurring-jobs/:name/enqueue' do
|
19
19
|
schedule = Sidekiq.get_schedule(params[:name])
|
20
20
|
SidekiqScheduler::Scheduler.instance.enqueue_job(schedule)
|
21
21
|
redirect "#{root_path}recurring-jobs"
|
22
22
|
end
|
23
23
|
|
24
|
-
app.
|
24
|
+
app.post '/recurring-jobs/:name/toggle' do
|
25
25
|
Sidekiq.reload_schedule!
|
26
26
|
|
27
27
|
SidekiqScheduler::Scheduler.instance.toggle_job_enabled(params[:name])
|
@@ -0,0 +1,27 @@
|
|
1
|
+
.recurring-jobs { border-top-left-radius: 4px; border-top-right-radius: 4px; }
|
2
|
+
.recurring-jobs .title { margin-bottom: 5px; }
|
3
|
+
.recurring-jobs .title .name { font-weight: bold;}
|
4
|
+
.recurring-jobs .info,
|
5
|
+
.recurring-jobs .description { margin-bottom: 5px; }
|
6
|
+
.recurring-jobs .actions { margin-bottom: 5px; }
|
7
|
+
.recurring-jobs .status,
|
8
|
+
.recurring-jobs .description { font-size: 12px; }
|
9
|
+
.recurring-jobs .enqueue { margin-bottom: 0.5rem }
|
10
|
+
|
11
|
+
.list-group-item {
|
12
|
+
background-color: #f3f3f3;
|
13
|
+
color: #585454;
|
14
|
+
border: 1px solid rgba(0, 0, 0, 0.1);
|
15
|
+
}
|
16
|
+
|
17
|
+
.list-group-item-disabled {
|
18
|
+
background-color: #f3d3d3;
|
19
|
+
}
|
20
|
+
|
21
|
+
@media (prefers-color-scheme: dark) {
|
22
|
+
.list-group-item {
|
23
|
+
background-color: #222;
|
24
|
+
color: white;
|
25
|
+
border: 1px solid #555;
|
26
|
+
}
|
27
|
+
}
|
@@ -1,48 +1,50 @@
|
|
1
|
-
<
|
1
|
+
<link href="<%= root_path %>stylesheets/recurring_jobs.css" media="screen" rel="stylesheet" type="text/css" />
|
2
2
|
|
3
|
-
<
|
4
|
-
<table class="table table-hover table-bordered table-striped table-white">
|
5
|
-
<thead>
|
6
|
-
<tr>
|
7
|
-
<th><%= t('name') %></th>
|
8
|
-
<th><%= t('description') %></th>
|
9
|
-
<th><%= t('interval') %></th>
|
10
|
-
<th><%= t('class') %></th>
|
11
|
-
<th><%= t('queue') %></th>
|
12
|
-
<th><%= t('arguments') %></th>
|
13
|
-
<th><%= t('last_time') %></th>
|
14
|
-
<th><%= t('next_time') %></th>
|
15
|
-
<th></th>
|
16
|
-
</tr>
|
17
|
-
</thead>
|
3
|
+
<h3><%= t('recurring_jobs') %></h3>
|
18
4
|
|
19
|
-
|
20
|
-
|
21
|
-
|
22
|
-
|
23
|
-
|
24
|
-
<
|
25
|
-
|
26
|
-
|
27
|
-
|
28
|
-
|
29
|
-
|
30
|
-
|
31
|
-
|
32
|
-
|
33
|
-
|
5
|
+
<div class="recurring-jobs">
|
6
|
+
<ul class="list-group">
|
7
|
+
<% @presented_jobs.each do |job| %>
|
8
|
+
<li class="list-group-item <%= !job.enabled? && "list-group-item-disabled" %>">
|
9
|
+
<div class="title">
|
10
|
+
<div class="row">
|
11
|
+
<div class="col-xs-6">
|
12
|
+
<span class="name"><%= job.name %></span>
|
13
|
+
</div>
|
14
|
+
<div class="col-xs-6 text-right">
|
15
|
+
<a href="<%= root_path %>queues/<%= job.queue %>"><%= job.queue %></a>
|
16
|
+
</div>
|
17
|
+
</div>
|
18
|
+
</div>
|
19
|
+
<div class="description"><%= job['description'] %></div>
|
20
|
+
<div class="info">
|
21
|
+
<div class="row">
|
22
|
+
<div class="col-md-4 class"><%= job['class'] %></div>
|
23
|
+
<div class="col-md-4 interval text-left"><%= t('interval') %>: <%= job.interval %></div>
|
24
|
+
<div class="col-md-4 args"><%= t('arguments') %>: <%= job['args'] %></div>
|
25
|
+
</div>
|
26
|
+
</div>
|
27
|
+
<div class="status row">
|
28
|
+
<div class="col-md-4 actions">
|
29
|
+
<form action="<%= root_path %>recurring-jobs/<%= ERB::Util.url_encode(job.name) %>/enqueue" method="post" class="enqueue">
|
30
|
+
<%= csrf_tag %>
|
31
|
+
<input type="submit" class="btn btn-warn btn-xs" value="<%= t('enqueue_now') %>" />
|
32
|
+
</form>
|
33
|
+
<form action="<%= root_path %>recurring-jobs/<%= ERB::Util.url_encode(job.name) %>/toggle" method="post">
|
34
|
+
<%= csrf_tag %>
|
35
|
+
<input type="submit" class="btn <%= job.enabled? ? "btn-primary" : "btn-warn"%> btn-xs" value="<%= job.enabled? ? t('disable') : t('enable') %>" />
|
36
|
+
</form>
|
37
|
+
</div>
|
38
|
+
<div class="col-md-4">
|
39
|
+
<span class="last_time"><%= t('last_time') %>: <%= job.last_time %></span>
|
40
|
+
</div>
|
41
|
+
<div class="col-md-4">
|
42
|
+
<span class="next_time text-right" style="<%= 'text-decoration:line-through' unless job.enabled? %>">
|
43
|
+
<%= t('next_time') %>: <%= job.next_time || t('no_next_time') %>
|
34
44
|
</span>
|
35
|
-
</
|
36
|
-
|
37
|
-
|
38
|
-
|
39
|
-
|
40
|
-
<a class="btn <%= job.enabled? ? "btn-primary" : "btn-warn"%> btn-xs" href="<%= root_path %>recurring-jobs/<%= ERB::Util.url_encode(job.name) %>/toggle">
|
41
|
-
<%= job.enabled? ? t('disable') : t('enable') %>
|
42
|
-
</a>
|
43
|
-
</td>
|
44
|
-
</tr>
|
45
|
-
<% end %>
|
46
|
-
</tbody>
|
47
|
-
</table>
|
45
|
+
</div>
|
46
|
+
</div>
|
47
|
+
</li>
|
48
|
+
<% end %>
|
49
|
+
</ul>
|
48
50
|
</div>
|
metadata
CHANGED
@@ -1,15 +1,16 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: sidekiq-scheduler
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version:
|
4
|
+
version: 4.0.0.alpha1
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Morton Jonuschat
|
8
8
|
- Moove-it
|
9
|
-
|
9
|
+
- Marcelo Lauxen
|
10
|
+
autorequire:
|
10
11
|
bindir: bin
|
11
12
|
cert_chain: []
|
12
|
-
date:
|
13
|
+
date: 2022-04-21 00:00:00.000000000 Z
|
13
14
|
dependencies:
|
14
15
|
- !ruby/object:Gem::Dependency
|
15
16
|
name: sidekiq
|
@@ -31,20 +32,14 @@ dependencies:
|
|
31
32
|
requirements:
|
32
33
|
- - ">="
|
33
34
|
- !ruby/object:Gem::Version
|
34
|
-
version:
|
35
|
-
- - "<"
|
36
|
-
- !ruby/object:Gem::Version
|
37
|
-
version: '5'
|
35
|
+
version: 4.2.0
|
38
36
|
type: :runtime
|
39
37
|
prerelease: false
|
40
38
|
version_requirements: !ruby/object:Gem::Requirement
|
41
39
|
requirements:
|
42
40
|
- - ">="
|
43
41
|
- !ruby/object:Gem::Version
|
44
|
-
version:
|
45
|
-
- - "<"
|
46
|
-
- !ruby/object:Gem::Version
|
47
|
-
version: '5'
|
42
|
+
version: 4.2.0
|
48
43
|
- !ruby/object:Gem::Dependency
|
49
44
|
name: rufus-scheduler
|
50
45
|
requirement: !ruby/object:Gem::Requirement
|
@@ -73,34 +68,6 @@ dependencies:
|
|
73
68
|
- - ">="
|
74
69
|
- !ruby/object:Gem::Version
|
75
70
|
version: 1.4.0
|
76
|
-
- !ruby/object:Gem::Dependency
|
77
|
-
name: thwait
|
78
|
-
requirement: !ruby/object:Gem::Requirement
|
79
|
-
requirements:
|
80
|
-
- - ">="
|
81
|
-
- !ruby/object:Gem::Version
|
82
|
-
version: '0'
|
83
|
-
type: :runtime
|
84
|
-
prerelease: false
|
85
|
-
version_requirements: !ruby/object:Gem::Requirement
|
86
|
-
requirements:
|
87
|
-
- - ">="
|
88
|
-
- !ruby/object:Gem::Version
|
89
|
-
version: '0'
|
90
|
-
- !ruby/object:Gem::Dependency
|
91
|
-
name: e2mmap
|
92
|
-
requirement: !ruby/object:Gem::Requirement
|
93
|
-
requirements:
|
94
|
-
- - ">="
|
95
|
-
- !ruby/object:Gem::Version
|
96
|
-
version: '0'
|
97
|
-
type: :runtime
|
98
|
-
prerelease: false
|
99
|
-
version_requirements: !ruby/object:Gem::Requirement
|
100
|
-
requirements:
|
101
|
-
- - ">="
|
102
|
-
- !ruby/object:Gem::Version
|
103
|
-
version: '0'
|
104
71
|
- !ruby/object:Gem::Dependency
|
105
72
|
name: rake
|
106
73
|
requirement: !ruby/object:Gem::Requirement
|
@@ -119,28 +86,28 @@ dependencies:
|
|
119
86
|
name: timecop
|
120
87
|
requirement: !ruby/object:Gem::Requirement
|
121
88
|
requirements:
|
122
|
-
- - "
|
89
|
+
- - ">="
|
123
90
|
- !ruby/object:Gem::Version
|
124
91
|
version: '0'
|
125
92
|
type: :development
|
126
93
|
prerelease: false
|
127
94
|
version_requirements: !ruby/object:Gem::Requirement
|
128
95
|
requirements:
|
129
|
-
- - "
|
96
|
+
- - ">="
|
130
97
|
- !ruby/object:Gem::Version
|
131
98
|
version: '0'
|
132
99
|
- !ruby/object:Gem::Dependency
|
133
100
|
name: mocha
|
134
101
|
requirement: !ruby/object:Gem::Requirement
|
135
102
|
requirements:
|
136
|
-
- - "
|
103
|
+
- - ">="
|
137
104
|
- !ruby/object:Gem::Version
|
138
105
|
version: '0'
|
139
106
|
type: :development
|
140
107
|
prerelease: false
|
141
108
|
version_requirements: !ruby/object:Gem::Requirement
|
142
109
|
requirements:
|
143
|
-
- - "
|
110
|
+
- - ">="
|
144
111
|
- !ruby/object:Gem::Version
|
145
112
|
version: '0'
|
146
113
|
- !ruby/object:Gem::Dependency
|
@@ -163,30 +130,16 @@ dependencies:
|
|
163
130
|
requirements:
|
164
131
|
- - "~>"
|
165
132
|
- !ruby/object:Gem::Version
|
166
|
-
version: 0.
|
133
|
+
version: 0.28.0
|
167
134
|
type: :development
|
168
135
|
prerelease: false
|
169
136
|
version_requirements: !ruby/object:Gem::Requirement
|
170
137
|
requirements:
|
171
138
|
- - "~>"
|
172
139
|
- !ruby/object:Gem::Version
|
173
|
-
version: 0.
|
140
|
+
version: 0.28.0
|
174
141
|
- !ruby/object:Gem::Dependency
|
175
142
|
name: simplecov
|
176
|
-
requirement: !ruby/object:Gem::Requirement
|
177
|
-
requirements:
|
178
|
-
- - "~>"
|
179
|
-
- !ruby/object:Gem::Version
|
180
|
-
version: '0'
|
181
|
-
type: :development
|
182
|
-
prerelease: false
|
183
|
-
version_requirements: !ruby/object:Gem::Requirement
|
184
|
-
requirements:
|
185
|
-
- - "~>"
|
186
|
-
- !ruby/object:Gem::Version
|
187
|
-
version: '0'
|
188
|
-
- !ruby/object:Gem::Dependency
|
189
|
-
name: byebug
|
190
143
|
requirement: !ruby/object:Gem::Requirement
|
191
144
|
requirements:
|
192
145
|
- - ">="
|
@@ -200,7 +153,7 @@ dependencies:
|
|
200
153
|
- !ruby/object:Gem::Version
|
201
154
|
version: '0'
|
202
155
|
- !ruby/object:Gem::Dependency
|
203
|
-
name:
|
156
|
+
name: byebug
|
204
157
|
requirement: !ruby/object:Gem::Requirement
|
205
158
|
requirements:
|
206
159
|
- - ">="
|
@@ -214,7 +167,7 @@ dependencies:
|
|
214
167
|
- !ruby/object:Gem::Version
|
215
168
|
version: '0'
|
216
169
|
- !ruby/object:Gem::Dependency
|
217
|
-
name:
|
170
|
+
name: activejob
|
218
171
|
requirement: !ruby/object:Gem::Requirement
|
219
172
|
requirements:
|
220
173
|
- - ">="
|
@@ -259,6 +212,7 @@ description: Light weight job scheduling extension for Sidekiq that adds support
|
|
259
212
|
queueing jobs in a recurring way.
|
260
213
|
email:
|
261
214
|
- sidekiq-scheduler@moove-it.com
|
215
|
+
- marcelolauxen16@gmail.com
|
262
216
|
executables: []
|
263
217
|
extensions: []
|
264
218
|
extra_rdoc_files: []
|
@@ -279,6 +233,7 @@ files:
|
|
279
233
|
- lib/sidekiq-scheduler/version.rb
|
280
234
|
- lib/sidekiq-scheduler/web.rb
|
281
235
|
- lib/sidekiq/scheduler.rb
|
236
|
+
- web/assets/stylesheets/recurring_jobs.css
|
282
237
|
- web/locales/cs.yml
|
283
238
|
- web/locales/de.yml
|
284
239
|
- web/locales/en.yml
|
@@ -297,7 +252,7 @@ homepage: https://moove-it.github.io/sidekiq-scheduler/
|
|
297
252
|
licenses:
|
298
253
|
- MIT
|
299
254
|
metadata: {}
|
300
|
-
post_install_message:
|
255
|
+
post_install_message:
|
301
256
|
rdoc_options: []
|
302
257
|
require_paths:
|
303
258
|
- lib
|
@@ -305,15 +260,15 @@ required_ruby_version: !ruby/object:Gem::Requirement
|
|
305
260
|
requirements:
|
306
261
|
- - ">="
|
307
262
|
- !ruby/object:Gem::Version
|
308
|
-
version: '
|
263
|
+
version: '2.5'
|
309
264
|
required_rubygems_version: !ruby/object:Gem::Requirement
|
310
265
|
requirements:
|
311
|
-
- - "
|
266
|
+
- - ">"
|
312
267
|
- !ruby/object:Gem::Version
|
313
|
-
version:
|
268
|
+
version: 1.3.1
|
314
269
|
requirements: []
|
315
|
-
rubygems_version: 3.2.
|
316
|
-
signing_key:
|
270
|
+
rubygems_version: 3.2.19
|
271
|
+
signing_key:
|
317
272
|
specification_version: 4
|
318
273
|
summary: Light weight job scheduling extension for Sidekiq
|
319
274
|
test_files: []
|