Detect down & up

master
aeris 2021-01-02 16:39:12 +01:00
parent 36ec984c33
commit d427add86f
13 changed files with 165 additions and 111 deletions

3
.env.test 100644
View File

@ -0,0 +1,3 @@
EMAIL_FROM = monit_from@example.org
EMAIL_TO = monit_to@example.org
EMAIL_REPLY_TO = noreply@example.org

View File

@ -43,6 +43,7 @@ group :test do
gem 'rspec-rails'
gem 'rspec-json_expectations'
gem 'webmock'
gem 'timecop'
end
gem 'tzinfo-data', platforms: %i[mingw mswin x64_mingw jruby]

View File

@ -1,56 +1,56 @@
GEM
remote: https://rubygems.org/
specs:
actioncable (6.0.3.3)
actionpack (= 6.0.3.3)
actioncable (6.0.3.4)
actionpack (= 6.0.3.4)
nio4r (~> 2.0)
websocket-driver (>= 0.6.1)
actionmailbox (6.0.3.3)
actionpack (= 6.0.3.3)
activejob (= 6.0.3.3)
activerecord (= 6.0.3.3)
activestorage (= 6.0.3.3)
activesupport (= 6.0.3.3)
actionmailbox (6.0.3.4)
actionpack (= 6.0.3.4)
activejob (= 6.0.3.4)
activerecord (= 6.0.3.4)
activestorage (= 6.0.3.4)
activesupport (= 6.0.3.4)
mail (>= 2.7.1)
actionmailer (6.0.3.3)
actionpack (= 6.0.3.3)
actionview (= 6.0.3.3)
activejob (= 6.0.3.3)
actionmailer (6.0.3.4)
actionpack (= 6.0.3.4)
actionview (= 6.0.3.4)
activejob (= 6.0.3.4)
mail (~> 2.5, >= 2.5.4)
rails-dom-testing (~> 2.0)
actionpack (6.0.3.3)
actionview (= 6.0.3.3)
activesupport (= 6.0.3.3)
actionpack (6.0.3.4)
actionview (= 6.0.3.4)
activesupport (= 6.0.3.4)
rack (~> 2.0, >= 2.0.8)
rack-test (>= 0.6.3)
rails-dom-testing (~> 2.0)
rails-html-sanitizer (~> 1.0, >= 1.2.0)
actiontext (6.0.3.3)
actionpack (= 6.0.3.3)
activerecord (= 6.0.3.3)
activestorage (= 6.0.3.3)
activesupport (= 6.0.3.3)
actiontext (6.0.3.4)
actionpack (= 6.0.3.4)
activerecord (= 6.0.3.4)
activestorage (= 6.0.3.4)
activesupport (= 6.0.3.4)
nokogiri (>= 1.8.5)
actionview (6.0.3.3)
activesupport (= 6.0.3.3)
actionview (6.0.3.4)
activesupport (= 6.0.3.4)
builder (~> 3.1)
erubi (~> 1.4)
rails-dom-testing (~> 2.0)
rails-html-sanitizer (~> 1.1, >= 1.2.0)
activejob (6.0.3.3)
activesupport (= 6.0.3.3)
activejob (6.0.3.4)
activesupport (= 6.0.3.4)
globalid (>= 0.3.6)
activemodel (6.0.3.3)
activesupport (= 6.0.3.3)
activerecord (6.0.3.3)
activemodel (= 6.0.3.3)
activesupport (= 6.0.3.3)
activestorage (6.0.3.3)
actionpack (= 6.0.3.3)
activejob (= 6.0.3.3)
activerecord (= 6.0.3.3)
activemodel (6.0.3.4)
activesupport (= 6.0.3.4)
activerecord (6.0.3.4)
activemodel (= 6.0.3.4)
activesupport (= 6.0.3.4)
activestorage (6.0.3.4)
actionpack (= 6.0.3.4)
activejob (= 6.0.3.4)
activerecord (= 6.0.3.4)
marcel (~> 0.3.1)
activesupport (6.0.3.3)
activesupport (6.0.3.4)
concurrent-ruby (~> 1.0, >= 1.0.2)
i18n (>= 0.7, < 2)
minitest (~> 5.1)
@ -59,23 +59,24 @@ GEM
addressable (2.7.0)
public_suffix (>= 2.0.2, < 5.0)
amazing_print (1.2.2)
better_errors (2.8.1)
better_errors (2.9.1)
coderay (>= 1.0.0)
erubi (>= 1.0.0)
rack (>= 0.9.0)
bindex (0.8.1)
binding_of_caller (0.8.0)
binding_of_caller (1.0.0)
debug_inspector (>= 0.0.1)
bootsnap (1.4.8)
bootsnap (1.5.1)
msgpack (~> 1.0)
builder (3.2.4)
byebug (11.1.3)
coderay (1.1.3)
colorize (0.8.1)
concurrent-ruby (1.1.7)
crack (0.4.4)
crack (0.4.5)
rexml
crass (1.0.6)
debug_inspector (0.0.3)
debug_inspector (1.0.0)
diff-lcs (1.4.4)
domain_name (0.5.20190701)
unf (>= 0.0.5, < 1.0.0)
@ -83,15 +84,18 @@ GEM
dotenv-rails (2.7.6)
dotenv (= 2.7.6)
railties (>= 3.2)
em-websocket (0.5.1)
em-websocket (0.5.2)
eventmachine (>= 0.12.9)
http_parser.rb (~> 0.6.0)
erubi (1.9.0)
erubi (1.10.0)
eventmachine (1.2.7)
execjs (2.7.0)
faraday (1.0.1)
faraday (1.3.0)
faraday-net_http (~> 1.0)
multipart-post (>= 1.2, < 3)
ffi (1.13.1)
ruby2_keywords
faraday-net_http (1.0.0)
ffi (1.14.2)
ffi-compiler (1.0.1)
ffi (>= 1.0.0)
rake
@ -125,21 +129,20 @@ GEM
http-cookie (1.0.3)
domain_name (~> 0.5)
http-form_data (2.3.0)
http-parser (1.2.1)
ffi-compiler (>= 1.0, < 2.0)
http-parser (1.2.2)
ffi-compiler
http_parser.rb (0.6.0)
httplog (1.4.3)
rack (>= 1.0)
rainbow (>= 2.0.0)
i18n (1.8.5)
concurrent-ruby (~> 1.0)
js-routes (1.4.9)
js-routes (1.4.13)
railties (>= 4)
sprockets-rails
listen (3.2.1)
listen (3.4.0)
rb-fsevent (~> 0.10, >= 0.10.3)
rb-inotify (~> 0.9, >= 0.9.10)
loofah (2.7.0)
loofah (2.8.0)
crass (~> 1.0.2)
nokogiri (>= 1.5.9)
lumberjack (1.2.8)
@ -174,7 +177,7 @@ GEM
pry-rails (0.3.9)
pry (>= 0.10.4)
public_suffix (4.0.6)
puma (5.0.0)
puma (5.1.1)
nio4r (~> 2.0)
rack (2.2.3)
rack-livereload (0.3.17)
@ -183,57 +186,59 @@ GEM
rack
rack-test (1.1.0)
rack (>= 1.0, < 3)
rails (6.0.3.3)
actioncable (= 6.0.3.3)
actionmailbox (= 6.0.3.3)
actionmailer (= 6.0.3.3)
actionpack (= 6.0.3.3)
actiontext (= 6.0.3.3)
actionview (= 6.0.3.3)
activejob (= 6.0.3.3)
activemodel (= 6.0.3.3)
activerecord (= 6.0.3.3)
activestorage (= 6.0.3.3)
activesupport (= 6.0.3.3)
rails (6.0.3.4)
actioncable (= 6.0.3.4)
actionmailbox (= 6.0.3.4)
actionmailer (= 6.0.3.4)
actionpack (= 6.0.3.4)
actiontext (= 6.0.3.4)
actionview (= 6.0.3.4)
activejob (= 6.0.3.4)
activemodel (= 6.0.3.4)
activerecord (= 6.0.3.4)
activestorage (= 6.0.3.4)
activesupport (= 6.0.3.4)
bundler (>= 1.3.0)
railties (= 6.0.3.3)
railties (= 6.0.3.4)
sprockets-rails (>= 2.0.0)
rails-dom-testing (2.0.3)
activesupport (>= 4.2.0)
nokogiri (>= 1.6)
rails-html-sanitizer (1.3.0)
loofah (~> 2.3)
railties (6.0.3.3)
actionpack (= 6.0.3.3)
activesupport (= 6.0.3.3)
railties (6.0.3.4)
actionpack (= 6.0.3.4)
activesupport (= 6.0.3.4)
method_source
rake (>= 0.8.7)
thor (>= 0.20.3, < 2.0)
rainbow (3.0.0)
rake (13.0.1)
rake (13.0.3)
rb-fsevent (0.10.4)
rb-inotify (0.10.1)
ffi (~> 1.0)
rspec-core (3.9.2)
rspec-support (~> 3.9.3)
rspec-expectations (3.9.2)
rexml (3.2.4)
rspec-core (3.10.1)
rspec-support (~> 3.10.0)
rspec-expectations (3.10.1)
diff-lcs (>= 1.2.0, < 2.0)
rspec-support (~> 3.9.0)
rspec-support (~> 3.10.0)
rspec-json_expectations (2.2.0)
rspec-mocks (3.9.1)
rspec-mocks (3.10.1)
diff-lcs (>= 1.2.0, < 2.0)
rspec-support (~> 3.9.0)
rspec-rails (4.0.1)
rspec-support (~> 3.10.0)
rspec-rails (4.0.2)
actionpack (>= 4.2)
activesupport (>= 4.2)
railties (>= 4.2)
rspec-core (~> 3.9)
rspec-expectations (~> 3.9)
rspec-mocks (~> 3.9)
rspec-support (~> 3.9)
rspec-support (3.9.3)
semantic_range (2.3.0)
sentry-raven (3.1.0)
rspec-core (~> 3.10)
rspec-expectations (~> 3.10)
rspec-mocks (~> 3.10)
rspec-support (~> 3.10)
rspec-support (3.10.1)
ruby2_keywords (0.0.2)
semantic_range (2.3.1)
sentry-raven (3.1.1)
faraday (>= 1.0)
shellany (0.0.1)
spring (2.1.1)
@ -249,19 +254,20 @@ GEM
sprockets (>= 3.0.0)
thor (1.0.1)
thread_safe (0.3.6)
tzinfo (1.2.7)
timecop (0.9.2)
tzinfo (1.2.9)
thread_safe (~> 0.1)
uglifier (4.2.0)
execjs (>= 0.3.0, < 3)
unf (0.1.4)
unf_ext
unf_ext (0.0.7.7)
web-console (4.0.4)
web-console (4.1.0)
actionview (>= 6.0.0)
activemodel (>= 6.0.0)
bindex (>= 0.4.0)
railties (>= 6.0.0)
webmock (3.9.2)
webmock (3.11.0)
addressable (>= 2.3.6)
crack (>= 0.3.2)
hashdiff (>= 0.4.0, < 2.0.0)
@ -273,7 +279,7 @@ GEM
websocket-driver (0.7.3)
websocket-extensions (>= 0.1.0)
websocket-extensions (0.1.5)
zeitwerk (2.4.0)
zeitwerk (2.4.2)
PLATFORMS
ruby
@ -306,6 +312,7 @@ DEPENDENCIES
spring
spring-watcher-listen
thor
timecop
tzinfo-data
uglifier
web-console

