dynamodb-sidekiq-scheduler 0.0.1

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.
@@ -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'