slave 0.2.0 → 1.0.0

Sign up to get free protection for your applications and to get access to all the features.
data/README CHANGED
@@ -12,49 +12,49 @@ SYNOPSIS
12
12
 
13
13
  obj = AnyClass::new
14
14
 
15
- slave = Slave::new obj
15
+ slave = Slave::new 'object' => obj
16
16
 
17
17
  p slave.object # handle on drb object
18
18
  p slave.uri # uri of the drb object
19
19
  p slave.socket # unix domain socket path for drb object
20
20
  p slave.psname # title shown in ps/top
21
21
 
22
- other usage:
23
-
24
- set the pulse_rate used for the Heartbeat
25
-
26
- slave = Slave::new MyClass::new, 'pulse_rate' => 10
22
+ slaves may be configured via the environment, the Slave class, or via the
23
+ ctor for object itself. attributes which may be configured include
27
24
 
28
- same
25
+ * socket_creation_attempts
26
+ * pulse_rate
27
+ * psname
28
+ * debug
29
+ * dumped
29
30
 
30
- Slave::pulse_rate = 10
31
- slave = Slave::new MyClass::new
31
+ URIS
32
32
 
33
- same
33
+ http://rubyforge.org/projects/codeforpeople/
34
+ http://codeforpeople.com/lib/ruby/slave
34
35
 
35
- ENV['SLAVE_PULSE_RATE'] = 10
36
- slave = Slave::new MyClass::new
36
+ HISTORY
37
37
 
38
- to avoid having a copy of the object in both the parent and child use the
39
- block form
38
+ THIS RELEASE IS !! NOT !! BACKWARD COMPATIBLE. NOTE NEW CTOR SYNTAX.
40
39
 
41
- slave = Slave::new{ Server::new } # copy only in child!
42
- server = slave.object
40
+ 1.0.0:
43
41
 
44
- if both an object AND a block are passed the object is passed to the block
45
- in the child process
42
+ - detach method also sets up at_exit handler. extra protection from
43
+ zombies.
46
44
 
47
- slave = Slave::new(Server::new){|server| p 'in child!' }
45
+ - ezra zygmuntowicz asked for a feature whereby a parent could be notified
46
+ when a child exited. obviously such a mechanism should be both async
47
+ and sync. to accomplish this the wait method was extended to support a
48
+ callback with is either sync or async
48
49
 
49
- slaves may be configured via the environment, the Slave class, or via the
50
- ctor for object itself. attributes which may be configured include
50
+ slave = Server.new{ Server.new }
51
51
 
52
- * socket_creation_attempts
53
- * pulse_rate
54
- * psname
55
- * debug
52
+ slave.wait and puts 'this is sync!'
56
53
 
57
- HISTORY
54
+ slave.wait(:non_block=>true){ 'this is async!' }
55
+
56
+ - patch to getval from skaar<skaar@waste.org>. the impl dropped opts
57
+ delgating to the class method from the instance one.
58
58
 
59
59
  0.2.0:
60
60
  incorporated joel vanderWerf's patch such that, if no object is passed the
@@ -77,3 +77,141 @@ HISTORY
77
77
 
78
78
  0.0.0:
79
79
  - initial version
