ruby-watchcat-pure 1.0.0
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.
- data/README +64 -0
- data/examples/example.rb +21 -0
- data/lib/watchcat.rb +142 -0
- metadata +57 -0
data/README
ADDED
@@ -0,0 +1,64 @@
|
|
1
|
+
== Introduction
|
2
|
+
|
3
|
+
Ruby/Watchcat allows the development of watchcatd-aware applications in
|
4
|
+
Ruby.
|
5
|
+
|
6
|
+
Watchcatd is a watchdog-like daemon in the sense that it takes actions
|
7
|
+
in situations where a machine is under heavy load and/or unresponsive.
|
8
|
+
However, watchcatd isn't as drastic as the usual watchdog systems, which
|
9
|
+
generally reboot the machine. Instead, all it does is sending a signal to
|
10
|
+
a registered process (which by default is SIGKILL) if the process doesn't
|
11
|
+
send it a heartbeat before a user-specified timeout.
|
12
|
+
|
13
|
+
Ruby/Watchcatd allows a Ruby application to register itself with watchcatd.
|
14
|
+
|
15
|
+
|
16
|
+
== Requirements
|
17
|
+
|
18
|
+
Ruby/Watchcatd was tested with Ruby versions >= 1.8.4 and requires watchcatd
|
19
|
+
version 1.1 and libwcat version 1.0 to be installed (see References below).
|
20
|
+
|
21
|
+
|
22
|
+
== Installation
|
23
|
+
|
24
|
+
The easiest way to install Ruby/Watchcat is to use rubygems:
|
25
|
+
|
26
|
+
* For the C extension:
|
27
|
+
gem install ruby-watchcat
|
28
|
+
|
29
|
+
* For the pure-Ruby version:
|
30
|
+
gem install ruby-watchcat-pure
|
31
|
+
|
32
|
+
The C extension requires you to have the libwcat development package
|
33
|
+
installed.
|
34
|
+
|
35
|
+
== License
|
36
|
+
|
37
|
+
Copyright (c) 2006, 2007, 2008 Andre Nathan <andre@digirati.com.br>
|
38
|
+
|
39
|
+
Permission to use, copy, modify, and distribute this software for any
|
40
|
+
purpose with or without fee is hereby granted, provided that the above
|
41
|
+
copyright notice and this permission notice appear in all copies.
|
42
|
+
|
43
|
+
THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
|
44
|
+
WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
|
45
|
+
MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
|
46
|
+
ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
|
47
|
+
WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
|
48
|
+
ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
|
49
|
+
OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
|
50
|
+
|
51
|
+
|
52
|
+
== Author
|
53
|
+
|
54
|
+
Ruby/Watchcat was developed by Andre Nathan.
|
55
|
+
|
56
|
+
|
57
|
+
== References
|
58
|
+
|
59
|
+
* Ruby/Watchcat homepage:
|
60
|
+
http://oss.digirati.com.br/ruby-watchcat/
|
61
|
+
* Rubyforge project home:
|
62
|
+
http://www.rubyforge.org/projects/watchcat
|
63
|
+
* Watchcatd and libwcat:
|
64
|
+
http://oss.digirati.com.br/watchcatd/
|
data/examples/example.rb
ADDED
@@ -0,0 +1,21 @@
|
|
1
|
+
require 'watchcat'
|
2
|
+
|
3
|
+
# Create a new cat.
|
4
|
+
cat = Watchcat.new(:timeout => 5, :signal => 'KILL', :info => 'rubykill!')
|
5
|
+
loop do
|
6
|
+
# Do something that might be slow.
|
7
|
+
sleep 4 + rand(3)
|
8
|
+
puts 'survived'
|
9
|
+
cat.heartbeat
|
10
|
+
end
|
11
|
+
cat.close # clean cat's litter box.
|
12
|
+
|
13
|
+
# If you call it with a block, the cat cleans its own litter box.
|
14
|
+
Watchcat.new do |cat|
|
15
|
+
loop do
|
16
|
+
# Do something that might be slow.
|
17
|
+
sleep 4 + rand(3)
|
18
|
+
puts 'survived'
|
19
|
+
cat.heartbeat
|
20
|
+
end
|
21
|
+
end
|
data/lib/watchcat.rb
ADDED
@@ -0,0 +1,142 @@
|
|
1
|
+
#--
|
2
|
+
# Copyright (c) 2008 Andre Nathan <andre@digirati.com.br>
|
3
|
+
#
|
4
|
+
# Permission to use, copy, modify, and distribute this software for any
|
5
|
+
# purpose with or without fee is hereby granted, provided that the above
|
6
|
+
# copyright notice and this permission notice appear in all copies.
|
7
|
+
#
|
8
|
+
# THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
|
9
|
+
# WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
|
10
|
+
# MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
|
11
|
+
# ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
|
12
|
+
# WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
|
13
|
+
# ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
|
14
|
+
# OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
|
15
|
+
#
|
16
|
+
# $Id: watchcat.rb 24 2008-08-04 14:47:08Z andre $
|
17
|
+
#++
|
18
|
+
|
19
|
+
# Pure-ruby version of libwcat.
|
20
|
+
|
21
|
+
require 'fcntl'
|
22
|
+
require 'socket'
|
23
|
+
|
24
|
+
#
|
25
|
+
# == Overview
|
26
|
+
#
|
27
|
+
# Ruby/Watchcat is a library for the development of watchcatd-aware
|
28
|
+
# applications. It requires watchcatd to be installed and running, and
|
29
|
+
# communicates with it via UNIX sockets.
|
30
|
+
#
|
31
|
+
class Watchcat
|
32
|
+
DEFAULT_TIMEOUT = 60
|
33
|
+
DEFAULT_DEVICE = '/dev/watchcat'
|
34
|
+
DEFAULT_SIGNAL = Signal.list['KILL']
|
35
|
+
|
36
|
+
# Create a new Watchcat object. The parameter hash may have the following
|
37
|
+
# symbols:
|
38
|
+
# +timeout+::
|
39
|
+
# If watchcatd doesn't receive a heartbeat after this period (in seconds),
|
40
|
+
# it will signal the process. (default: 60)
|
41
|
+
# +signal+::
|
42
|
+
# Defines which signal will be sent to the process after the timeout
|
43
|
+
# expires. Can be a string like 'HUP' or 'SIGHUP' or an integer like 9.
|
44
|
+
# (default: 9)
|
45
|
+
# +info+::
|
46
|
+
# Should be a string which is added to the log generated by watchcatd
|
47
|
+
# when it signals a process. (default: nil)
|
48
|
+
# +device+::
|
49
|
+
# The watchcat device. (default: +/dev/watchcat+). Use for debugging
|
50
|
+
# purposes.
|
51
|
+
#
|
52
|
+
# If a block is given, the Watchcat object will be yielded and automatically
|
53
|
+
# closed on block termination.
|
54
|
+
def initialize(args = {}) # :yield:
|
55
|
+
timeout = args[:timeout] || DEFAULT_TIMEOUT
|
56
|
+
device = args[:device] || DEFAULT_DEVICE
|
57
|
+
info = args[:info] ? args[:info].to_s : ''
|
58
|
+
|
59
|
+
unless timeout.is_a? Fixnum
|
60
|
+
raise ArgumentError, 'timeout must be an integer'
|
61
|
+
end
|
62
|
+
|
63
|
+
case args[:signal]
|
64
|
+
when nil
|
65
|
+
signal = DEFAULT_SIGNAL
|
66
|
+
when String
|
67
|
+
signal = Signal.list[args[:signal].sub(/^SIG/, '')]
|
68
|
+
raise ArgumentError, "invalid signal name" if signal.nil?
|
69
|
+
when Fixnum
|
70
|
+
signal = args[:signal]
|
71
|
+
else
|
72
|
+
raise ArgumentError, "signal must be an integer or a string"
|
73
|
+
end
|
74
|
+
|
75
|
+
@sock = UNIXSocket.new(device)
|
76
|
+
if Fcntl.const_defined? :F_SETFD
|
77
|
+
@sock.fcntl(Fcntl::F_SETFD, Fcntl::FD_CLOEXEC)
|
78
|
+
end
|
79
|
+
|
80
|
+
msg = "version: 1\ntimeout: #{timeout}\nsignal: #{signal}"
|
81
|
+
if info.nil?
|
82
|
+
msg << "\n\n"
|
83
|
+
else
|
84
|
+
info.gsub!(/\n/, '_')
|
85
|
+
msg << "\ninfo: #{info}\n\n"
|
86
|
+
end
|
87
|
+
|
88
|
+
safe_write(@sock, msg)
|
89
|
+
if safe_read(@sock, 256) == "ok\n"
|
90
|
+
if block_given?
|
91
|
+
begin
|
92
|
+
yield(self)
|
93
|
+
ensure
|
94
|
+
@sock.close
|
95
|
+
end
|
96
|
+
end
|
97
|
+
return self
|
98
|
+
else
|
99
|
+
@sock.close
|
100
|
+
# Probably not the best error, but it matches the C library.
|
101
|
+
raise Errno::EPERM
|
102
|
+
end
|
103
|
+
end
|
104
|
+
|
105
|
+
# Send a heartbeat to watchcatd, telling it we're still alive.
|
106
|
+
def heartbeat
|
107
|
+
safe_write(@sock, '.')
|
108
|
+
return nil
|
109
|
+
end
|
110
|
+
|
111
|
+
# Close communication with watchcatd.
|
112
|
+
def close
|
113
|
+
begin
|
114
|
+
@sock.close
|
115
|
+
rescue Errno::EINTR
|
116
|
+
retry
|
117
|
+
end
|
118
|
+
return nil
|
119
|
+
end
|
120
|
+
|
121
|
+
private
|
122
|
+
|
123
|
+
def safe_write(fd, buf)
|
124
|
+
act = Signal.trap('PIPE', 'IGN')
|
125
|
+
begin
|
126
|
+
fd.syswrite(buf)
|
127
|
+
rescue Errno::EINTR
|
128
|
+
retry
|
129
|
+
end
|
130
|
+
Signal.trap('PIPE', act)
|
131
|
+
end
|
132
|
+
|
133
|
+
def safe_read(fd, len)
|
134
|
+
buf = ''
|
135
|
+
begin
|
136
|
+
buf = fd.sysread(len)
|
137
|
+
rescue Errno::EINTR
|
138
|
+
retry
|
139
|
+
end
|
140
|
+
return buf
|
141
|
+
end
|
142
|
+
end
|
metadata
ADDED
@@ -0,0 +1,57 @@
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
2
|
+
name: ruby-watchcat-pure
|
3
|
+
version: !ruby/object:Gem::Version
|
4
|
+
version: 1.0.0
|
5
|
+
platform: ruby
|
6
|
+
authors:
|
7
|
+
- Andre Nathan
|
8
|
+
autorequire:
|
9
|
+
bindir: bin
|
10
|
+
cert_chain: []
|
11
|
+
|
12
|
+
date: 2008-08-06 00:00:00 -03:00
|
13
|
+
default_executable:
|
14
|
+
dependencies: []
|
15
|
+
|
16
|
+
description: Ruby/Watchcat-Pure is a pure-ruby implementation of libwatchcat for the development of watchcatd-aware applications.
|
17
|
+
email: andre@digirati.com.br
|
18
|
+
executables: []
|
19
|
+
|
20
|
+
extensions: []
|
21
|
+
|
22
|
+
extra_rdoc_files: []
|
23
|
+
|
24
|
+
files:
|
25
|
+
- README
|
26
|
+
- lib/watchcat.rb
|
27
|
+
- examples/example.rb
|
28
|
+
has_rdoc: true
|
29
|
+
homepage: http://watchcat.rubyforge.org
|
30
|
+
post_install_message:
|
31
|
+
rdoc_options:
|
32
|
+
- --title
|
33
|
+
- Ruby/Watchcat--main
|
34
|
+
- README
|
35
|
+
require_paths:
|
36
|
+
- lib
|
37
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
38
|
+
requirements:
|
39
|
+
- - ">="
|
40
|
+
- !ruby/object:Gem::Version
|
41
|
+
version: "0"
|
42
|
+
version:
|
43
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
44
|
+
requirements:
|
45
|
+
- - ">="
|
46
|
+
- !ruby/object:Gem::Version
|
47
|
+
version: "0"
|
48
|
+
version:
|
49
|
+
requirements:
|
50
|
+
- watchcatd
|
51
|
+
rubyforge_project: ruby-watchcat
|
52
|
+
rubygems_version: 1.0.0
|
53
|
+
signing_key:
|
54
|
+
specification_version: 2
|
55
|
+
summary: A pure-ruby implementation of libwatchcat
|
56
|
+
test_files: []
|
57
|
+
|