alarmable 1.4.0 → 1.5.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.
- checksums.yaml +4 -4
- data/CHANGELOG.md +9 -1
- data/alarmable.gemspec +1 -0
- data/lib/alarmable/version.rb +1 -1
- data/lib/alarmable.rb +214 -2
- metadata +16 -3
- data/lib/alarmable/concern.rb +0 -203
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 577dcfa9cb1b37ba1ee9a4025ce045d19f36ae61d371270049310e696c5ee32c
|
4
|
+
data.tar.gz: 38bccc14a3f155e50d1397a23a3582b7546c0995785b47da3dd8598e83743c4c
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: '087f42cdcbe1e7fcd64b88ef7f8c7ec60607296cc071861974692b3cafbefbfd22943d4432962a6e78dfb7d170d06ae0fae5e32f23d2b4bb082c14b75b1b6049'
|
7
|
+
data.tar.gz: 36c38cacac483c1a242e2f21fd033d0bdb6e226fbcd452d4596d3aae55c7550340c11cfb7ba643daf43699796f041f6a4bacd0a8c4f5bc954537ea8dbfb0069c
|
data/CHANGELOG.md
CHANGED
@@ -2,9 +2,17 @@
|
|
2
2
|
|
3
3
|
* TODO: Replace this bullet point with an actual description of a change.
|
4
4
|
|
5
|
+
### 1.5.1 (17 January 2025)
|
6
|
+
|
7
|
+
* Added the logger dependency (#15)
|
8
|
+
|
9
|
+
### 1.5.0 (14 January 2025)
|
10
|
+
|
11
|
+
* Switched to Zeitwerk as autoloader (#14)
|
12
|
+
|
5
13
|
### 1.4.0 (12 January 2025)
|
6
14
|
|
7
|
-
*
|
15
|
+
* Just a retag of 1.3.0
|
8
16
|
|
9
17
|
### 1.3.0 (3 January 2025)
|
10
18
|
|
data/alarmable.gemspec
CHANGED
data/lib/alarmable/version.rb
CHANGED
data/lib/alarmable.rb
CHANGED
@@ -1,10 +1,222 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
2
|
|
3
|
+
require 'zeitwerk'
|
4
|
+
require 'logger'
|
3
5
|
require 'active_support'
|
4
6
|
require 'active_record'
|
5
7
|
require 'active_job'
|
6
8
|
require 'active_job/cancel'
|
7
9
|
require 'hashdiff'
|
8
10
|
|
9
|
-
|
10
|
-
|
11
|
+
# A reusable alarm extension to Active Record models. It adds support for the
|
12
|
+
# maintenance of Active Job's (create, update (cancel)) which are schedules
|
13
|
+
# for the given alarms. We check for changes on the alarms hash and perform
|
14
|
+
# updates accordingly.
|
15
|
+
#
|
16
|
+
# This concern requires the persistence (and availability) of two properties.
|
17
|
+
#
|
18
|
+
# * The first is the JSONB array which holds the alarms. (+alarms+)
|
19
|
+
# * The seconds is the JSONB array which holds the ids of
|
20
|
+
# scheduled alarm jobs. (+alarm_jobs+)
|
21
|
+
#
|
22
|
+
# rails generate migration AddAlarmsAndAlarmJobsToEntity \
|
23
|
+
# alarms:jsonb alarm_jobs:jsonb
|
24
|
+
#
|
25
|
+
# Furthermore a Active Record model which uses this concern must define the
|
26
|
+
# Active Job class which will be scheduled. (+alarm_job+) The user must also
|
27
|
+
# define the base date property of the owning side.
|
28
|
+
# (+alarm_base_date_property+) This base date is mandatory to calculate the
|
29
|
+
# correct alarm date/time. When the base date is not set (+nil+) no new
|
30
|
+
# notification job will be enqueued. When the base date is unset on an
|
31
|
+
# update, the previously enqueued job will be canceled.
|
32
|
+
#
|
33
|
+
# The alarms hash needs to be an array in the following format:
|
34
|
+
#
|
35
|
+
# [
|
36
|
+
# {
|
37
|
+
# "channel": "email", # email, push, web_notification, etc..
|
38
|
+
# "before_minutes": 15 # start_at - before_minutes, >= 1
|
39
|
+
# }
|
40
|
+
# ]
|
41
|
+
#
|
42
|
+
# The given alarm job class will be scheduled with the following two
|
43
|
+
# arguments.
|
44
|
+
#
|
45
|
+
# * id - The class/instance id of the record which owns the alarm
|
46
|
+
# * alarm - The alarm hash itself (see the format above)
|
47
|
+
#
|
48
|
+
# A suitable alarm job perform method should look like this:
|
49
|
+
#
|
50
|
+
# # @param id [String] The entity id
|
51
|
+
# # @param alarm [Hash] The alarm object
|
52
|
+
# def perform(id, alarm)
|
53
|
+
# # Do something special for +alarm.channel+ ..
|
54
|
+
# end
|
55
|
+
module Alarmable
|
56
|
+
# Setup a Zeitwerk autoloader instance and configure it
|
57
|
+
loader = Zeitwerk::Loader.for_gem
|
58
|
+
|
59
|
+
# Finish the auto loader configuration
|
60
|
+
loader.setup
|
61
|
+
|
62
|
+
# Make sure to eager load all constants
|
63
|
+
loader.eager_load
|
64
|
+
|
65
|
+
extend ActiveSupport::Concern
|
66
|
+
|
67
|
+
class_methods do
|
68
|
+
# Getter/Setter
|
69
|
+
#
|
70
|
+
# :reek:Attribute because thats what this thing is about
|
71
|
+
attr_accessor :alarm_job, :alarm_base_date_property
|
72
|
+
end
|
73
|
+
|
74
|
+
# rubocop:disable Metrics/BlockLength because Active Support like it
|
75
|
+
included do
|
76
|
+
# Hooks
|
77
|
+
after_initialize :validate_alarm_settings, :alarm_defaults
|
78
|
+
|
79
|
+
# Here comes a little cheat sheet when and what action is performed
|
80
|
+
# on the alarm jobs.
|
81
|
+
#
|
82
|
+
# create | [ time check, reschedule]
|
83
|
+
# update | dirty check, [cancel job, time check, reschedule]
|
84
|
+
# destroy | [cancel job ]
|
85
|
+
after_create :reschedule_alarm_jobs
|
86
|
+
before_update :alarms_update_callback
|
87
|
+
before_destroy :alarms_destroy_callback
|
88
|
+
|
89
|
+
# Getter for the alarm job class.
|
90
|
+
#
|
91
|
+
# @return [Class] The alarm job class
|
92
|
+
def alarm_job
|
93
|
+
self.class.alarm_job
|
94
|
+
end
|
95
|
+
|
96
|
+
# Getter for the alarm base date property.
|
97
|
+
#
|
98
|
+
# @return [Symbol] The user defined base date property
|
99
|
+
def alarm_base_date_property
|
100
|
+
self.class.alarm_base_date_property
|
101
|
+
end
|
102
|
+
|
103
|
+
# Set some defaults on the relevant alarm properties.
|
104
|
+
def alarm_defaults
|
105
|
+
self.alarms ||= []
|
106
|
+
self.alarm_jobs ||= {}
|
107
|
+
end
|
108
|
+
|
109
|
+
# Validate the presence of the +alarm_job+ property and the accessibility
|
110
|
+
# of the specified class. Also validate the +alarm_base_date_property+
|
111
|
+
# setting.
|
112
|
+
#
|
113
|
+
# rubocop:disable Style/GuardClause because its fine like this
|
114
|
+
# :reek:NilCheck because we validate concern usage
|
115
|
+
def validate_alarm_settings
|
116
|
+
raise 'Alarmable +alarm_job+ is not configured' if alarm_job.nil?
|
117
|
+
unless alarm_job.is_a? Class
|
118
|
+
raise 'Alarmable +alarm_job+ is not instantiable'
|
119
|
+
end
|
120
|
+
if alarm_base_date_property.nil?
|
121
|
+
raise 'Alarmable +alarm_base_date_property+ is not configured'
|
122
|
+
end
|
123
|
+
unless has_attribute? alarm_base_date_property
|
124
|
+
raise 'Alarmable +alarm_base_date_property+ is not usable'
|
125
|
+
end
|
126
|
+
end
|
127
|
+
# rubocop:enable Style/GuardClause
|
128
|
+
|
129
|
+
# Generate a unique and recalculatable identifier for a given alarm
|
130
|
+
# object. We build a hash of the primary keys (before_minutes and
|
131
|
+
# channel) to achive this. Afterwards, this alarm id is used to
|
132
|
+
# reference dedicated scheduled jobs and track their updates. (Or cancel
|
133
|
+
# them accordingly)
|
134
|
+
#
|
135
|
+
# @param channel [String] The alarm channel
|
136
|
+
# @param before_minutes [Integer] The minutes before the alarm starts
|
137
|
+
# @return [String] The unique alarm id
|
138
|
+
#
|
139
|
+
# :reek:UtilityFunction because its a utility, for sure
|
140
|
+
def alarm_id(channel, before_minutes)
|
141
|
+
(Digest::MD5.new << "#{channel}#{before_minutes}").to_s
|
142
|
+
end
|
143
|
+
|
144
|
+
# Schedule a new Active Job for the alarm notification. This method takes
|
145
|
+
# care of the notification time (+date) and will not touch anything when
|
146
|
+
# the desired time already passed. It cancels the correct job for the
|
147
|
+
# given combination, when it is present. In the end it schedules a new
|
148
|
+
# (renewed) job for the given alarm settings.
|
149
|
+
#
|
150
|
+
# @param alarm [Hash] The alarm object
|
151
|
+
# @return [Object] The new alarm_jobs instance (partial)
|
152
|
+
# Example: { "alarm id": "job id" }
|
153
|
+
#
|
154
|
+
# rubocop:disable Metrics/AbcSize because its already broken down
|
155
|
+
# :reek:TooManyStatements because see above
|
156
|
+
# :reek:NilCheck because we dont want to cancel 'nil' job id
|
157
|
+
# :reek:DuplicateMethodCall because hash access is fast
|
158
|
+
def reschedule_alarm_job(alarm)
|
159
|
+
# Symbolize the hash keys (just to be sure).
|
160
|
+
alarm = alarm.symbolize_keys
|
161
|
+
|
162
|
+
# Calculate the alarm id for job canceling and cancel a found job.
|
163
|
+
id = alarm_id(alarm[:channel], alarm[:before_minutes])
|
164
|
+
previous_job_id = alarm_jobs.try(:[], id)
|
165
|
+
alarm_job.cancel(previous_job_id) unless previous_job_id.nil?
|
166
|
+
|
167
|
+
base_date = self[alarm_base_date_property]
|
168
|
+
|
169
|
+
# When the base date is not set, we schedule not a new notification job.
|
170
|
+
return {} if base_date.nil?
|
171
|
+
|
172
|
+
# Calculate the time when the job should run.
|
173
|
+
notify_at = base_date - alarm[:before_minutes].minutes
|
174
|
+
|
175
|
+
# Do nothing when the notification date already passed.
|
176
|
+
return {} if Time.current >= notify_at
|
177
|
+
|
178
|
+
# Put a new job to the queue with the new (current) job execution date.
|
179
|
+
job = alarm_job.set(wait_until: notify_at).perform_later(self.id, alarm)
|
180
|
+
|
181
|
+
# Construct a new alarm_jobs partial instance for this job
|
182
|
+
{ id => job.job_id }
|
183
|
+
end
|
184
|
+
# rubocop:enable Metrics/AbcSize
|
185
|
+
|
186
|
+
# Initiate a reschedule for each alarm in the alarm settings and
|
187
|
+
# cancel all left-overs.
|
188
|
+
#
|
189
|
+
# :reek:TooManyStatements because its already broken down
|
190
|
+
def reschedule_alarm_jobs
|
191
|
+
# Perform the reschedule of all the current alarms.
|
192
|
+
new_alarm_jobs = alarms.each_with_object({}) do |alarm, memo|
|
193
|
+
memo.merge!(reschedule_alarm_job(alarm))
|
194
|
+
end
|
195
|
+
|
196
|
+
# Detect the differences from the original alarm_jobs hash to the new
|
197
|
+
# built (by partials) alarm_jobs hash. The jobs from negative
|
198
|
+
# differences must be canceled.
|
199
|
+
diff = Hashdiff.diff(alarm_jobs, new_alarm_jobs)
|
200
|
+
|
201
|
+
diff.select { |prop| prop.first == '-' }.each do |prop|
|
202
|
+
alarm_job.cancel(prop.last)
|
203
|
+
end
|
204
|
+
|
205
|
+
# Update the alarm_jobs reference pool with our fresh hash. Bypass the
|
206
|
+
# regular validation and callbacks here, this is required to not stuck
|
207
|
+
# in endless create-update loops.
|
208
|
+
update_columns(alarm_jobs: new_alarm_jobs)
|
209
|
+
end
|
210
|
+
|
211
|
+
# Reschedule only on updates when the alarm settings are changed.
|
212
|
+
def alarms_update_callback
|
213
|
+
reschedule_alarm_jobs if alarms_changed?
|
214
|
+
end
|
215
|
+
|
216
|
+
# Cancel all alarm notification jobs on parent destroy.
|
217
|
+
def alarms_destroy_callback
|
218
|
+
alarm_jobs.each_value { |job_id| alarm_job.cancel(job_id) }
|
219
|
+
end
|
220
|
+
end
|
221
|
+
# rubocop:enable Metrics/BlockLength
|
222
|
+
end
|
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: alarmable
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 1.
|
4
|
+
version: 1.5.1
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Hermann Mayer
|
8
8
|
autorequire:
|
9
9
|
bindir: exe
|
10
10
|
cert_chain: []
|
11
|
-
date: 2025-01-
|
11
|
+
date: 2025-01-17 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: activejob
|
@@ -80,6 +80,20 @@ dependencies:
|
|
80
80
|
- - "~>"
|
81
81
|
- !ruby/object:Gem::Version
|
82
82
|
version: '1.0'
|
83
|
+
- !ruby/object:Gem::Dependency
|
84
|
+
name: zeitwerk
|
85
|
+
requirement: !ruby/object:Gem::Requirement
|
86
|
+
requirements:
|
87
|
+
- - "~>"
|
88
|
+
- !ruby/object:Gem::Version
|
89
|
+
version: '2.6'
|
90
|
+
type: :runtime
|
91
|
+
prerelease: false
|
92
|
+
version_requirements: !ruby/object:Gem::Requirement
|
93
|
+
requirements:
|
94
|
+
- - "~>"
|
95
|
+
- !ruby/object:Gem::Version
|
96
|
+
version: '2.6'
|
83
97
|
description: This is a reusable alarm concern for Active Recordmodels. It adds support
|
84
98
|
for the automatic maintenanceof Active Job's which are scheduled for the givenalarms.
|
85
99
|
email:
|
@@ -118,7 +132,6 @@ files:
|
|
118
132
|
- gemfiles/rails_6.1.gemfile
|
119
133
|
- gemfiles/rails_7.1.gemfile
|
120
134
|
- lib/alarmable.rb
|
121
|
-
- lib/alarmable/concern.rb
|
122
135
|
- lib/alarmable/version.rb
|
123
136
|
homepage:
|
124
137
|
licenses:
|
data/lib/alarmable/concern.rb
DELETED
@@ -1,203 +0,0 @@
|
|
1
|
-
# frozen_string_literal: true
|
2
|
-
|
3
|
-
# A reusable alarm extension to Active Record models. It adds support for the
|
4
|
-
# maintenance of Active Job's (create, update (cancel)) which are schedules for
|
5
|
-
# the given alarms. We check for changes on the alarms hash and perform
|
6
|
-
# updates accordingly.
|
7
|
-
#
|
8
|
-
# This concern requires the persistence (and availability) of two properties.
|
9
|
-
#
|
10
|
-
# * The first is the JSONB array which holds the alarms. (+alarms+)
|
11
|
-
# * The seconds is the JSONB array which holds the ids of
|
12
|
-
# scheduled alarm jobs. (+alarm_jobs+)
|
13
|
-
#
|
14
|
-
# rails generate migration AddAlarmsAndAlarmJobsToEntity \
|
15
|
-
# alarms:jsonb alarm_jobs:jsonb
|
16
|
-
#
|
17
|
-
# Furthermore a Active Record model which uses this concern must define the
|
18
|
-
# Active Job class which will be scheduled. (+alarm_job+) The user must also
|
19
|
-
# define the base date property of the owning side.
|
20
|
-
# (+alarm_base_date_property+) This base date is mandatory to calculate the
|
21
|
-
# correct alarm date/time. When the base date is not set (+nil+) no new
|
22
|
-
# notification job will be enqueued. When the base date is unset on an update,
|
23
|
-
# the previously enqueued job will be canceled.
|
24
|
-
#
|
25
|
-
# The alarms hash needs to be an array in the following format:
|
26
|
-
#
|
27
|
-
# [
|
28
|
-
# {
|
29
|
-
# "channel": "email", # email, push, web_notification, etc..
|
30
|
-
# "before_minutes": 15 # start_at - before_minutes, >= 1
|
31
|
-
# }
|
32
|
-
# ]
|
33
|
-
#
|
34
|
-
# The given alarm job class will be scheduled with the following two arguments.
|
35
|
-
#
|
36
|
-
# * id - The class/instance id of the record which owns the alarm
|
37
|
-
# * alarm - The alarm hash itself (see the format above)
|
38
|
-
#
|
39
|
-
# A suitable alarm job perform method should look like this:
|
40
|
-
#
|
41
|
-
# # @param id [String] The entity id
|
42
|
-
# # @param alarm [Hash] The alarm object
|
43
|
-
# def perform(id, alarm)
|
44
|
-
# # Do something special for +alarm.channel+ ..
|
45
|
-
# end
|
46
|
-
module Alarmable
|
47
|
-
extend ActiveSupport::Concern
|
48
|
-
|
49
|
-
class_methods do
|
50
|
-
# Getter/Setter
|
51
|
-
#
|
52
|
-
# :reek:Attribute because thats what this thing is about
|
53
|
-
attr_accessor :alarm_job, :alarm_base_date_property
|
54
|
-
end
|
55
|
-
|
56
|
-
# rubocop:disable Metrics/BlockLength because Active Support like it
|
57
|
-
included do
|
58
|
-
# Hooks
|
59
|
-
after_initialize :validate_alarm_settings, :alarm_defaults
|
60
|
-
|
61
|
-
# Here comes a little cheat sheet when and what action is performed
|
62
|
-
# on the alarm jobs.
|
63
|
-
#
|
64
|
-
# create | [ time check, reschedule]
|
65
|
-
# update | dirty check, [cancel job, time check, reschedule]
|
66
|
-
# destroy | [cancel job ]
|
67
|
-
after_create :reschedule_alarm_jobs
|
68
|
-
before_update :alarms_update_callback
|
69
|
-
before_destroy :alarms_destroy_callback
|
70
|
-
|
71
|
-
# Getter for the alarm job class.
|
72
|
-
#
|
73
|
-
# @return [Class] The alarm job class
|
74
|
-
def alarm_job
|
75
|
-
self.class.alarm_job
|
76
|
-
end
|
77
|
-
|
78
|
-
# Getter for the alarm base date property.
|
79
|
-
#
|
80
|
-
# @return [Symbol] The user defined base date property
|
81
|
-
def alarm_base_date_property
|
82
|
-
self.class.alarm_base_date_property
|
83
|
-
end
|
84
|
-
|
85
|
-
# Set some defaults on the relevant alarm properties.
|
86
|
-
def alarm_defaults
|
87
|
-
self.alarms ||= []
|
88
|
-
self.alarm_jobs ||= {}
|
89
|
-
end
|
90
|
-
|
91
|
-
# Validate the presence of the +alarm_job+ property and the accessibility
|
92
|
-
# of the specified class. Also validate the +alarm_base_date_property+
|
93
|
-
# setting.
|
94
|
-
#
|
95
|
-
# rubocop:disable Style/GuardClause because its fine like this
|
96
|
-
# :reek:NilCheck because we validate concern usage
|
97
|
-
def validate_alarm_settings
|
98
|
-
raise 'Alarmable +alarm_job+ is not configured' if alarm_job.nil?
|
99
|
-
unless alarm_job.is_a? Class
|
100
|
-
raise 'Alarmable +alarm_job+ is not instantiable'
|
101
|
-
end
|
102
|
-
if alarm_base_date_property.nil?
|
103
|
-
raise 'Alarmable +alarm_base_date_property+ is not configured'
|
104
|
-
end
|
105
|
-
unless has_attribute? alarm_base_date_property
|
106
|
-
raise 'Alarmable +alarm_base_date_property+ is not usable'
|
107
|
-
end
|
108
|
-
end
|
109
|
-
# rubocop:enable Style/GuardClause
|
110
|
-
|
111
|
-
# Generate a unique and recalculatable identifier for a given alarm object.
|
112
|
-
# We build a hash of the primary keys (before_minutes and channel) to
|
113
|
-
# achive this. Afterwards, this alarm id is used to reference dedicated
|
114
|
-
# scheduled jobs and track their updates. (Or cancel them accordingly)
|
115
|
-
#
|
116
|
-
# @param channel [String] The alarm channel
|
117
|
-
# @param before_minutes [Integer] The minutes before the alarm starts
|
118
|
-
# @return [String] The unique alarm id
|
119
|
-
#
|
120
|
-
# :reek:UtilityFunction because its a utility, for sure
|
121
|
-
def alarm_id(channel, before_minutes)
|
122
|
-
(Digest::MD5.new << "#{channel}#{before_minutes}").to_s
|
123
|
-
end
|
124
|
-
|
125
|
-
# Schedule a new Active Job for the alarm notification. This method takes
|
126
|
-
# care of the notification time (+date) and will not touch anything when
|
127
|
-
# the desired time already passed. It cancels the correct job for the
|
128
|
-
# given combination, when it is present. In the end it schedules a new
|
129
|
-
# (renewed) job for the given alarm settings.
|
130
|
-
#
|
131
|
-
# @param alarm [Hash] The alarm object
|
132
|
-
# @return [Object] The new alarm_jobs instance (partial)
|
133
|
-
# Example: { "alarm id": "job id" }
|
134
|
-
#
|
135
|
-
# rubocop:disable Metrics/AbcSize because its already broken down
|
136
|
-
# :reek:TooManyStatements because see above
|
137
|
-
# :reek:NilCheck because we dont want to cancel 'nil' job id
|
138
|
-
# :reek:DuplicateMethodCall because hash access is fast
|
139
|
-
def reschedule_alarm_job(alarm)
|
140
|
-
# Symbolize the hash keys (just to be sure).
|
141
|
-
alarm = alarm.symbolize_keys
|
142
|
-
|
143
|
-
# Calculate the alarm id for job canceling and cancel a found job.
|
144
|
-
id = alarm_id(alarm[:channel], alarm[:before_minutes])
|
145
|
-
previous_job_id = alarm_jobs.try(:[], id)
|
146
|
-
alarm_job.cancel(previous_job_id) unless previous_job_id.nil?
|
147
|
-
|
148
|
-
base_date = self[alarm_base_date_property]
|
149
|
-
|
150
|
-
# When the base date is not set, we schedule not a new notification job.
|
151
|
-
return {} if base_date.nil?
|
152
|
-
|
153
|
-
# Calculate the time when the job should run.
|
154
|
-
notify_at = base_date - alarm[:before_minutes].minutes
|
155
|
-
|
156
|
-
# Do nothing when the notification date already passed.
|
157
|
-
return {} if Time.current >= notify_at
|
158
|
-
|
159
|
-
# Put a new job to the queue with the new (current) job execution date.
|
160
|
-
job = alarm_job.set(wait_until: notify_at).perform_later(self.id, alarm)
|
161
|
-
|
162
|
-
# Construct a new alarm_jobs partial instance for this job
|
163
|
-
{ id => job.job_id }
|
164
|
-
end
|
165
|
-
# rubocop:enable Metrics/AbcSize
|
166
|
-
|
167
|
-
# Initiate a reschedule for each alarm in the alarm settings and
|
168
|
-
# cancel all left-overs.
|
169
|
-
#
|
170
|
-
# :reek:TooManyStatements because its already broken down
|
171
|
-
def reschedule_alarm_jobs
|
172
|
-
# Perform the reschedule of all the current alarms.
|
173
|
-
new_alarm_jobs = alarms.each_with_object({}) do |alarm, memo|
|
174
|
-
memo.merge!(reschedule_alarm_job(alarm))
|
175
|
-
end
|
176
|
-
|
177
|
-
# Detect the differences from the original alarm_jobs hash to the new
|
178
|
-
# built (by partials) alarm_jobs hash. The jobs from negative differences
|
179
|
-
# must be canceled.
|
180
|
-
diff = Hashdiff.diff(alarm_jobs, new_alarm_jobs)
|
181
|
-
|
182
|
-
diff.select { |prop| prop.first == '-' }.each do |prop|
|
183
|
-
alarm_job.cancel(prop.last)
|
184
|
-
end
|
185
|
-
|
186
|
-
# Update the alarm_jobs reference pool with our fresh hash. Bypass the
|
187
|
-
# regular validation and callbacks here, this is required to not stuck in
|
188
|
-
# endless create-update loops.
|
189
|
-
update_columns(alarm_jobs: new_alarm_jobs)
|
190
|
-
end
|
191
|
-
|
192
|
-
# Reschedule only on updates when the alarm settings are changed.
|
193
|
-
def alarms_update_callback
|
194
|
-
reschedule_alarm_jobs if alarms_changed?
|
195
|
-
end
|
196
|
-
|
197
|
-
# Cancel all alarm notification jobs on parent destroy.
|
198
|
-
def alarms_destroy_callback
|
199
|
-
alarm_jobs.each_value { |job_id| alarm_job.cancel(job_id) }
|
200
|
-
end
|
201
|
-
end
|
202
|
-
# rubocop:enable Metrics/BlockLength
|
203
|
-
end
|