mysql-heartbeat 0.1.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 ADDED
@@ -0,0 +1,7 @@
1
+ ---
2
+ SHA1:
3
+ metadata.gz: 6e93ade565eea9f1b66486408985bfb44d5b79ac
4
+ data.tar.gz: 9646d80688a80acbceabac57b5b50aa596fa878e
5
+ SHA512:
6
+ metadata.gz: ed5e41132f88501024905824e6cf6ff5a99e55c592d38f1170658c74a7bfce9b00ca8ec8f72b0f8fa4914fbada56403cd3faf6aa60845c8e7587e1a0b7c25311
7
+ data.tar.gz: 3efd5f6234c8b32451821f4d23017b8dbb052b1085dcc5d26f5f47d6d82cd8b180d18a6fbbbfc3ebae86539ec12ed43fd1464cdff28860d7ed89ffb82ba8237f
data/.travis.yml ADDED
@@ -0,0 +1,10 @@
1
+ language: ruby
2
+ bundler_args: ""
3
+ rvm:
4
+ - 2.0.0
5
+ - 1.9.3
6
+ env:
7
+ - "RACK_ENV=test"
8
+ script:
9
+ - bundle exec rspec --color --format progress
10
+ - bundle exec rubocop
data/Gemfile ADDED
@@ -0,0 +1,20 @@
1
+ source 'http://rubygems.org'
2
+ gem 'sinatra'
3
+ gem 'mysql2'
4
+ gem 'celluloid'
5
+ gem 'thin'
6
+
7
+ group :test, :development do
8
+ gem 'rspec'
9
+ end
10
+
11
+ group :development do
12
+ gem 'guard'
13
+ gem 'guard-rubocop'
14
+ gem 'guard-rspec'
15
+ end
16
+
17
+ group :test do
18
+ gem 'rubocop'
19
+ gem 'rack-test'
20
+ end
data/Gemfile.lock ADDED
@@ -0,0 +1,87 @@
1
+ GEM
2
+ remote: http://rubygems.org/
3
+ specs:
4
+ ast (1.1.0)
5
+ celluloid (0.15.2)
6
+ timers (~> 1.1.0)
7
+ coderay (1.0.9)
8
+ daemons (1.1.9)
9
+ diff-lcs (1.2.4)
10
+ eventmachine (1.0.3)
11
+ ffi (1.9.3)
12
+ formatador (0.2.4)
13
+ guard (2.2.2)
14
+ formatador (>= 0.2.4)
15
+ listen (~> 2.1)
16
+ lumberjack (~> 1.0)
17
+ pry (>= 0.9.12)
18
+ thor (>= 0.18.1)
19
+ guard-rspec (4.0.3)
20
+ guard (>= 2.1.1)
21
+ rspec (~> 2.14)
22
+ guard-rubocop (1.0.0)
23
+ guard (~> 2.0)
24
+ rubocop (~> 0.10)
25
+ listen (2.2.0)
26
+ celluloid (>= 0.15.2)
27
+ rb-fsevent (>= 0.9.3)
28
+ rb-inotify (>= 0.9)
29
+ lumberjack (1.0.4)
30
+ method_source (0.8.2)
31
+ mysql2 (0.3.13)
32
+ parser (2.0.0)
33
+ ast (~> 1.1)
34
+ slop (~> 3.4, >= 3.4.5)
35
+ powerpack (0.0.9)
36
+ pry (0.9.12.2)
37
+ coderay (~> 1.0.5)
38
+ method_source (~> 0.8)
39
+ slop (~> 3.4)
40
+ rack (1.5.2)
41
+ rack-protection (1.5.1)
42
+ rack
43
+ rack-test (0.6.2)
44
+ rack (>= 1.0)
45
+ rainbow (1.1.4)
46
+ rb-fsevent (0.9.3)
47
+ rb-inotify (0.9.2)
48
+ ffi (>= 0.5.0)
49
+ rspec (2.14.1)
50
+ rspec-core (~> 2.14.0)
51
+ rspec-expectations (~> 2.14.0)
52
+ rspec-mocks (~> 2.14.0)
53
+ rspec-core (2.14.7)
54
+ rspec-expectations (2.14.3)
55
+ diff-lcs (>= 1.1.3, < 2.0)
56
+ rspec-mocks (2.14.4)
57
+ rubocop (0.14.1)
58
+ parser (~> 2.0)
59
+ powerpack (~> 0.0.6)
60
+ rainbow (>= 1.1.4)
61
+ sinatra (1.4.4)
62
+ rack (~> 1.4)
63
+ rack-protection (~> 1.4)
64
+ tilt (~> 1.3, >= 1.3.4)
65
+ slop (3.4.6)
66
+ thin (1.6.1)
67
+ daemons (>= 1.0.9)
68
+ eventmachine (>= 1.0.0)
69
+ rack (>= 1.0.0)
70
+ thor (0.18.1)
71
+ tilt (1.4.1)
72
+ timers (1.1.0)
73
+
74
+ PLATFORMS
75
+ ruby
76
+
77
+ DEPENDENCIES
78
+ celluloid
79
+ guard
80
+ guard-rspec
81
+ guard-rubocop
82
+ mysql2
83
+ rack-test
84
+ rspec
85
+ rubocop
86
+ sinatra
87
+ thin
data/Guardfile ADDED
@@ -0,0 +1,29 @@
1
+ # A sample Guardfile
2
+ # More info at https://github.com/guard/guard#readme
3
+
4
+ guard :rubocop do
5
+ watch(%r{.+\.rb$})
6
+ watch(%r{(?:.+/)?\.rubocop\.yml$}) { |m| File.dirname(m[0]) }
7
+ end
8
+
9
+ guard :rspec do
10
+ watch(%r{^spec/.+_spec\.rb$})
11
+ watch(%r{^lib/(.+)\.rb$}) { |m| "spec/lib/#{m[1]}_spec.rb" }
12
+ watch('spec/spec_helper.rb') { "spec" }
13
+
14
+ # Rails example
15
+ watch(%r{^app/(.+)\.rb$}) { |m| "spec/#{m[1]}_spec.rb" }
16
+ watch(%r{^app/(.*)(\.erb|\.haml|\.slim)$}) { |m| "spec/#{m[1]}#{m[2]}_spec.rb" }
17
+ watch(%r{^app/controllers/(.+)_(controller)\.rb$}) { |m| ["spec/routing/#{m[1]}_routing_spec.rb", "spec/#{m[2]}s/#{m[1]}_#{m[2]}_spec.rb", "spec/acceptance/#{m[1]}_spec.rb"] }
18
+ watch(%r{^spec/support/(.+)\.rb$}) { "spec" }
19
+ watch('config/routes.rb') { "spec/routing" }
20
+ watch('app/controllers/application_controller.rb') { "spec/controllers" }
21
+
22
+ # Capybara features specs
23
+ watch(%r{^app/views/(.+)/.*\.(erb|haml|slim)$}) { |m| "spec/features/#{m[1]}_spec.rb" }
24
+
25
+ # Turnip features and steps
26
+ watch(%r{^spec/acceptance/(.+)\.feature$})
27
+ watch(%r{^spec/acceptance/steps/(.+)_steps\.rb$}) { |m| Dir[File.join("**/#{m[1]}.feature")][0] || 'spec/acceptance' }
28
+ end
29
+
data/README.md ADDED
@@ -0,0 +1,57 @@
1
+ [![Dependency Status](https://gemnasium.com/johnbarney/mysql-heartbeat.png)](https://gemnasium.com/johnbarney/mysql-heartbeat)
2
+ [![Build Status](https://secure.travis-ci.org/johnbarney/mysql-heartbeat.png)](http://travis-ci.org/johnbarney/mysql-heartbeat)
3
+ [![Gem Version](https://badge.fury.io/rb/mysql-heartbeat.png)](http://badge.fury.io/rb/mysql-heartbeat)
4
+ # MySQL Heartbeat
5
+
6
+ A health monitor for MySQL replication. This can be used in tandem with applications like HAProxy to check the health of replication, and load balance across read slaves.
7
+
8
+ Installation
9
+ ------------
10
+
11
+ Installation is as easy as installing a gem.
12
+
13
+ $ gem install mysql-heartbeat
14
+ $ mysql-heartbeat yourconfig.yml
15
+
16
+ Configuration
17
+ -------------
18
+
19
+ Make a copy of database.yml for each MySQL instance you want to watch. You can launch as many of these instances as you like as long as they each use a different local port.
20
+
21
+ custom.yml:
22
+
23
+ host: "localhost" # Address of MySQL instance
24
+ username: "health" # Username of MySQL user
25
+ password: "health99" # Password of MySQL user
26
+ health_port: 6977 # Port this instance of MySQL health resides on
27
+ tolerance: 5 # How far behind MySQL replication can be before healthchecks fail
28
+
29
+ $ ruby heartbeat.rb custom.yml
30
+
31
+ Note: The user must have REPLICATION CLIENT privileges for mysql_heartbeat to function.
32
+
33
+ Example:
34
+
35
+ mysql> create user 'health'@'localhost' identified by 'health99';
36
+
37
+ mysql> grant REPLICATION CLIENT on *.* to 'health'@'localhost';
38
+
39
+ Process Control
40
+ ---------------
41
+
42
+ I would recommend either [Supervisord](http://supervisord.org/ "Supervisord") or [Bluepill](https://github.com/bluepill-rb/bluepill "Bluepill") to manage forking and management of instances.
43
+
44
+ HAProxy Configuration
45
+ ---------------------
46
+
47
+ Coming Soon!
48
+
49
+ Work in Progress
50
+ ----------------
51
+
52
+ This project is primarily to teach myself how to write tests, and integrate with Travis. It's still a long way from complete. Contributions and suggestions are always welcome.
53
+
54
+ Contributing
55
+ ------------
56
+
57
+ See GitHub's ["Fork A Repo"](https://help.github.com/articles/fork-a-repo "Forking a project") for more information.
@@ -0,0 +1,15 @@
1
+ #! /usr/bin/env ruby
2
+ # -*- encoding: utf-8 -*-
3
+
4
+ if RUBY_VERSION >= '1.9.3'
5
+ if ARGV[0].nil? && ENV['RACK_ENV'] != 'test'
6
+ puts 'No configuration file specified'
7
+ exit 1
8
+ end
9
+ $LOAD_PATH.unshift(File.dirname(File.realpath(__FILE__)) + '/../lib')
10
+ require 'mysql-heartbeat'
11
+ HeartBeat.run!
12
+ else
13
+ puts 'mysql-heartbeat supports only Ruby 1.9.3+'
14
+ exit(-1)
15
+ end
@@ -0,0 +1,5 @@
1
+ host: "localhost"
2
+ username: "health"
3
+ password: "check99"
4
+ tolerance: 5
5
+ health_port: 6977
data/config/travis.yml ADDED
@@ -0,0 +1,5 @@
1
+ host: 'localhost'
2
+ username: 'travis'
3
+ password: ''
4
+ tolerance: 5
5
+ health_port: 6977
@@ -0,0 +1,26 @@
1
+ # -*- encoding: utf-8 -*-
2
+ require 'sinatra/base'
3
+ require 'yaml'
4
+ require 'rack/test' if ENV['RACK_ENV'] == 'test'
5
+ require 'mysql-heartbeat/health'
6
+ require 'mysql-heartbeat/worker'
7
+ require 'mysql-heartbeat/version'
8
+
9
+ # Heartbeat Class
10
+ class HeartBeat < Sinatra::Base
11
+ configure do
12
+ if ENV['RACK_ENV'] == 'test'
13
+ config = YAML.load_file("#{File.dirname(__FILE__)}/../config/travis.yml")
14
+ else
15
+ config = YAML.load_file(ARGV[0])
16
+ end
17
+ set :port, config['health_port'].to_i
18
+ set :bind, '0.0.0.0'
19
+ set :server, 'thin'
20
+ set :process, HeartbeatWorker.new(config)
21
+ end
22
+
23
+ options '/' do
24
+ settings.process.current_health
25
+ end
26
+ end
@@ -0,0 +1,55 @@
1
+ # -*- encoding: utf-8 -*-
2
+ require 'mysql2'
3
+
4
+ # Is MySQL healthy?
5
+ class Health
6
+ def initialize(config)
7
+ @conn = Mysql2::Client.new(host: config['host'],
8
+ username: config['username'],
9
+ password: config['password']
10
+ )
11
+ @tolerance = config[:tolerance]
12
+ get_status
13
+ rescue => ex
14
+ puts ex
15
+ puts 'Could not connect to MySQL.'
16
+ end
17
+
18
+ def get_status
19
+ results = @conn.query('show slave status;')
20
+ results.each do |row|
21
+ @sec_behind = row['Seconds_Behind_Master'].to_i
22
+ @slave_sql = row['Slave_SQL_Running'] == 'Yes'
23
+ @slave_io = row['Slave_IO_Running'] == 'Yes'
24
+ @last_error = row['Last_Error']
25
+ end
26
+ rescue => ex
27
+ puts ex
28
+ puts 'Could not query slave status.'
29
+ end
30
+
31
+ def replicating?
32
+ @slave_sql && @slave_io
33
+ end
34
+
35
+ def behind?
36
+ @sec_behind > @tolerance unless @sec_behind.nil?
37
+ end
38
+
39
+ def healthy?
40
+ if replicating? && !behind?
41
+ return [200, "OK\n"]
42
+ else
43
+ reason = "Replication is not healthy!
44
+ \nSlave_IO running: #{@slave_io}
45
+ \nSlave_SQL running: #{@slave_sql}
46
+ \nSeconds Behind: #{@sec_behind}
47
+ \nLast Error: #{@last_error}"
48
+ return [503, reason]
49
+ end
50
+ end
51
+
52
+ def conn_close
53
+ @conn.close unless @conn.nil?
54
+ end
55
+ end
@@ -0,0 +1,5 @@
1
+ # -*- encoding: utf-8 -*-
2
+ # Version
3
+ module MysqlHeartBeat
4
+ VERSION = '0.1.1'.freeze
5
+ end
@@ -0,0 +1,25 @@
1
+ # -*- encoding: utf-8 -*-
2
+ require 'celluloid'
3
+
4
+ # Celluloid worker
5
+ class HeartbeatWorker
6
+ include Celluloid
7
+ attr_reader :current_health
8
+
9
+ def initialize(config)
10
+ @config = config
11
+ async.worker
12
+ end
13
+
14
+ def worker
15
+ loop do
16
+ begin
17
+ db = Health.new(@config)
18
+ @current_health = db.healthy?
19
+ sleep 15
20
+ ensure
21
+ db.conn_close unless db.nil?
22
+ end
23
+ end
24
+ end
25
+ end
@@ -0,0 +1,29 @@
1
+ $LOAD_PATH.push File.expand_path("../lib", __FILE__)
2
+
3
+ require "mysql-heartbeat/version"
4
+
5
+ Gem::Specification.new do |s|
6
+ s.name = 'mysql-heartbeat'
7
+ s.version = MysqlHeartBeat::VERSION.dup
8
+ s.date = '2013-10-28'
9
+ s.summary = "Queries the replication health of a MySQL server."
10
+ s.description = <<-EOF
11
+ Queries the replication health of a MySQL server.
12
+ A health monitor for MySQL replication. This can be used
13
+ in tandem with applications like HAProxy to check the
14
+ health of replication, and load balance across read slaves.
15
+ EOF
16
+
17
+ s.add_dependency 'sinatra', '~> 1.4'
18
+ s.add_dependency 'mysql2', '~> 0.3'
19
+ s.add_dependency 'celluloid', '~> 0.15'
20
+ s.add_dependency 'thin', '~> 1.6'
21
+
22
+ s.authors = ["John Barney"]
23
+ s.email = 'johnb0011@gmail.com'
24
+ s.required_ruby_version = '>= 1.9.3'
25
+ s.platform = Gem::Platform::RUBY
26
+ s.files = `git ls-files`.split("\n")
27
+ s.executables = `git ls-files -- bin/*`.split("\n").map{ |f| File.basename(f) }
28
+ s.homepage = 'http://github.com/johnb0011/mysql_heartbeat'
29
+ end
@@ -0,0 +1,14 @@
1
+ # -*- encoding: utf-8 -*-
2
+ # spec/features/base_spec.rb
3
+ require_relative '../spec_helper'
4
+
5
+ describe 'Root Path' do
6
+ describe 'OPTIONS /' do
7
+ before { options '/' }
8
+
9
+ it 'is successful' do
10
+ # Yep. I wrote a test to pass on a 503. Deal with it. (This will change)
11
+ expect(last_response.status).to eq(503)
12
+ end
13
+ end
14
+ end
@@ -0,0 +1,13 @@
1
+ # -*- encoding: utf-8 -*-
2
+ # spec/spec_helper.rb
3
+ ENV['RACK_ENV'] = 'test'
4
+
5
+ require_relative File.join('..', 'lib/mysql-heartbeat')
6
+
7
+ RSpec.configure do |config|
8
+ include Rack::Test::Methods
9
+
10
+ def app
11
+ HeartBeat
12
+ end
13
+ end
metadata ADDED
@@ -0,0 +1,117 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: mysql-heartbeat
3
+ version: !ruby/object:Gem::Version
4
+ version: 0.1.1
5
+ platform: ruby
6
+ authors:
7
+ - John Barney
8
+ autorequire:
9
+ bindir: bin
10
+ cert_chain: []
11
+ date: 2013-10-28 00:00:00.000000000 Z
12
+ dependencies:
13
+ - !ruby/object:Gem::Dependency
14
+ name: sinatra
15
+ requirement: !ruby/object:Gem::Requirement
16
+ requirements:
17
+ - - ~>
18
+ - !ruby/object:Gem::Version
19
+ version: '1.4'
20
+ type: :runtime
21
+ prerelease: false
22
+ version_requirements: !ruby/object:Gem::Requirement
23
+ requirements:
24
+ - - ~>
25
+ - !ruby/object:Gem::Version
26
+ version: '1.4'
27
+ - !ruby/object:Gem::Dependency
28
+ name: mysql2
29
+ requirement: !ruby/object:Gem::Requirement
30
+ requirements:
31
+ - - ~>
32
+ - !ruby/object:Gem::Version
33
+ version: '0.3'
34
+ type: :runtime
35
+ prerelease: false
36
+ version_requirements: !ruby/object:Gem::Requirement
37
+ requirements:
38
+ - - ~>
39
+ - !ruby/object:Gem::Version
40
+ version: '0.3'
41
+ - !ruby/object:Gem::Dependency
42
+ name: celluloid
43
+ requirement: !ruby/object:Gem::Requirement
44
+ requirements:
45
+ - - ~>
46
+ - !ruby/object:Gem::Version
47
+ version: '0.15'
48
+ type: :runtime
49
+ prerelease: false
50
+ version_requirements: !ruby/object:Gem::Requirement
51
+ requirements:
52
+ - - ~>
53
+ - !ruby/object:Gem::Version
54
+ version: '0.15'
55
+ - !ruby/object:Gem::Dependency
56
+ name: thin
57
+ requirement: !ruby/object:Gem::Requirement
58
+ requirements:
59
+ - - ~>
60
+ - !ruby/object:Gem::Version
61
+ version: '1.6'
62
+ type: :runtime
63
+ prerelease: false
64
+ version_requirements: !ruby/object:Gem::Requirement
65
+ requirements:
66
+ - - ~>
67
+ - !ruby/object:Gem::Version
68
+ version: '1.6'
69
+ description: " Queries the replication health of a MySQL server.\n A health
70
+ monitor for MySQL replication. This can be used \n in tandem with applications
71
+ like HAProxy to check the\n health of replication, and load balance across read
72
+ slaves.\n"
73
+ email: johnb0011@gmail.com
74
+ executables:
75
+ - mysql-heartbeat
76
+ extensions: []
77
+ extra_rdoc_files: []
78
+ files:
79
+ - .travis.yml
80
+ - Gemfile
81
+ - Gemfile.lock
82
+ - Guardfile
83
+ - README.md
84
+ - bin/mysql-heartbeat
85
+ - config/example_mysql.yml
86
+ - config/travis.yml
87
+ - lib/mysql-heartbeat.rb
88
+ - lib/mysql-heartbeat/health.rb
89
+ - lib/mysql-heartbeat/version.rb
90
+ - lib/mysql-heartbeat/worker.rb
91
+ - mysql-heartbeat.gemspec
92
+ - spec/requests/base_spec.rb
93
+ - spec/spec_helper.rb
94
+ homepage: http://github.com/johnb0011/mysql_heartbeat
95
+ licenses: []
96
+ metadata: {}
97
+ post_install_message:
98
+ rdoc_options: []
99
+ require_paths:
100
+ - lib
101
+ required_ruby_version: !ruby/object:Gem::Requirement
102
+ requirements:
103
+ - - '>='
104
+ - !ruby/object:Gem::Version
105
+ version: 1.9.3
106
+ required_rubygems_version: !ruby/object:Gem::Requirement
107
+ requirements:
108
+ - - '>='
109
+ - !ruby/object:Gem::Version
110
+ version: '0'
111
+ requirements: []
112
+ rubyforge_project:
113
+ rubygems_version: 2.0.3
114
+ signing_key:
115
+ specification_version: 4
116
+ summary: Queries the replication health of a MySQL server.
117
+ test_files: []