dynamodb-sidekiq-scheduler 0.0.1

Sign up to get free protection for your applications and to get access to all the features.
@@ -0,0 +1,356 @@
1
+ require 'rufus/scheduler'
2
+ require 'json'
3
+ require 'sidekiq-scheduler/rufus_utils'
4
+ require 'sidekiq-scheduler/redis_manager'
5
+ require 'sidekiq-scheduler/config'
6
+
7
+ module SidekiqScheduler
8
+ class Scheduler
9
+ # We expect rufus jobs to have #params
10
+ Rufus::Scheduler::Job.module_eval do
11
+ alias_method :params, :opts
12
+ end
13
+
14
+ # TODO: Can we remove those attr_accessor's? If we need to keep them, we should
15
+ # update those values on the config object instead of just here in the scheduler.
16
+ # That's why we need to do what we do in the set_current_scheduler_options (not
17
+ # saying we will have to do it somehow still)
18
+ #
19
+ # NOTE: ^ Keeping this TODO here for now, in a future version of this project
20
+ # we will remove those attr acessors and use only our config object. For now,
21
+ # let's keep as it is.
22
+
23
+ # Set to enable or disable the scheduler.
24
+ attr_accessor :enabled
25
+
26
+ # Set to update the schedule in runtime in a given time period.
27
+ attr_accessor :dynamic
28
+
29
+ # Set to update the schedule in runtime dynamically per this period.
30
+ attr_accessor :dynamic_every
31
+
32
+ # Set to schedule jobs only when will be pushed to queues listened by sidekiq
33
+ attr_accessor :listened_queues_only
34
+
35
+ # Set custom options for rufus scheduler, like max_work_threads.
36
+ attr_accessor :rufus_scheduler_options
37
+
38
+ class << self
39
+
40
+ def instance
41
+ @instance = new unless @instance
42
+ @instance
43
+ end
44
+
45
+ def instance=(value)
46
+ @instance = value
47
+ end
48
+
49
+ def method_missing(method, *arguments, &block)
50
+ instance_methods.include?(method) ? instance.public_send(method, *arguments) : super
51
+ end
52
+ end
53
+
54
+ def initialize(config = SidekiqScheduler::Config.new(without_defaults: true))
55
+ @scheduler_config = config
56
+
57
+ self.enabled = config.enabled?
58
+ self.dynamic = config.dynamic?
59
+ self.dynamic_every = config.dynamic_every?
60
+ self.listened_queues_only = config.listened_queues_only?
61
+ self.rufus_scheduler_options = config.rufus_scheduler_options
62
+ end
63
+
64
+ # the Rufus::Scheduler jobs that are scheduled
65
+ def scheduled_jobs
66
+ @scheduled_jobs
67
+ end
68
+
69
+ def print_schedule
70
+ if rufus_scheduler
71
+ Sidekiq.logger.info "Scheduling Info\tLast Run"
72
+ scheduler_jobs = rufus_scheduler.jobs
73
+ scheduler_jobs.each_value do |v|
74
+ Sidekiq.logger.info "#{v.t}\t#{v.last}\t"
75
+ end
76
+ end
77
+ end
78
+
79
+ # Pulls the schedule from Sidekiq.schedule and loads it into the
80
+ # rufus scheduler instance
81
+ def load_schedule!
82
+ if enabled
83
+ Sidekiq.logger.info 'Loading Schedule'
84
+
85
+ # Load schedule from redis for the first time if dynamic
86
+ if dynamic
87
+ Sidekiq.reload_schedule!
88
+ @current_changed_score = Time.now.to_f
89
+ rufus_scheduler.every(dynamic_every) do
90
+ update_schedule
91
+ end
92
+ end
93
+
94
+ Sidekiq.logger.info 'Schedule empty! Set Sidekiq.schedule' if Sidekiq.schedule.empty?
95
+
96
+ @scheduled_jobs = {}
97
+ queues = scheduler_config.sidekiq_queues
98
+
99
+ Sidekiq.schedule.each do |name, config|
100
+ if !listened_queues_only || enabled_queue?(config['queue'].to_s, queues)
101
+ load_schedule_job(name, config)
102
+ else
103
+ Sidekiq.logger.info { "Ignoring #{name}, job's queue is not enabled." }
104
+ end
105
+ end
106
+
107
+ Sidekiq.logger.info 'Schedules Loaded'
108
+ else
109
+ Sidekiq.logger.info 'SidekiqScheduler is disabled'
110
+ end
111
+ end
112
+
113
+ # Loads a job schedule into the Rufus::Scheduler and stores it in @scheduled_jobs
114
+ def load_schedule_job(name, config)
115
+ # If rails_env is set in the config, enforce ENV['RAILS_ENV'] as
116
+ # required for the jobs to be scheduled. If rails_env is missing, the
117
+ # job should be scheduled regardless of what ENV['RAILS_ENV'] is set
118
+ # to.
119
+ if config['rails_env'].nil? || rails_env_matches?(config)
120
+ Sidekiq.logger.info "Scheduling #{name} #{config}"
121
+ interval_defined = false
122
+ interval_types = %w(cron every at in interval)
123
+ interval_types.each do |interval_type|
124
+ config_interval_type = config[interval_type]
125
+
126
+ if !config_interval_type.nil? && config_interval_type.length > 0
127
+
128
+ schedule, options = SidekiqScheduler::RufusUtils.normalize_schedule_options(config_interval_type)
129
+
130
+ rufus_job = new_job(name, interval_type, config, schedule, options)
131
+ @scheduled_jobs[name] = rufus_job
132
+ SidekiqScheduler::Utils.update_job_next_time(name, rufus_job.next_time)
133
+
134
+ interval_defined = true
135
+
136
+ break
137
+ end
138
+ end
139
+
140
+ unless interval_defined
141
+ Sidekiq.logger.info "no #{interval_types.join(' / ')} found for #{config['class']} (#{name}) - skipping"
142
+ end
143
+ end
144
+ end
145
+
146
+ # Pushes the job into Sidekiq if not already pushed for the given time
147
+ #
148
+ # @param [String] job_name The job's name
149
+ # @param [Time] time The time when the job got cleared for triggering
150
+ # @param [Hash] config Job's config hash
151
+ def idempotent_job_enqueue(job_name, time, config)
152
+ registered = SidekiqScheduler::RedisManager.register_job_instance(job_name, time)
153
+
154
+ if registered
155
+ Sidekiq.logger.info "queueing #{config['class']} (#{job_name})"
156
+
157
+ handle_errors { enqueue_job(config, time) }
158
+
159
+ SidekiqScheduler::RedisManager.remove_elder_job_instances(job_name)
160
+ else
161
+ Sidekiq.logger.debug { "Ignoring #{job_name} job as it has been already enqueued" }
162
+ end
163
+ end
164
+
165
+ # Enqueue a job based on a config hash
166
+ #
167
+ # @param job_config [Hash] the job configuration
168
+ # @param time [Time] time the job is enqueued
169
+ def enqueue_job(job_config, time = Time.now)
170
+ config = prepare_arguments(job_config.dup)
171
+
172
+ if config.delete('include_metadata')
173
+ config['args'] = arguments_with_metadata(config['args'], "scheduled_at" => time.to_f.round(3))
174
+ end
175
+
176
+ if SidekiqScheduler::Utils.active_job_enqueue?(config['class'])
177
+ SidekiqScheduler::Utils.enqueue_with_active_job(config)
178
+ else
179
+ SidekiqScheduler::Utils.enqueue_with_sidekiq(config)
180
+ end
181
+ end
182
+
183
+ def rufus_scheduler
184
+ @rufus_scheduler ||= SidekiqScheduler::Utils.new_rufus_scheduler(rufus_scheduler_options)
185
+ end
186
+
187
+ # Stops old rufus scheduler and creates a new one. Returns the new
188
+ # rufus scheduler
189
+ #
190
+ # @param [Symbol] stop_option The option to be passed to Rufus::Scheduler#stop
191
+ def clear_schedule!(stop_option = :wait)
192
+ if @rufus_scheduler
193
+ @rufus_scheduler.stop(stop_option)
194
+ @rufus_scheduler = nil
195
+ end
196
+
197
+ @@scheduled_jobs = {}
198
+
199
+ rufus_scheduler
200
+ end
201
+
202
+ def reload_schedule!
203
+ if enabled
204
+ Sidekiq.logger.info 'Reloading Schedule'
205
+ clear_schedule!
206
+ load_schedule!
207
+ else
208
+ Sidekiq.logger.info 'SidekiqScheduler is disabled'
209
+ end
210
+ end
211
+
212
+ def update_schedule
213
+ last_changed_score, @current_changed_score = @current_changed_score, Time.now.to_f
214
+ schedule_changes = SidekiqScheduler::RedisManager.get_schedule_changes(last_changed_score, @current_changed_score)
215
+
216
+ if schedule_changes.size > 0
217
+ Sidekiq.logger.info 'Updating schedule'
218
+
219
+ Sidekiq.reload_schedule!
220
+ schedule_changes.each do |schedule_name|
221
+ if Sidekiq.schedule.keys.include?(schedule_name)
222
+ unschedule_job(schedule_name)
223
+ load_schedule_job(schedule_name, Sidekiq.schedule[schedule_name])
224
+ else
225
+ unschedule_job(schedule_name)
226
+ end
227
+ end
228
+ Sidekiq.logger.info 'Schedule updated'
229
+ end
230
+ end
231
+
232
+ def job_enabled?(name)
233
+ job = Sidekiq.schedule[name]
234
+ schedule_state(name).fetch('enabled', job.fetch('enabled', true)) if job
235
+ end
236
+
237
+ def toggle_job_enabled(name)
238
+ state = schedule_state(name)
239
+ state['enabled'] = !job_enabled?(name)
240
+ set_schedule_state(name, state)
241
+ end
242
+
243
+ def toggle_all_jobs(new_state)
244
+ Sidekiq.schedule!.keys.each do |name|
245
+ state = schedule_state(name)
246
+ state['enabled'] = new_state
247
+ set_schedule_state(name, state)
248
+ end
249
+ end
250
+
251
+ private
252
+
253
+ attr_reader :scheduler_config
254
+
255
+ def new_job(name, interval_type, config, schedule, options)
256
+ options = options.merge({ :job => true, :tags => [name] })
257
+
258
+ rufus_scheduler.send(interval_type, schedule, options) do |job, time|
259
+ idempotent_job_enqueue(name, time, SidekiqScheduler::Utils.sanitize_job_config(config)) if job_enabled?(name)
260
+ end
261
+ end
262
+
263
+ def unschedule_job(name)
264
+ if scheduled_jobs[name]
265
+ Sidekiq.logger.debug "Removing schedule #{name}"
266
+ scheduled_jobs[name].unschedule
267
+ scheduled_jobs.delete(name)
268
+ end
269
+ end
270
+
271
+ # Retrieves a schedule state
272
+ #
273
+ # @param name [String] with the schedule's name
274
+ # @return [Hash] with the schedule's state
275
+ def schedule_state(name)
276
+ state = SidekiqScheduler::RedisManager.get_job_state(name)
277
+
278
+ state ? JSON.parse(state) : {}
279
+ end
280
+
281
+ # Saves a schedule state
282
+ #
283
+ # @param name [String] with the schedule's name
284
+ # @param state [Hash] with the schedule's state
285
+ def set_schedule_state(name, state)
286
+ SidekiqScheduler::RedisManager.set_job_state(name, state)
287
+ end
288
+
289
+ # Adds a Hash with schedule metadata as the last argument to call the worker.
290
+ # It currently returns the schedule time as a Float number representing the milisencods
291
+ # since epoch.
292
+ #
293
+ # @example with hash argument
294
+ # arguments_with_metadata({value: 1}, scheduled_at: Time.now.round(3))
295
+ # #=> [{value: 1}, {scheduled_at: <miliseconds since epoch>}]
296
+ #
297
+ # @param args [Array|Hash]
298
+ # @param metadata [Hash]
299
+ # @return [Array] arguments with added metadata
300
+ def arguments_with_metadata(args, metadata)
301
+ if args.is_a? Array
302
+ [*args, metadata]
303
+ else
304
+ [args, metadata]
305
+ end
306
+ end
307
+
308
+ # Returns true if a job's queue is included in the array of queues
309
+ #
310
+ # If queues are empty, returns true.
311
+ #
312
+ # @param [String] job_queue Job's queue name
313
+ # @param [Array<String>] queues
314
+ #
315
+ # @return [Boolean]
316
+ def enabled_queue?(job_queue, queues)
317
+ queues.empty? || queues.include?(job_queue)
318
+ end
319
+
320
+ # Convert the given arguments in the format expected to be enqueued.
321
+ #
322
+ # @param [Hash] config the options to be converted
323
+ # @option config [String] class the job class
324
+ # @option config [Hash/Array] args the arguments to be passed to the job
325
+ # class
326
+ #
327
+ # @return [Hash]
328
+ def prepare_arguments(config)
329
+ config['class'] = SidekiqScheduler::Utils.try_to_constantize(config['class'])
330
+
331
+ if config['args'].is_a?(Hash)
332
+ config['args'].symbolize_keys! if config['args'].respond_to?(:symbolize_keys!)
333
+ else
334
+ config['args'] = Array(config['args'])
335
+ end
336
+
337
+ config
338
+ end
339
+
340
+ # Returns true if the given schedule config hash matches the current ENV['RAILS_ENV']
341
+ # @param [Hash] config The schedule job configuration
342
+ #
343
+ # @return [Boolean] true if the schedule config matches the current ENV['RAILS_ENV']
344
+ def rails_env_matches?(config)
345
+ config['rails_env'] && ENV['RAILS_ENV'] && config['rails_env'].gsub(/\s/, '').split(',').include?(ENV['RAILS_ENV'])
346
+ end
347
+
348
+ def handle_errors
349
+ begin
350
+ yield
351
+ rescue StandardError => e
352
+ Sidekiq.logger.info "#{e.class.name}: #{e.message}"
353
+ end
354
+ end
355
+ end
356
+ end
@@ -0,0 +1,80 @@
1
+ module SidekiqScheduler
2
+ class OptionNotSupportedAnymore < StandardError; end
3
+
4
+ class SidekiqAdapter
5
+ SIDEKIQ_GTE_6_5_0 = Gem::Version.new(Sidekiq::VERSION) >= Gem::Version.new('6.5.0')
6
+ SIDEKIQ_GTE_7_0_0 = Gem::Version.new(Sidekiq::VERSION) >= Gem::Version.new('7.0.0')
7
+
8
+ def self.fetch_scheduler_config_from_sidekiq(sidekiq_config)
9
+ return {} if sidekiq_config.nil?
10
+
11
+ check_using_old_sidekiq_scheduler_config!(sidekiq_config)
12
+
13
+ if SIDEKIQ_GTE_6_5_0
14
+ sidekiq_config.fetch(:scheduler, {})
15
+ else
16
+ sidekiq_config.options.fetch(:scheduler, {})
17
+ end
18
+ end
19
+
20
+ def self.check_using_old_sidekiq_scheduler_config!(sidekiq_config)
21
+ %i[enabled dynamic dynamic_every schedule listened_queues_only rufus_scheduler_options].each do |option|
22
+ if SIDEKIQ_GTE_7_0_0
23
+ if sidekiq_config.key?(option)
24
+ raise OptionNotSupportedAnymore, ":#{option} option should be under the :scheduler: key"
25
+ end
26
+ elsif SIDEKIQ_GTE_6_5_0
27
+ unless sidekiq_config[option].nil?
28
+ raise OptionNotSupportedAnymore, ":#{option} option should be under the :scheduler: key"
29
+ end
30
+ else
31
+ if sidekiq_config.options.key?(option)
32
+ raise OptionNotSupportedAnymore, ":#{option} option should be under the :scheduler: key"
33
+ end
34
+ end
35
+ end
36
+ end
37
+
38
+ def self.start_schedule_manager(sidekiq_config:, schedule_manager:)
39
+ if SIDEKIQ_GTE_6_5_0
40
+ sidekiq_config[:schedule_manager] = schedule_manager
41
+ sidekiq_config[:schedule_manager].start
42
+ else
43
+ sidekiq_config.options[:schedule_manager] = schedule_manager
44
+ sidekiq_config.options[:schedule_manager].start
45
+ end
46
+ end
47
+
48
+ def self.stop_schedule_manager(sidekiq_config:)
49
+ if SIDEKIQ_GTE_6_5_0
50
+ sidekiq_config[:schedule_manager].stop
51
+ else
52
+ sidekiq_config.options[:schedule_manager].stop
53
+ end
54
+ end
55
+
56
+ def self.sidekiq_queues(sidekiq_config)
57
+ if SIDEKIQ_GTE_7_0_0
58
+ if sidekiq_config.nil? || (sidekiq_config.respond_to?(:empty?) && sidekiq_config.empty?)
59
+ Sidekiq.instance_variable_get(:@config).queues.map(&:to_s)
60
+ else
61
+ sidekiq_config.queues.map(&:to_s)
62
+ end
63
+ elsif SIDEKIQ_GTE_6_5_0
64
+ Sidekiq[:queues].map(&:to_s)
65
+ else
66
+ Sidekiq.options[:queues].map(&:to_s)
67
+ end
68
+ end
69
+
70
+ def self.redis_key_exists?(key_name)
71
+ Sidekiq.redis do |r|
72
+ if SIDEKIQ_GTE_7_0_0
73
+ r.exists(key_name) > 0
74
+ else
75
+ r.exists?(key_name)
76
+ end
77
+ end
78
+ end
79
+ end
80
+ end
@@ -0,0 +1,143 @@
1
+ require 'set'
2
+
3
+ module SidekiqScheduler
4
+ module Utils
5
+
6
+ RUFUS_METADATA_KEYS = %w(description at cron every in interval enabled)
7
+
8
+ # Stringify keys belonging to a hash.
9
+ #
10
+ # Also stringifies nested keys and keys of hashes inside arrays, and sets
11
+ #
12
+ # @param [Object] object
13
+ #
14
+ # @return [Object]
15
+ def self.stringify_keys(object)
16
+ if object.is_a?(Hash)
17
+ Hash[[*object.map { |k, v| [k.to_s, stringify_keys(v) ]} ]]
18
+
19
+ elsif object.is_a?(Array) || object.is_a?(Set)
20
+ object.map { |v| stringify_keys(v) }
21
+
22
+ else
23
+ object
24
+ end
25
+ end
26
+
27
+ # Symbolize keys belonging to a hash.
28
+ #
29
+ # Also symbolizes nested keys and keys of hashes inside arrays, and sets
30
+ #
31
+ # @param [Object] object
32
+ #
33
+ # @return [Object]
34
+ def self.symbolize_keys(object)
35
+ if object.is_a?(Hash)
36
+ Hash[[*object.map { |k, v| [k.to_sym, symbolize_keys(v) ]} ]]
37
+
38
+ elsif object.is_a?(Array) || object.is_a?(Set)
39
+ object.map { |v| symbolize_keys(v) }
40
+
41
+ else
42
+ object
43
+ end
44
+ end
45
+
46
+ # Constantize a given string.
47
+ #
48
+ # @param [String] klass The string to constantize
49
+ #
50
+ # @return [Class] the class corresponding to the klass param
51
+ def self.try_to_constantize(klass)
52
+ klass.is_a?(String) ? Object.const_get(klass) : klass
53
+ rescue NameError
54
+ klass
55
+ end
56
+
57
+ # Initializes active_job using the passed parameters.
58
+ #
59
+ # @param [Class] klass The class to initialize
60
+ # @param [Array, Hash] args The parameters passed to the klass initializer
61
+ #
62
+ # @return [Object] instance of the class klass
63
+ def self.initialize_active_job(klass, args)
64
+ if args.is_a?(Array)
65
+ klass.new(*args)
66
+ else
67
+ klass.new(args)
68
+ end
69
+ end
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
+
82
+ # Enqueues the job using the Sidekiq client.
83
+ #
84
+ # @param [Hash] config The job configuration
85
+ def self.enqueue_with_sidekiq(config)
86
+ Sidekiq::Client.push(sanitize_job_config(config))
87
+ end
88
+
89
+ # Enqueues the job using the ActiveJob.
90
+ #
91
+ # @param [Hash] config The job configuration
92
+ def self.enqueue_with_active_job(config)
93
+ options = {
94
+ queue: config['queue']
95
+ }.keep_if { |_, v| !v.nil? }
96
+
97
+ initialize_active_job(config['class'], config['args']).enqueue(options)
98
+ end
99
+
100
+ # Removes the hash values associated to the rufus metadata keys.
101
+ #
102
+ # @param [Hash] config The job configuration
103
+ #
104
+ # @return [Hash] the sanitized job config
105
+ def self.sanitize_job_config(config)
106
+ config.reject { |k, _| RUFUS_METADATA_KEYS.include?(k) }
107
+ end
108
+
109
+ # Creates a new instance of rufus scheduler.
110
+ #
111
+ # @return [Rufus::Scheduler] the scheduler instance
112
+ def self.new_rufus_scheduler(options = {})
113
+ Rufus::Scheduler.new(options).tap do |scheduler|
114
+ scheduler.define_singleton_method(:on_post_trigger) do |job, triggered_time|
115
+ if (job_name = job.tags[0])
116
+ SidekiqScheduler::Utils.update_job_last_time(job_name, triggered_time)
117
+ SidekiqScheduler::Utils.update_job_next_time(job_name, job.next_time)
118
+ end
119
+ end
120
+ end
121
+ end
122
+
123
+ # Pushes job's next time execution
124
+ #
125
+ # @param [String] name The job's name
126
+ # @param [Time] next_time The job's next time execution
127
+ def self.update_job_next_time(name, next_time)
128
+ if next_time
129
+ SidekiqScheduler::RedisManager.set_job_next_time(name, next_time)
130
+ else
131
+ SidekiqScheduler::RedisManager.remove_job_next_time(name)
132
+ end
133
+ end
134
+
135
+ # Pushes job's last execution time
136
+ #
137
+ # @param [String] name The job's name
138
+ # @param [Time] last_time The job's last execution time
139
+ def self.update_job_last_time(name, last_time)
140
+ SidekiqScheduler::RedisManager.set_job_last_time(name, last_time) if last_time
141
+ end
142
+ end
143
+ end
@@ -0,0 +1,3 @@
1
+ module SidekiqScheduler
2
+ VERSION = '0.0.1'
3
+ end
@@ -0,0 +1,98 @@
1
+ require 'sidekiq-scheduler'
2
+
3
+ require_relative 'job_presenter'
4
+
5
+ module SidekiqScheduler
6
+ # Hook into *Sidekiq::Web* app which adds a new '/recurring-jobs' page
7
+
8
+ module Web
9
+ VIEW_PATH = File.expand_path('../../../web/views', __FILE__)
10
+
11
+ def self.registered(app)
12
+ app.get '/recurring-jobs' do
13
+ @presented_jobs = JobPresenter.build_collection(Sidekiq.schedule!)
14
+
15
+ erb File.read(File.join(VIEW_PATH, 'recurring_jobs.erb'))
16
+ end
17
+
18
+ app.post '/recurring-jobs/:name/enqueue' do
19
+ schedule = Sidekiq.get_schedule(params[:name])
20
+ SidekiqScheduler::Scheduler.instance.enqueue_job(schedule)
21
+ redirect "#{root_path}recurring-jobs"
22
+ end
23
+
24
+ app.post '/recurring-jobs/:name/toggle' do
25
+ Sidekiq.reload_schedule!
26
+
27
+ SidekiqScheduler::Scheduler.instance.toggle_job_enabled(params[:name])
28
+ redirect "#{root_path}recurring-jobs"
29
+ end
30
+
31
+ app.post '/recurring-jobs/:name/remove' do
32
+ Sidekiq.reload_schedule!
33
+
34
+ Sidekiq.remove_schedule(params[:name])
35
+ redirect "#{root_path}recurring-jobs"
36
+ end
37
+
38
+ app.post '/recurring-jobs/toggle-all' do
39
+ SidekiqScheduler::Scheduler.instance.toggle_all_jobs(params[:action] == 'enable')
40
+ redirect "#{root_path}recurring-jobs"
41
+ end
42
+
43
+ # New actions
44
+ app.post '/recurring-jobs/:name/destroy' do
45
+ Sidekiq.reload_schedule!
46
+
47
+ dynamo_clas_name = ENV.fetch('SIDEKIQ_SCHEDUER_DYNAMOID_CLASS', 'ScheduleRule')
48
+ klass = dynamo_clas_name.constantize
49
+ sr = klass.where(name: params[:name]).first
50
+ if sr.present?
51
+ sr.destroy
52
+ else
53
+ Sidekiq.remove_schedule(params[:name])
54
+ end
55
+
56
+ redirect "#{root_path}recurring-jobs"
57
+ end
58
+
59
+ app.post '/recurring-jobs/:name/edit' do
60
+ @title = 'Recurring Job Update'
61
+ @form_action = "#{root_path}recurring-jobs/#{ERB::Util.url_encode(params[:name])}/update"
62
+ @existing_rule = true
63
+ @name = params[:name]
64
+ @config = Sidekiq.get_schedule(params[:name])
65
+ erb File.read(File.join(VIEW_PATH, 'recurring_job.erb'))
66
+ end
67
+
68
+ app.post '/recurring-jobs/new' do
69
+ @title = 'New Recurring Job'
70
+ @existing_rule = false
71
+ @form_action = "#{root_path}recurring-jobs/create"
72
+ @name = ''
73
+ @config = { queue: 'default', enabled: false }
74
+ erb File.read(File.join(VIEW_PATH, 'recurring_job.erb'))
75
+ end
76
+
77
+ app.post '/recurring-jobs/:name/update' do
78
+ dynamo_clas_name = ENV.fetch('SIDEKIQ_SCHEDUER_DYNAMOID_CLASS', 'ScheduleRule')
79
+ klass = dynamo_clas_name.constantize
80
+ klass.update_or_create name: params[:name], config: JSON.parse(params[:config])
81
+
82
+ Sidekiq.reload_schedule!
83
+ redirect "#{root_path}recurring-jobs"
84
+ end
85
+
86
+ app.post '/recurring-jobs/create' do
87
+ dynamo_clas_name = ENV.fetch('SIDEKIQ_SCHEDUER_DYNAMOID_CLASS', 'ScheduleRule')
88
+ klass = dynamo_clas_name.constantize
89
+ klass.update_or_create name: params[:name], config: JSON.parse(params[:config])
90
+
91
+ Sidekiq.reload_schedule!
92
+ redirect "#{root_path}recurring-jobs"
93
+ end
94
+ end
95
+ end
96
+ end
97
+
98
+ require_relative 'extensions/web'