View File

@ -4,14 +4,14 @@ class NotifierMailer < ApplicationMailer
reply_to: ENV.fetch('EMAIL_REPLY_TO')
def service_fail
@service = param.fetch :service
@down = param.fetch :down
@service = params.fetch :service
@down = params.fetch :down
self.mail subject: "Service is DOWN: [#{@service.type}] #{@service.name}"
end
def service_recover
@service = param.fetch :service
@down = param.fetch :down
@service = params.fetch :service
@down = params.fetch :down
self.mail subject: "Service is UP: [#{@service.type}] #{@service.name}"
end
end

View File

@ -1,4 +1,6 @@
class Down < ApplicationRecord
belongs_to :service
def duration
to = self.to
return nil unless to

View File

@ -25,11 +25,11 @@ class Service < ApplicationRecord
case [last.result, result]
when [true, false]
down = self.downs.create! from: check.created_at
NotifierMailer.with(service: service, down: down).service_fail.deliver_now
NotifierMailer.with(service: self, down: down).service_fail.deliver_now
when [false, true]
down = self.last_down
down.update! to: check.created_at if down
NotifierMailer.with(service: service, down: down).service_recover.deliver_now
NotifierMailer.with(service: self, down: down).service_recover.deliver_now
end
end
end

View File

@ -1,4 +1,4 @@
Hello,
Hello
A mail to notify you that your service [<%= @service.type %>] <%= @service.name %>
is down since <%= @down.from %>.

