terminator 0.4.3 → 0.4.4

Sign up to get free protection for your applications and to get access to all the features.
data/README CHANGED
@@ -2,10 +2,10 @@ NAME
2
2
  Terminator
3
3
 
4
4
  SYNOPSIS
5
- An external timeout mechanism based on processes and signals. Safe on
6
- windows. Safe for system calls. Safe for minors. but not very safe
7
- for misbehaving, downtrodden zombied out processes.
8
-
5
+ An external timeout mechanism based on processes and signals. Safe for
6
+ system calls. Safe for minors. but not very safe for misbehaving,
7
+ downtrodden zombied out processes.
8
+
9
9
  DESCRIPTION
10
10
  Terminator is a solution to the problem of 'how am I meant to kill a
11
11
  system call in Ruby!?'
@@ -43,6 +43,16 @@ HOW IT WORKS
43
43
 
44
44
  So really it is a race of who is going to win?
45
45
 
46
+ Word of warning though. Terminator is not subtle. Don't expect it to split
47
+ hairs. Trying to give a process that takes about 1 second to complete, a
48
+ 2 second terminator... well... odds are 50/50 on who is going to make it.
49
+
50
+ If you have a 1 second process, give it 3 seconds to complete. Arnie doesn't
51
+ much care for casualties of war.
52
+
53
+ Another word of warning, if using Terminator inside a loop, it is possible
54
+ to exceed your open file limit. I have safely tested looping 1000 times
55
+
46
56
  INSTALL
47
57
  gem install terminator
48
58
 
@@ -52,7 +62,13 @@ URIS
52
62
 
53
63
  HISTORY
54
64
  0.4.2
55
- initial version
65
+ * initial version (ara)
66
+ 0.4.3
67
+ * added some extra specs and test cases (mikel)
68
+ 0.4.4
69
+ * made terminator loop safe. 1000.times { Terminator.timeout(1) do true; end }
70
+ now works (mikel)
71
+ * added more test cases (mikel)
56
72
 
57
73
  AUTHORS
58
74
  ara.t.howard - ara.t.howard@gmail.com
@@ -128,3 +144,26 @@ SAMPLES
128
144
  signaled @ 1221026177
129
145
  woke up @ 1221026178
130
146
 
