Commit ff42edd688014d06726b6edd7e29e34a1e68a800:
invoke each monitor in a separate thread
Branch: refs/heads/master
Author: Sam Ruby <[email protected]>
Committer: Sam Ruby <[email protected]>
Pusher: rubys <[email protected]>
------------------------------------------------------------
www/status/README.md | +++++ ------
www/status/monitor.rb | +++++ ----
------------------------------------------------------------
78 changes: 44 additions, 34 deletions.
------------------------------------------------------------
diff --git a/www/status/README.md b/www/status/README.md
index c37e42d..ed4130e 100644
--- a/www/status/README.md
+++ b/www/status/README.md
@@ -91,12 +91,11 @@ no more often than once a minute, and are passed the
normalized results of the
previous call.
As monitors are called in response to a ping, they are expected to produce
-results in sub-second time in order to avoid the ping timing out. (Currently
-monitors are called in series, but in the future this may change to threads so
-that statuses may be collected in parallel.) Monitors that perform activities
-that take a substantial amount of time may elect to do so less frequently than
-once a minute, and can take advantage of the `mtime` values to determine when
-to do so.
+results in sub-second time in order to avoid the ping timing out. (Monitors
+are run in separate threads to minimize the total elapsed time). Monitors
+that perform activities that take a substantial amount of time may elect to do
+so less frequently than once a minute, and can take advantage of the `mtime`
+values to determine when to do so.
Results are collected into a hash, and that hash is then normalized.
Normalization resolves default values for items like levels and titles
diff --git a/www/status/monitor.rb b/www/status/monitor.rb
index 781d997..6822875 100644
--- a/www/status/monitor.rb
+++ b/www/status/monitor.rb
@@ -6,6 +6,7 @@
require 'json'
require 'time'
+require 'thread'
class Monitor
# match http://getbootstrap.com/components/#alerts
@@ -30,42 +31,52 @@ def initialize(args = [])
return
end
- # invoke each monitor, collecting status from each
- newstatus = {}
+ # start each monitor in a separate thread
+ threads = []
self.class.singleton_methods.sort.each do |method|
next if args.length > 0 and not args.include? method.to_s
- # invoke method to determine current status
- begin
- previous = baseline[method] || {mtime: Time.at(0)}
- status = Monitor.send(method, previous) || previous
-
- # convert non-hashes in proper statuses
- if not status.instance_of? Hash
- if status.instance_of? String or status.instance_of? Array
- status = {data: status}
- else
- status = {level: 'danger', data: status.inspect}
+ threads << Thread.new do
+ begin
+ # invoke method to determine current status
+ previous = baseline[method] || {mtime: Time.at(0)}
+ status = Monitor.send(method, previous) || previous
+
+ # convert non-hashes in proper statuses
+ if not status.instance_of? Hash
+ if status.instance_of? String or status.instance_of? Array
+ status = {data: status}
+ else
+ status = {level: 'danger', data: status.inspect}
+ end
end
- end
- rescue Exception => e
- status = {
- level: 'danger',
- data: {
- exception: {
- level: 'danger',
- text: e.inspect,
- data: e.backtrace
+ rescue Exception => e
+ status = {
+ level: 'danger',
+ data: {
+ exception: {
+ level: 'danger',
+ text: e.inspect,
+ data: e.backtrace
+ }
}
}
- }
- end
+ end
- # default mtime to now
- status['mtime'] ||= Time.now if status.instance_of? Hash
+ # default mtime to now
+ status['mtime'] ||= Time.now if status.instance_of? Hash
- # update baseline
- newstatus[method] = status
+ # store status in thread local storage
+ Thread.current[:name] = method.to_s
+ Thread.current[:status] = status
+ end
+ end
+
+ # collect status from each monitor thread
+ newstatus = {}
+ threads.each do |thread|
+ thread.join
+ newstatus[thread[:name]] = thread[:status]
end
# normalize status