Class: MysqlHealth::Health
- Inherits:
-
Object
- Object
- MysqlHealth::Health
- Defined in:
- lib/mysql_health/health.rb
Class Method Summary collapse
Instance Method Summary collapse
- #check_master ⇒ Object
- #check_slave ⇒ Object
- #database?(dbh, name) ⇒ Boolean
- #describe_status(status) ⇒ Object
-
#initialize(options = {}) ⇒ Health
constructor
A new instance of Health.
- #master?(dbh) ⇒ Boolean
- #master_status ⇒ Object
- #master_status=(response) ⇒ Object
- #read_only?(dbh) ⇒ Boolean
- #show_create_database(dbh, name) ⇒ Object
-
#show_status(dbh, type = nil) ⇒ Object
Return a hash of status information.
- #slave_status ⇒ Object
- #slave_status=(response) ⇒ Object
Constructor Details
#initialize(options = {}) ⇒ Health
Returns a new instance of Health.
32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 |
# File 'lib/mysql_health/health.rb', line 32 def initialize( = {}) @options = @mutex = Mutex.new @scheduler = Rufus::Scheduler.start_new def @scheduler.handle_exception(job, e) MysqlHealth.log.error "job #{job.job_id} caught #{e.class} exception '#{e}' #{e.backtrace.join("\n")}" end if [:master] master_status = {} master_status[:status] = 503 master_status[:content] = "Health of master not yet determined\n" self.master_status=(master_status) @scheduler.every [:interval], :allow_overlapping => [:allow_overlapping], :first_in => [:delay] do check_master end else master_status = {} master_status[:status] = '501 Not Enabled' master_status[:content] = "Health of master not enabled\n" self.master_status=(master_status) end if [:slave] slave_status = {} slave_status[:status] = '501 Not Enabled' slave_status[:content] = "Health of slave not yet determined\n" self.slave_status=(slave_status) @scheduler.every [:interval], :allow_overlapping => [:allow_overlapping], :first_in => [:delay] do check_slave end else slave_status = {} slave_status[:status] = '501 Not Enabled' slave_status[:content] = "Health of slave not enabled\n" self.slave_status=(slave_status) end end |
Class Method Details
.handle_exception(job, e) ⇒ Object
37 38 39 |
# File 'lib/mysql_health/health.rb', line 37 def @scheduler.handle_exception(job, e) MysqlHealth.log.error "job #{job.job_id} caught #{e.class} exception '#{e}' #{e.backtrace.join("\n")}" end |
Instance Method Details
#check_master ⇒ Object
111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 |
# File 'lib/mysql_health/health.rb', line 111 def check_master MysqlHealth.log.debug("check_master") response = {} response[:content_type] = 'text/plain' begin # connect to the MySQL server dbh = DBI.connect(@options[:dsn], @options[:username], @options[:password]) # Validate that database exists unless @options[:database].nil? unless database?(dbh, @options[:database]) raise Exception.new("Database schema named #{@options[:database]} does not exist") end end status = show_status(dbh) if status.length > 0 if read_only?(dbh) response[:status] = '503 Service Read Only' response[:content] = describe_status(status) else response[:status] = '200 OK' response[:content] = describe_status(status) end else response[:status] = '503 Service Unavailable' response[:content] = describe_status(status) end rescue Exception => e response[:status] = '500 Server Error' response[:content] = e. end self.master_status=(response) end |
#check_slave ⇒ Object
187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 |
# File 'lib/mysql_health/health.rb', line 187 def check_slave MysqlHealth.log.debug("check_slave") response = {} response[:content_type] = 'text/plain' begin # connect to the MySQL server dbh = DBI.connect(@options[:dsn], @options[:username], @options[:password]) # Validate that database exists unless @options[:database].nil? unless database?(dbh, @options[:database]) raise Exception.new("Database schema named #{@options[:database]} does not exist") end end show_slave_status = show_status(dbh, :slave) if show_slave_status.length > 0 seconds_behind_master = show_slave_status[:seconds_behind_master] # We return a "203 Non-Authoritative Information" when replication is shot. We don't want to reduce site performance, but still want to track that something is awry. if seconds_behind_master.eql?('NULL') response[:status] = '203 Slave Stopped' response[:content] = show_slave_status.to_json response[:content_type] = 'application/json' elsif seconds_behind_master.to_i > 60*30 response[:status] = '203 Slave Behind' response[:content] = show_slave_status.to_json response[:content_type] = 'application/json' elsif read_only?(dbh) response[:status] = '200 OK ' + seconds_behind_master + ' Seconds Behind Master' response[:content] = show_slave_status.to_json response[:content_type] = 'application/json' else response[:status] = '503 Service Unavailable' response[:content] = show_slave_status.to_json response[:content_type] = 'application/json' end elsif @options[:allow_master] && master?(dbh) response[:status] = '200 OK Master Running' response[:content] = describe_status show_status(dbh) response[:content_type] = 'application/json' else response[:status] = '503 Slave Not Configured' response[:content] = show_slave_status.to_json end rescue Exception => e response[:status] = '500 Server Error' response[:content] = e. end self.slave_status=(response) end |
#database?(dbh, name) ⇒ Boolean
183 184 185 |
# File 'lib/mysql_health/health.rb', line 183 def database?(dbh, name) show_create_database(dbh, name).nil? == false end |
#describe_status(status) ⇒ Object
147 148 149 150 151 |
# File 'lib/mysql_health/health.rb', line 147 def describe_status(status) # Mimick "mysqladmin status" "Uptime: %s Threads: %s Questions: %s Slow queries: %s Opens: %s Flush tables: %s Open tables: %s Queries per second avg: %.3f\n" % [ status[:uptime], status[:threads_running], status[:questions], status[:slow_queries], status[:opened_tables], status[:flush_commands], status[:open_tables], status[:queries].to_i/status[:uptime].to_i] end |
#master?(dbh) ⇒ Boolean
107 108 109 |
# File 'lib/mysql_health/health.rb', line 107 def master?(dbh) read_only?(dbh) == false end |
#master_status ⇒ Object
79 80 81 82 83 84 85 |
# File 'lib/mysql_health/health.rb', line 79 def master_status master_status = nil @mutex.synchronize do master_status = @master_status end return master_status end |
#master_status=(response) ⇒ Object
72 73 74 75 76 77 |
# File 'lib/mysql_health/health.rb', line 72 def master_status=(response) @mutex.synchronize do MysqlHealth.log.info("master status: #{response[:status]} (#{response[:content].split(/\n/)[0]})") @master_status = response end end |
#read_only?(dbh) ⇒ Boolean
102 103 104 105 |
# File 'lib/mysql_health/health.rb', line 102 def read_only?(dbh) variables = dbh.select_all("SHOW VARIABLES WHERE Variable_name = 'read_only' AND Value = 'ON'") return (variables.length == 1) end |
#show_create_database(dbh, name) ⇒ Object
173 174 175 176 177 178 179 180 181 |
# File 'lib/mysql_health/health.rb', line 173 def show_create_database(dbh, name) schema = nil dbh.execute('SHOW CREATE DATABASE %s' % name) do |sth| sth.fetch() do |row| schema = row[1] end end return schema end |
#show_status(dbh, type = nil) ⇒ Object
Return a hash of status information
154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 |
# File 'lib/mysql_health/health.rb', line 154 def show_status(dbh, type = nil) status = {} if type.nil? # Format of "SHOW STATUS" differs from "SHOW [MASTER|SLAVE] STATUS" dbh.select_all('SHOW STATUS') do |row| status[row[0].downcase.to_sym] = row[1] end else dbh.execute('SHOW %s STATUS' % type.to_s.upcase) do |sth| sth.fetch_hash() do |row| row.each_pair do |k,v| status[k.downcase.to_sym] = v end end end end status end |
#slave_status ⇒ Object
94 95 96 97 98 99 100 |
# File 'lib/mysql_health/health.rb', line 94 def slave_status slave_status = nil @mutex.synchronize do slave_status = @slave_status end return slave_status end |
#slave_status=(response) ⇒ Object
87 88 89 90 91 92 |
# File 'lib/mysql_health/health.rb', line 87 def slave_status=(response) @mutex.synchronize do MysqlHealth.log.info("slave status: #{response[:status]} (#{response[:content].split(/\n/)[0]})") @slave_status = response end end |