147
+
148
+ <========< samples/e.rb >========>
149
+
150
+ ~ > cat samples/e.rb
151
+
152
+ require 'terminator'
153
+
154
+ puts "Looping 1000 times on the terminator..."
155
+ success = false
156
+ 1.upto(1000) do |i|
157
+ success = false
158
+ Terminator.terminate(1) do
159
+ success = true
160
+ end
161
+ print "\b\b\b#{i}"
162
+ end
163
+ puts "\nI was successful" if success
164
+
165
+ ~ > ruby samples/e.rb
166
+
167
+ Looping 1000 times on the terminator...
168
+ 1000
169
+ I was successful
@@ -0,0 +1,307 @@
1
+ <?xml version="1.0" encoding="iso-8859-1"?>
2
+ <!DOCTYPE html
3
+ PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN"
4
+ "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
5
+
6
+ <html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en" lang="en">
7
+ <head>
8
+ <title>Module: Terminator</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
+ <table class="header-table">
51
+ <tr class="top-aligned-row">
52
+ <td><strong>Module</strong></td>
53
+ <td class="class-name-in-header">Terminator</td>
54
+ </tr>
55
+ <tr class="top-aligned-row">
56
+ <td><strong>In:</strong></td>
57
+ <td>
58
+ <a href="../files/lib/terminator_rb.html">
59
+ lib/terminator.rb
60
+ </a>
61
+ <br />
62
+ </td>
63
+ </tr>
64
+
65
+ </table>
66
+ </div>
67
+ <!-- banner header -->
68
+
69
+ <div id="bodyContent">
70
+
71
+
72
+
73
+ <div id="contextContent">
74
+
75
+ <div id="description">
76
+ <h1><a href="Terminator.html">Terminator</a></h1>
77
+ <h2>Synopsis</h2>
78
+ <p>
79
+ An external timeout mechanism based on processes and signals. Safe for
80
+ system calls. Safe for minors. but not very safe for misbehaving,
81
+ downtrodden zombied out processes.
82
+ </p>
83
+ <h2>Description</h2>
84
+ <p>
85
+ <a href="Terminator.html">Terminator</a> is a solution to the problem of
86
+ &#8216;how am I meant to kill a system call in Ruby!?&#8217;
87
+ </p>
88
+ <p>
89
+ Ruby (at least MRI) uses green threads to &quot;multitask&quot;. This means
90
+ that there is really only ever one ruby process running which then splits
91
+ up it&#8216;s processor time between all of it&#8216;s threads internally.
92
+ </p>
93
+ <p>
94
+ The processor then only has to deal with one ruby process and the ruby
95
+ process deals with all it&#8216;s threads. There are pros and cons to this
96
+ method, but that is not the point of this library.
97
+ </p>
98
+ <p>
99
+ The point is, that if you make a system call to an external resource from
100
+ ruby, then the kernel will go and make that call for ruby and NOT COME BACK
101
+ to ruby until that system call completes or fails. This can take a very
102
+ long time and is why your feeble attempts at using ruby&#8216;s internal
103
+ &quot;Timeout&quot; command has failed miserably at timing out your
104
+ external web service, database or network connections.
105
+ </p>
106
+ <p>
107
+ You see, Ruby just doesn&#8216;t get a chance to do anything as the kernel
108
+ goes &quot;I&#8216;m not going to talk to you again until your system calls
109
+ complete&quot;. Sort of a no win situation for Ruby.
110
+ </p>
111
+ <p>
112
+ That&#8216;s where <a href="Terminator.html">Terminator</a> comes in. Like
113
+ Arnie, he will come back. No matter what, and complete his mission, unless
114
+ he gets aborted before his timeout, you can trust <a
115
+ href="Terminator.html">Terminator</a> to thoroughly and without remorse,
116
+ nuke your misbehaving and timing out ruby processes efficiently, and
117
+ quickly.
118
+ </p>
119
+ <h2>How it Works</h2>
120
+ <p>
121
+ Basically we create a new terminator ruby process, separate to the existing
122
+ running ruby process that has a simple command of sleep for x seconds, and
123
+ then do a process TERM on the PID of the original ruby process that created
124
+ it.
125
+ </p>
126
+ <p>
127
+ If your process finishes before the timeout, it will kill the <a
128
+ href="Terminator.html">Terminator</a> first.
129
+ </p>
130
+ <p>
131
+ So really it is a race of who is going to win?
132
+ </p>
133
+ <p>
134
+ Word of warning though. <a href="Terminator.html">Terminator</a> is not
135
+ subtle. Don&#8216;t expect it to split hairs. Trying to give a process that
136
+ takes about 1 second to complete, a 2 second terminator&#8230; well&#8230;
137
+ odds are 50/50 on who is going to make it.
138
+ </p>
139
+ <p>
140
+ If you have a 1 second process, give it 3 seconds to complete. Arnie
141
+ doesn&#8216;t much care for casualties of war.
142
+ </p>
143
+ <p>
144
+ Another word of warning, if using <a href="Terminator.html">Terminator</a>
145
+ inside a loop, it is possible to exceed your open file limit. I have safely
146
+ tested looping 1000 times
147
+ </p>
148
+ <h2>URIS</h2>
149
+ <ul>
150
+ <li><a href="http://codeforpeople.com/lib/ruby">codeforpeople.com/lib/ruby</a>
151
+
152
+ </li>
153
+ <li><a
154
+ href="http://rubyforge.org/projects/codeforpeople">rubyforge.org/projects/codeforpeople</a>
155
+
156
+ </li>
157
+ </ul>
158
+ <h2>Usage</h2>
159
+ <p>
160
+ The terminator library is simple to use.
161
+ </p>
162
+ <pre>
163
+ require 'terminator'
164
+ Terminator.terminate(1) do
165
+ sleep 4
166
+ puts(&quot;I will never print&quot;)
167
+ end
168
+ #=&gt; Terminator::Error: Timeout out after 1s
169
+ </pre>
170
+ <p>
171
+ The above code snippet will raise a <a
172
+ href="Terminator/Error.html">Terminator::Error</a> as the
173
+ terminator&#8216;s timeout is 2 seconds and the block will take at least 4
174
+ to complete.
175
+ </p>
176
+ <p>
177
+ You can put error handling in with a simple begin / rescue block:
178
+ </p>
179
+ <pre>
180
+ require 'terminator'
181
+ begin
182
+ Terminator.terminate(1) do
183
+ sleep 4
184
+ puts(&quot;I will never print&quot;)
185
+ end
186
+ rescue
187
+ puts(&quot;I got terminated, but rescued myself.&quot;)
188
+ end
189
+ #=&gt; I got terminated, but rescued myself.
190
+ </pre>
191
+ <p>
192
+ The standard action on termination is to raise a <a
193
+ href="Terminator/Error.html">Terminator::Error</a>, however, this is just
194
+ an anonymous object that is called, so you can pass your own trap handling
195
+ by giving the terminator a lambda as an argument.
196
+ </p>
197
+ <pre>
198
+ require 'terminator'
199
+ custom_trap = lambda { eval(&quot;raise(RuntimeError, 'Oops... I failed...')&quot;) }
200
+ Terminator.terminate(:seconds =&gt; 1, :trap =&gt; custom_trap) do
201
+ sleep 10
202
+ end
203
+ #=&gt; RuntimeError: (eval):1:in `irb_binding': Oops... I failed...
204
+ </pre>
205
+
206
+ </div>
207
+
208
+
209
+ </div>
210
+
211
+ <div id="method-list">
212
+ <h3 class="section-bar">Methods</h3>
213
+
214
+ <div class="name-list">
215
+ <a href="#M000001">terminate</a>&nbsp;&nbsp;
216
+ </div>
217
+ </div>
218
+
219
+ </div>
220
+
221
+
222
+ <!-- if includes -->
223
+
224
+ <div id="section">
225
+
226
+ <div id="class-list">
227
+ <h3 class="section-bar">Classes and Modules</h3>
228
+
229
+ Class <a href="Terminator/Error.html" class="link">Terminator::Error</a><br />
230
+
231
+ </div>
232
+
233
+ <div id="constants-list">
234
+ <h3 class="section-bar">Constants</h3>
235
+
236
+ <div class="name-list">
237
+ <table summary="Constants">
238
+ <tr class="top-aligned-row context-row">
239
+ <td class="context-item-name">Version</td>
240
+ <td>=</td>
241
+ <td class="context-item-value">'0.4.4'</td>
242
+ </tr>
243
+ </table>
244
+ </div>
245
+ </div>
246
+
247
+
248
+
249
+
250
+
251
+
252
+ <!-- if method_list -->
253
+ <div id="methods">
254
+ <h3 class="section-bar">Public Instance methods</h3>
255
+
256
+ <div id="method-M000001" class="method-detail">
257
+ <a name="M000001"></a>
258
+
259
+ <div class="method-heading">
260
+ <a href="Terminator.src/M000001.html" target="Code" class="method-signature"
261
+ onclick="popupCode('Terminator.src/M000001.html');return false;">
262
+ <span class="method-name">terminate</span><span class="method-args">(options = {})</span>
263
+ </a>
264
+ </div>
265
+
266
+ <div class="method-description">
267
+ <p>
268
+ <a href="Terminator.html#M000001">Terminator.terminate</a> has two ways you
269
+ can call it. You can either just specify:
270
+ </p>
271
+ <pre>
272
+ Terminator.terminate(seconds) { code_to_execute }
273
+ </pre>
274
+ <p>
275
+ where seconds is an integer number greater than or equal to 1. If you pass
276
+ a float in on seconds, <a href="Terminator.html">Terminator</a> will call
277
+ to_i on it and convert it to an integer. This is because <a
278
+ href="Terminator.html">Terminator</a> is not a precise tool, due to it
279
+ calling a new ruby instance, and spawning a new process, relying on split
280
+ second accuracy is a folly.
281
+ </p>
282
+ <p>
283
+ If you want to pass in the block, please use:
284
+ </p>
285
+ <pre>
286
+ Terminator.terminate(:seconds =&gt; seconds, :trap =&gt; block) { code_to_execute }
287
+ </pre>
288
+ <p>
289
+ Where block is an anonymous method that gets called when the timeout
290
+ occurs.
291
+ </p>
292
+ </div>
293
+ </div>
294
+
295
+
296
+ </div>
297
+
298
+
299
+ </div>
300
+
301
+
302
+ <div id="validator-badges">
303
+ <p><small><a href="http://validator.w3.org/check/referer">[Validate]</a></small></p>
304
+ </div>
305
+
306
+ </body>
307
+ </html>
@@ -0,0 +1,35 @@
1
+ <?xml version="1.0" encoding="iso-8859-1"?>
2
+ <!DOCTYPE html
3
+ PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN"
4
+ "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
5
+
6
+ <html>
7
+ <head>
8
+ <title>terminate (Terminator)</title>
9
+ <meta http-equiv="Content-Type" content="text/html; charset=iso-8859-1" />
10
+ <link rel="stylesheet" href="../.././rdoc-style.css" type="text/css" media="screen" />
11
+ </head>
12
+ <body class="standalone-code">
13
+ <pre><span class="ruby-comment cmt"># File lib/terminator.rb, line 120</span>
14
+ <span class="ruby-keyword kw">def</span> <span class="ruby-identifier">terminate</span> <span class="ruby-identifier">options</span> = {}, <span class="ruby-operator">&amp;</span><span class="ruby-identifier">block</span>
15
+ <span class="ruby-identifier">options</span> = { <span class="ruby-identifier">:seconds</span> =<span class="ruby-operator">&gt;</span> <span class="ruby-constant">Float</span>(<span class="ruby-identifier">options</span>).<span class="ruby-identifier">to_i</span> } <span class="ruby-keyword kw">unless</span> <span class="ruby-constant">Hash</span> <span class="ruby-operator">===</span> <span class="ruby-identifier">options</span>
16
+
17
+ <span class="ruby-identifier">seconds</span> = <span class="ruby-identifier">getopt</span> <span class="ruby-identifier">:seconds</span>, <span class="ruby-identifier">options</span>
18
+
19
+ <span class="ruby-identifier">raise</span> <span class="ruby-operator">::</span><span class="ruby-constant">Terminator</span><span class="ruby-operator">::</span><span class="ruby-constant">Error</span>, <span class="ruby-value str">&quot;Time to kill must be at least 1 second&quot;</span> <span class="ruby-keyword kw">unless</span> <span class="ruby-identifier">seconds</span> <span class="ruby-operator">&gt;=</span> <span class="ruby-value">1</span>
20
+
21
+ <span class="ruby-identifier">trap</span> = <span class="ruby-identifier">getopt</span> <span class="ruby-identifier">:trap</span>, <span class="ruby-identifier">options</span>, <span class="ruby-identifier">lambda</span>{ <span class="ruby-identifier">eval</span>(<span class="ruby-node">&quot;raise(::Terminator::Error, 'Timeout out after #{ seconds }s')&quot;</span>, <span class="ruby-identifier">block</span>) }
22
+
23
+ <span class="ruby-identifier">handler</span> = <span class="ruby-constant">Signal</span>.<span class="ruby-identifier">trap</span>(<span class="ruby-identifier">signal</span>, <span class="ruby-operator">&amp;</span><span class="ruby-identifier">trap</span>)
24
+
25
+ <span class="ruby-identifier">terminator_pid</span> = <span class="ruby-identifier">plot_to_kill</span> <span class="ruby-identifier">pid</span>, <span class="ruby-identifier">:in</span> =<span class="ruby-operator">&gt;</span> <span class="ruby-identifier">seconds</span>, <span class="ruby-identifier">:with</span> =<span class="ruby-operator">&gt;</span> <span class="ruby-identifier">signal</span>
26
+
27
+ <span class="ruby-keyword kw">begin</span>
28
+ <span class="ruby-identifier">block</span>.<span class="ruby-identifier">call</span>
29
+ <span class="ruby-identifier">nuke_terminator</span>(<span class="ruby-identifier">terminator_pid</span>)
30
+ <span class="ruby-keyword kw">ensure</span>
31
+ <span class="ruby-constant">Signal</span>.<span class="ruby-identifier">trap</span>(<span class="ruby-identifier">signal</span>, <span class="ruby-identifier">handler</span>)
32
+ <span class="ruby-keyword kw">end</span>
33
+ <span class="ruby-keyword kw">end</span></pre>
34
+ </body>
35
+ </html>
@@ -0,0 +1,111 @@
1
+ <?xml version="1.0" encoding="iso-8859-1"?>
2
+ <!DOCTYPE html
3
+ PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN"
4
+ "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
5
+
6
+ <html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en" lang="en">
7
+ <head>
8
+ <title>Class: Terminator::Error</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
+ <table class="header-table">
51
+ <tr class="top-aligned-row">
52
+ <td><strong>Class</strong></td>
53
+ <td class="class-name-in-header">Terminator::Error</td>
54
+ </tr>
55
+ <tr class="top-aligned-row">
56
+ <td><strong>In:</strong></td>
57
+ <td>
58
+ <a href="../../files/lib/terminator_rb.html">
59
+ lib/terminator.rb
60
+ </a>
61
+ <br />
62
+ </td>
63
+ </tr>
64
+
65
+ <tr class="top-aligned-row">
66
+ <td><strong>Parent:</strong></td>
67
+ <td>
68
+ ::StandardError
69
+ </td>
70
+ </tr>
71
+ </table>
72
+ </div>
73
+ <!-- banner header -->
74
+
75
+ <div id="bodyContent">
76
+
77
+
78
+
79
+ <div id="contextContent">
80
+
81
+
82
+
83
+ </div>
84
+
85
+
86
+ </div>
87
+
88
+
89
+ <!-- if includes -->
90
+
91
+ <div id="section">
92
+
93
+
94
+
95
+
96
+
97
+
98
+
99
+
100
+ <!-- if method_list -->
101
+
102
+
103
+ </div>
104
+
105
+
106
+ <div id="validator-badges">
107
+ <p><small><a href="http://validator.w3.org/check/referer">[Validate]</a></small></p>
108
+ </div>
109
+
110
+ </body>
111
+ </html>