View File

@ -1,7 +1,7 @@
class CreateDowns < ActiveRecord::Migration[6.0]
def change
create_table :downs, id: :uuid do |t|
t.column :type, :service, null: false
t.references :service, type: :uuid, null: false
t.datetime :from, null: false
t.datetime :to
t.timestamps

View File

@ -0,0 +1,57 @@
require 'rails_helper'
describe Service do
before do
Service.delete_all
end
describe :check! do
it 'must detect down change correctly and act accordingly' do
service = Service.create! name: :test, type: :ping, config: { host: 'example.org' }
check = double Check::Ping, process: []
allow(Check).to receive(:init).with(service.type, service.config)
.and_return(check)
now = Time.utc 2020, 01, 01, 00, 00, 00
from = nil
Timecop.freeze now do
allow(check).to receive(:ok?).and_return(true).at_least(:once)
expect { service.check! }.to not_change { ActionMailer::Base.deliveries.count } \
.and not_change { Down.all.count }
end
Timecop.freeze from = (now += 5.minutes) do
allow(check).to receive(:ok?).and_return(false).at_least(:once)
expect { service.check! }.to change { ActionMailer::Base.deliveries.count }.by(1) \
.and change { Down.all.count }.by(1)
mail = ActionMailer::Base.deliveries.pop
expect(mail.subject).to eq 'Service is DOWN: [ping] test'
down = Down.first
expect(down.from).to eq now
expect(down.to).to be_nil
end
Timecop.freeze now += 5.minutes do
expect { service.check! }.to not_change { ActionMailer::Base.deliveries.count } \
.and not_change { Down.all.count }
end
Timecop.freeze now += 5.minutes do
expect(check).to receive(:ok?).and_return(true).at_least(:once)
expect { service.check! }.to change { ActionMailer::Base.deliveries.count }.by(1) \
.and not_change { Down.all.count }
mail = ActionMailer::Base.deliveries.pop
expect(mail.subject).to eq 'Service is UP: [ping] test'
down = Down.first
expect(down.from).to eq from
expect(down.to).to eq now
expect(down.duration).to eq 10.minutes
end
Timecop.freeze now += 5.minutes do
expect { service.check! }.to not_change { ActionMailer::Base.deliveries.count } \
.and not_change { Down.all.count }
end
end
end
end

View File

@ -96,3 +96,5 @@ RSpec.configure do |config|
Kernel.srand config.seed
=end
end
RSpec::Matchers.define_negated_matcher :not_change, :change

View File

@ -1,7 +0,0 @@
require 'test_helper'
class NotifierMailerTest < ActionMailer::TestCase
# test "the truth" do
# assert true
# end
end

View File

@ -1,4 +0,0 @@
# Preview all emails at http://localhost:3000/rails/mailers/notifier_mailer
class NotifierMailerPreview < ActionMailer::Preview
end

View File

@ -1,7 +0,0 @@
require 'test_helper'
class DownTest < ActiveSupport::TestCase
# test "the truth" do
# assert true
# end
end