Detect down & up
parent
36ec984c33
commit
d427add86f
|
@ -0,0 +1,3 @@
|
|||
EMAIL_FROM = monit_from@example.org
|
||||
EMAIL_TO = monit_to@example.org
|
||||
EMAIL_REPLY_TO = noreply@example.org
|
1
Gemfile
1
Gemfile
|
@ -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]
|
||||
|
|
177
Gemfile.lock
177
Gemfile.lock
|
@ -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
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -1,4 +1,6 @@
|
|||
class Down < ApplicationRecord
|
||||
belongs_to :service
|
||||
|
||||
def duration
|
||||
to = self.to
|
||||
return nil unless to
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
Hello,
|
||||
Hello
|
||||
|
||||
A mail to notify you that your service [<%= @service.type %>] <%= @service.name %>
|
||||
is down since <%= @down.from %>.
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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
|
|
@ -96,3 +96,5 @@ RSpec.configure do |config|
|
|||
Kernel.srand config.seed
|
||||
=end
|
||||
end
|
||||
|
||||
RSpec::Matchers.define_negated_matcher :not_change, :change
|
||||
|
|
|
@ -1,7 +0,0 @@
|
|||
require 'test_helper'
|
||||
|
||||
class NotifierMailerTest < ActionMailer::TestCase
|
||||
# test "the truth" do
|
||||
# assert true
|
||||
# end
|
||||
end
|
|
@ -1,4 +0,0 @@
|
|||
# Preview all emails at http://localhost:3000/rails/mailers/notifier_mailer
|
||||
class NotifierMailerPreview < ActionMailer::Preview
|
||||
|
||||
end
|
|
@ -1,7 +0,0 @@
|
|||
require 'test_helper'
|
||||
|
||||
class DownTest < ActiveSupport::TestCase
|
||||
# test "the truth" do
|
||||
# assert true
|
||||
# end
|
||||
end
|
Loading…
Reference in New Issue