80
+
81
+ SAMPLES
82
+
83
+ <========< samples/a.rb >========>
84
+
85
+ ~ > cat samples/a.rb
86
+
87
+ require 'slave'
88
+ #
89
+ # simple usage is simply to stand up a server object as a slave. you do not
90
+ # need to wait for the server, join it, etc. it will die when the parent
91
+ # process dies - even under 'kill -9' conditions
92
+ #
93
+ class Server
94
+ def add_two n
95
+ n + 2
96
+ end
97
+ end
98
+
99
+ slave = Slave.new :object => Server.new
100
+ server = slave.object
101
+
102
+ p server.add_two(40) #=> 42
103
+
104
+ ~ > ruby samples/a.rb
105
+
106
+ 42
107
+
108
+
109
+ <========< samples/b.rb >========>
110
+
111
+ ~ > cat samples/b.rb
112
+
113
+ require 'slave'
114
+ #
115
+ # if certain operations need to take place in the child only a block can be
116
+ # used
117
+ #
118
+ class Server
119
+ def connect_to_db
120
+ "we only want to do this in the child process!"
121
+ @connection = :postgresql
122
+ end
123
+ attr :connection
124
+ end
125
+
126
+ slave = Slave.new('object' => Server.new){|s| s.connect_to_db}
127
+
128
+ server = slave.object
129
+
130
+ p server.connection #=> :postgresql
131
+ #
132
+ # errors in the child are detected and raised in the parent
133
+ #
134
+ slave = Slave.new('object' => Server.new){|s| s.typo} #=> raises an error!
135
+
136
+ ~ > ruby samples/b.rb
137
+
138
+ :postgresql
139
+ ./lib/slave.rb:276:in `initialize': undefined method `typo' for #<Server:0xb7573350> (NoMethodError)
140
+ from samples/b.rb:22:in `new'
141
+ from samples/b.rb:22
142
+
143
+
144
+ <========< samples/c.rb >========>
145
+
146
+ ~ > cat samples/c.rb
147
+
148
+ require 'slave'
149
+ #
150
+ # if no slave object is given the block itself is used to contruct it
151
+ #
152
+ class Server
153
+ def initialize
154
+ "this is run only in the child"
155
+ @pid = Process.pid
156
+ end
157
+ attr 'pid'
158
+ end
159
+
160
+ slave = Slave.new{ Server.new }
161
+ server = slave.object
162
+
163
+ p Process.pid
164
+ p server.pid # not going to be the same as parents!
165
+ #
166
+ # errors are still detected though
167
+ #
168
+ slave = Slave.new{ fubar } # raises error in parent
169
+
170
+ ~ > ruby samples/c.rb
171
+
172
+ 12244
173
+ 12245
174
+ ./lib/slave.rb:276:in `initialize': undefined local variable or method `fubar' for main:Object (NameError)
175
+ from samples/c.rb:21:in `new'
176
+ from samples/c.rb:21
177
+
178
+
179
+ <========< samples/d.rb >========>
180
+
181
+ ~ > cat samples/d.rb
182
+
183
+ require 'slave'
184
+ #
185
+ # at_exit hanlders are handled correctly in both child and parent
186
+ #
187
+ at_exit{ p 'parent' }
188
+ slave = Slave.new{ at_exit{ p 'child' }; 'the server is this string' }
189
+ #
190
+ # this will print 'child', then 'parent'
191
+ #
192
+
193
+ ~ > ruby samples/d.rb
194
+
195
+ "parent"
196
+
197
+
198
+ <========< samples/e.rb >========>
199
+
200
+ ~ > cat samples/e.rb
201
+
202
+ require 'slave'
203
+ #
204
+ # slaves never outlive their parent. if the parent exits, even under kill -9,
205
+ # the child will die.
206
+ #
207
+ slave = Slave.new{ at_exit{ p 'child' }; 'the server is this string' }
208
+
209
+ Process.kill brutal=9, the_parent_pid=Process.pid
210
+ #
211
+ # even though parent dies a nasty death the child will still print 'child'
212
+ #
213
+
214
+ ~ > ruby samples/e.rb
215
+
216
+ "child"
217
+
data/README.tmpl ADDED
@@ -0,0 +1,83 @@
1
+ SYNOPSIS
2
+
3
+ the Slave class forks a process and starts a drb server in the child using
4
+ any object as the server. the process is detached so it is not required
5
+ (nor possible) to wait on the child pid. a Heartbeat is set up between the
6
+ parent and child processes so that the child will exit of the parent exits
7
+ for any reason - preventing orphaned slaves from running indefinitely. the
8
+ purpose of Slaves is to be able to easily set up a collection of objects
9
+ communicating via drb protocols instead of having to use IPC.
10
+
11
+ typical usage:
12
+
13
+ obj = AnyClass::new
14
+
15
+ slave = Slave::new 'object' => obj
16
+
17
+ p slave.object # handle on drb object
18
+ p slave.uri # uri of the drb object
19
+ p slave.socket # unix domain socket path for drb object
20
+ p slave.psname # title shown in ps/top
21
+
22
+ slaves may be configured via the environment, the Slave class, or via the
23
+ ctor for object itself. attributes which may be configured include
24
+
25
+ * socket_creation_attempts
26
+ * pulse_rate
27
+ * psname
28
+ * debug
29
+ * dumped
30
+
31
+ URIS
32
+
33
+ http://rubyforge.org/projects/codeforpeople/
34
+ http://codeforpeople.com/lib/ruby/slave
35
+
36
+ HISTORY
37
+
38
+ THIS RELEASE IS !! NOT !! BACKWARD COMPATIBLE. NOTE NEW CTOR SYNTAX.
39
+
40
+ 1.0.0:
41
+
42
+ - detach method also sets up at_exit handler. extra protection from
43
+ zombies.
44
+
45
+ - ezra zygmuntowicz asked for a feature whereby a parent could be notified
46
+ when a child exited. obviously such a mechanism should be both async
47
+ and sync. to accomplish this the wait method was extended to support a
48
+ callback with is either sync or async
49
+
50
+ slave = Server.new{ Server.new }
51
+
52
+ slave.wait and puts 'this is sync!'
53
+
54
+ slave.wait(:non_block=>true){ 'this is async!' }
55
+
56
+ - patch to getval from skaar<skaar@waste.org>. the impl dropped opts
57
+ delgating to the class method from the instance one.
58
+
59
+ 0.2.0:
60
+ incorporated joel vanderWerf's patch such that, if no object is passed the
61
+ block is used to create one ONLY in the child. this avoids having a copy
62
+ in both parent and child is that needs to be avoided due to, for instance,
63
+ resource consumption.
64
+
65
+
66
+ 0.0.1:
67
+ - patch from Logan Capaldo adds block form to slave new, block is run in the
68
+ child
69
+
70
+ - added a few more samples/*
71
+
72
+ - added Slave#wait
73
+
74
+ - added status information to slaves
75
+
76
+ - added close-on-exec flag to pipes in parent process
77
+
78
+ 0.0.0:
79
+ - initial version
80
+
81
+ SAMPLES
82
+
83
+ @samples
@@ -0,0 +1,117 @@
1
+ <?xml version="1.0" encoding="iso-8859-1"?>
2
+ <!DOCTYPE html
3
+ PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN"
4
+ "DTD/xhtml1-transitional.dtd">
5
+
6
+ <html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en" lang="en">
7
+ <head>
8
+ <title>Class: (@object = Object.new)</title>
9
+ <meta http-equiv="Content-Type" content="text/html; charset=iso-8859-1" />
10
+ <meta http-equiv="Content-Script-Type" content="text/javascript" />
11
+ <link rel="stylesheet" href=".././rdoc-style.css" type="text/css" media="screen" />
12
+ <script type="text/javascript">
13
+ // <![CDATA[
14
+
15
+ function popupCode( url ) {
16
+ window.open(url, "Code", "resizable=yes,scrollbars=yes,toolbar=no,status=no,height=150,width=400")
17
+ }
18
+
19
+ function toggleCode( id ) {
20
+ if ( document.getElementById )
21
+ elem = document.getElementById( id );
22
+ else if ( document.all )
23
+ elem = eval( "document.all." + id );
24
+ else
25
+ return false;
26
+
27
+ elemStyle = elem.style;
28
+
29
+ if ( elemStyle.display != "block" ) {
30
+ elemStyle.display = "block"
31
+ } else {
32
+ elemStyle.display = "none"
33
+ }
34
+
35
+ return true;
36
+ }
37
+
38
+ // Make codeblocks hidden by default
39
+ document.writeln( "<style type=\"text/css\">div.method-source-code { display: none }</style>" )
40
+
41
+ // ]]>
42
+ </script>
43
+
44
+ </head>
45
+ <body>
46
+
47
+
48
+
49
+ <div id="classHeader">
50
+ <h1>(@object = Object.new) <sup class="type-note">(Class)</sup></h1>
51
+ <table class="header-table">
52
+ <tr class="top-aligned-row">
53
+ <td><strong>In:</strong></td>
54
+ <td>
55
+ <a href="../files/lib/slave_rb.html">
56
+ lib/slave.rb
57
+ </a>
58
+ <br />
59
+ </td>
60
+ </tr>
61
+
62
+ </table>
63
+ </div>
64
+ <!-- banner header -->
65
+
66
+ <div id="bodyContent">
67
+
68
+
69
+ <div id="contextContent">
70
+ <div id="diagram">
71
+ <map name="map">
72
+ <area shape="RECT" coords="27,98,99,50" href="Slave.html" alt="Slave">
73
+ <area shape="RECT" coords="16,108,205,16" href=".././classes" alt="(@object = Object.new).html (@object = Object.new)">
74
+ </map>
75
+ <img src="../dot/f_1.jpg" usemap="#map" border=0 alt="TopLevel">
76
+ </div>
77
+
78
+
79
+
80
+
81
+
82
+
83
+
84
+ <div id="attribute-list">
85
+ <h2 class="section-bar">Attributes</h2>
86
+
87
+ <div class="name-list">
88
+ <table>
89
+ <tr class="top-aligned-row context-row">
90
+ <td class="context-item-name">__slave_object_failure__</td>
91
+ <td class="context-item-value">&nbsp;[RW]&nbsp;</td>
92
+ <td class="context-item-desc"></td>
93
+ </tr>
94
+ </table>
95
+ </div>
96
+ </div>
97
+
98
+
99
+ </div>
100
+
101
+
102
+
103
+ <!-- if includes -->
104
+
105
+
106
+ <!-- if method_list -->
107
+
108
+
109
+ </div>
110
+
111
+
112
+ <div id="validator-badges">
113
+ <p><small><a href="http://validator.w3.org/check/referer">[Validate]</a></small></p>
114
+ </div>
115
+
116
+ </body>
117
+ </html>
@@ -0,0 +1,117 @@
1
+ <?xml version="1.0" encoding="iso-8859-1"?>
2
+ <!DOCTYPE html
3
+ PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN"
4
+ "DTD/xhtml1-transitional.dtd">
5
+
6
+ <html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en" lang="en">
7
+ <head>
8
+ <title>Class: (o = Object.new)</title>
9
+ <meta http-equiv="Content-Type" content="text/html; charset=iso-8859-1" />
10
+ <meta http-equiv="Content-Script-Type" content="text/javascript" />
11
+ <link rel="stylesheet" href=".././rdoc-style.css" type="text/css" media="screen" />
12
+ <script type="text/javascript">
13
+ // <![CDATA[
14
+
15
+ function popupCode( url ) {
16
+ window.open(url, "Code", "resizable=yes,scrollbars=yes,toolbar=no,status=no,height=150,width=400")
17
+ }
18
+
19
+ function toggleCode( id ) {
20
+ if ( document.getElementById )
21
+ elem = document.getElementById( id );
22
+ else if ( document.all )
23
+ elem = eval( "document.all." + id );
24
+ else
25
+ return false;
26
+
27
+ elemStyle = elem.style;
28
+
29
+ if ( elemStyle.display != "block" ) {
30
+ elemStyle.display = "block"
31
+ } else {
32
+ elemStyle.display = "none"
33
+ }
34
+
35
+ return true;
36
+ }
37
+
38
+ // Make codeblocks hidden by default
39
+ document.writeln( "<style type=\"text/css\">div.method-source-code { display: none }</style>" )
40
+
41
+ // ]]>
42
+ </script>
43
+
44
+ </head>
45
+ <body>
46
+
47
+
48
+
49
+ <div id="classHeader">
50
+ <h1>(o = Object.new) <sup class="type-note">(Class)</sup></h1>
51
+ <table class="header-table">
52
+ <tr class="top-aligned-row">
53
+ <td><strong>In:</strong></td>
54
+ <td>
55
+ <a href="../files/lib/slave_rb.html">
56
+ lib/slave.rb
57
+ </a>
58
+ <br />
59
+ </td>
60
+ </tr>
61
+
62
+ </table>
63
+ </div>
64
+ <!-- banner header -->
65
+
66
+ <div id="bodyContent">
67
+
68
+
69
+ <div id="contextContent">
70
+ <div id="diagram">
71
+ <map name="map">
72
+ <area shape="RECT" coords="123,98,195,50" href="Slave.html" alt="Slave">
73
+ <area shape="RECT" coords="16,108,205,16" href=".././classes" alt="(o = Object.new).html (o = Object.new)">
74
+ </map>
75
+ <img src="../dot/f_1.jpg" usemap="#map" border=0 alt="TopLevel">
76
+ </div>
77
+
78
+
79
+
80
+
81
+
82
+
83
+
84
+ <div id="attribute-list">
85
+ <h2 class="section-bar">Attributes</h2>
86
+
87
+ <div class="name-list">
88
+ <table>
89
+ <tr class="top-aligned-row context-row">
90
+ <td class="context-item-name">__slave_object_failure__</td>
91
+ <td class="context-item-value">&nbsp;[RW]&nbsp;</td>
92
+ <td class="context-item-desc"></td>
93
+ </tr>
94
+ </table>
95
+ </div>
96
+ </div>
97
+
98
+
99
+ </div>
100
+
101
+
102
+
103
+ <!-- if includes -->
104
+
105
+
106
+ <!-- if method_list -->
107
+
108
+
109
+ </div>
110
+
111
+
112
+ <div id="validator-badges">
113
+ <p><small><a href="http://validator.w3.org/check/referer">[Validate]</a></small></p>
114
+ </div>
115
+
116
+ </body>
117
+ </html>