cromwell 0.2.0 → 0.3.0

Sign up to get free protection for your applications and to get access to all the features.
data/README.rdoc CHANGED
@@ -175,6 +175,37 @@ When run, it goes like this:
175
175
 
176
176
  Of course, had I press <code>^C</code> right after "See you in a while...", the script would terminate after 1 second at the end of the protected block.
177
177
 
178
+ === Logging
179
+
180
+ If want to see what is going on with Cromwell or have some problems with it, you can use a logger (requires cromwell gem version >= 0.3). If Cromwell is used inside an application that already uses logging, you can use your app's logger. Or you might prefer to use a separate logger.
181
+
182
+ Cromwell uses two levels of log messages:
183
+
184
+ * <code>Logger::INFO</code> -- when a signal was caught or script is terminated.
185
+ * <code>Logger::DEBUG</code> -- all sorts of debugging information: setting up and restoring traps, calling methods and yielding block. Probably not useful for you, unless you have some problems with Cromwell or are messing with the code.
186
+
187
+ Here's an example of logger usage:
188
+
189
+ Cromwell.logger = Logger.new(STDOUT)
190
+ Cromwell.logger.level = Logger::INFO
191
+
192
+ puts 'See you in a while...'
193
+ Cromwell.protect {
194
+ sleep 10
195
+ }
196
+ puts "You're still here?"
197
+
198
+ When run, this script will log messages on <code>STDOUT</code>:
199
+
200
+ $ ruby examples/example6.rb
201
+ See you in a while...
202
+ ^CI, [2010-01-14T11:59:29.246851 #19011] INFO -- : Caught signal INT -- ignoring.
203
+ ^CI, [2010-01-14T11:59:31.558532 #19011] INFO -- : Caught signal INT -- ignoring.
204
+ ^CI, [2010-01-14T11:59:36.270395 #19011] INFO -- : Caught signal INT -- ignoring.
205
+ [ ten seconds pass... ]
206
+ I, [2010-01-14T11:59:37.872514 #19011] INFO -- : Exiting because should_exit is true
207
+ $
208
+
178
209
  == Compatibility
179
210
 
180
211
  Works for me. Tested on Mac OS X 10.4--10.6 and a little bit on Debian Linux. If it works for you too, I'd be glad to know. Cromwell's reliability depends heavily on your operating system's signals implementation reliability (which may not be very stable on some systems).
@@ -182,10 +213,13 @@ Works for me. Tested on Mac OS X 10.4--10.6 and a little bit on Debian Linux. If
182
213
  == To Do list
183
214
 
184
215
  * Allow to customize behavior after catching a signal. Right now, the script is terminated after the protected block is done (even if the signal would not normally cause script termination).
185
- * Add logger support.
186
216
 
187
217
  == Changelog
188
218
 
219
+ === 0.3
220
+
221
+ * Added logger support.
222
+
189
223
  === 0.2
190
224
 
191
225
  * Remove traps when they are not needed anymore and restore original traps.
data/VERSION CHANGED
@@ -1 +1 @@
1
- 0.2.0
1
+ 0.3.0
data/cromwell.gemspec CHANGED
@@ -5,11 +5,11 @@
5
5
 
6
6
  Gem::Specification.new do |s|
7
7
  s.name = %q{cromwell}
8
- s.version = "0.2.0"
8
+ s.version = "0.3.0"
9
9
 
10
10
  s.required_rubygems_version = Gem::Requirement.new(">= 0") if s.respond_to? :required_rubygems_version=
11
11
  s.authors = ["Przemyslaw Kowalczyk"]
12
- s.date = %q{2010-01-08}
12
+ s.date = %q{2010-01-14}
13
13
  s.description = %q{A very simple wrapper over Signal#trap method that allows you to easily protect your scripts from being killed while they are doing something that should not be interrupted (e.g. interacting with some non-transactional service) or is too costly to restart (e.g. long computations). }
14
14
  s.email = %q{szeryf@negativeiq.pl}
15
15
  s.extra_rdoc_files = [
@@ -29,6 +29,7 @@ Gem::Specification.new do |s|
29
29
  "examples/example3.rb",
30
30
  "examples/example4.rb",
31
31
  "examples/example5.rb",
32
+ "examples/example6.rb",
32
33
  "lib/cromwell.rb",
33
34
  "test/helper.rb",
34
35
  "test/test_cromwell.rb"
@@ -45,7 +46,8 @@ Gem::Specification.new do |s|
45
46
  "examples/example2.rb",
46
47
  "examples/example3.rb",
47
48
  "examples/example4.rb",
48
- "examples/example5.rb"
49
+ "examples/example5.rb",
50
+ "examples/example6.rb"
49
51
  ]
50
52
 
51
53
  if s.respond_to? :specification_version then
@@ -0,0 +1,14 @@
1
+ # ensure that we use ../lib/cromwell.rb, not the installed gem
2
+ $LOAD_PATH.unshift(File.join(File.dirname(__FILE__), '..', 'lib'))
3
+ $LOAD_PATH.unshift(File.dirname(__FILE__))
4
+ require 'cromwell'
5
+ require 'logger'
6
+
7
+ Cromwell.logger = Logger.new(STDOUT)
8
+ Cromwell.logger.level = Logger::INFO
9
+
10
+ puts 'See you in a while...'
11
+ Cromwell.protect {
12
+ sleep 10
13
+ }
14
+ puts "You're still here?"
data/lib/cromwell.rb CHANGED
@@ -1,6 +1,11 @@
1
1
  class Cromwell
2
2
  DEFAULT_SIGNAL_LIST = %w[INT TERM HUP QUIT].freeze
3
3
 
4
+ @@logger = nil
5
+ @@should_exit = false
6
+ @@protected = false
7
+ @@old_traps = {}
8
+
4
9
  class << self
5
10
  # call-seq:
6
11
  # Cromwell.protect(*signals) { ... some code ... }
@@ -14,12 +19,15 @@ class Cromwell
14
19
  # Without parameters, the code is protected from the signals in DEFAULT_SIGNAL_LIST.
15
20
  # More info and examples in README.rdoc.
16
21
  def protect *signals
22
+ debug "Protect called with [#{signals * ', '}]"
17
23
  set_up_traps(signals.empty? ? DEFAULT_SIGNAL_LIST : signals.flatten)
18
24
  @@should_exit = false
19
25
  @@protected = true
20
26
  if block_given?
21
27
  begin
28
+ debug "About to yield to block."
22
29
  yield
30
+ debug "After yielding to block."
23
31
  ensure
24
32
  unprotect
25
33
  end
@@ -33,8 +41,13 @@ class Cromwell
33
41
  # if signal was caught earlier (so any <code>at_exit</code> code will be executed).
34
42
  # The protect method calls this automatically when executed with a block.
35
43
  def unprotect
44
+ debug "Unprotect called"
36
45
  @@protected = false
37
- exit if @@should_exit
46
+ debug "should_exit? = #{@@should_exit}"
47
+ if @@should_exit
48
+ info "Exiting because should_exit is true"
49
+ exit
50
+ end
38
51
  restore_old_traps
39
52
  end
40
53
 
@@ -64,33 +77,63 @@ class Cromwell
64
77
  @@protected
65
78
  end
66
79
 
80
+ # call-seq:
81
+ # Cromwell.logger
82
+ #
83
+ # Returns logger. There is no default logger, so if you haven't set this before, it will be nil.
84
+ def logger
85
+ @@logger
86
+ end
87
+
88
+ # call-seq:
89
+ # Cromwell.logger = some_logger
90
+ #
91
+ # Set a logger for Cromwell.
92
+ def logger= logger
93
+ @@logger = logger
94
+ end
95
+
67
96
  private
68
97
  def set_up_traps signals
69
- signals.each { |signal| set_up_trap signal }
98
+ signals.each do |signal|
99
+ old_trap = set_up_trap signal
100
+ stash old_trap, signal
101
+ end
70
102
  end
71
103
 
72
104
  def set_up_trap signal
73
- old_trap = trap signal do
105
+ debug "Setting trap for #{signal}"
106
+ trap signal do
74
107
  if @@protected
108
+ info "Caught signal #{signal} -- ignoring."
75
109
  @@should_exit = true
76
110
  "IGNORE"
77
111
  else
112
+ info "Caught signal #{signal} -- exiting."
78
113
  exit
79
114
  end
80
115
  end
81
- stash old_trap, signal
82
116
  end
83
117
 
84
118
  def stash old_trap, signal
85
- @@old_traps ||= {}
119
+ debug "Stashing old trap #{old_trap} for #{signal}"
86
120
  @@old_traps[signal] = old_trap
87
121
  end
88
122
 
89
123
  def restore_old_traps
90
124
  @@old_traps.each do |signal, old_trap|
125
+ debug "Restoring old trap #{old_trap} for #{signal}"
91
126
  trap signal, old_trap
92
127
  end
93
128
  @@old_traps = {}
94
129
  end
130
+
131
+ def debug msg
132
+ @@logger.debug msg if @@logger
133
+ end
134
+
135
+ def info msg
136
+ @@logger.info msg if @@logger
137
+ end
95
138
  end
96
139
  end
@@ -115,9 +115,52 @@ class TestCromwell < Test::Unit::TestCase
115
115
  assert Cromwell.protected?
116
116
  end
117
117
 
118
+ context "with a logger" do
119
+ setup do
120
+ @log = stub :debug => true
121
+ Cromwell.logger = @log
122
+ end
123
+
124
+ teardown do
125
+ Cromwell.logger = nil
126
+ end
127
+
128
+ should "log about being called" do
129
+ @log.expects(:debug).with("Protect called with []")
130
+ Cromwell.protect { i = 1 }
131
+ end
132
+
133
+ should "log about being called with parameters" do
134
+ @log.expects(:debug).with("Protect called with [HUP, TERM]")
135
+ Cromwell.protect("HUP", "TERM") { i = 1 }
136
+ end
137
+
138
+ should "log about setting traps" do
139
+ @log.expects(:debug).with("Setting trap for HUP")
140
+ @log.expects(:debug).with("Setting trap for TERM")
141
+ Cromwell.protect("HUP", "TERM") { i = 1 }
142
+ end
143
+
144
+ should "log about stashing old traps" do
145
+ Signal.trap "HUP", proc {}
146
+ Signal.trap "TERM", "DEFAULT"
147
+ @log.expects(:debug).with(regexp_matches(/^Stashing old trap #<Proc:.+> for HUP$/))
148
+ @log.expects(:debug).with('Stashing old trap DEFAULT for TERM')
149
+ Cromwell.protect("HUP", "TERM") { i = 1 }
150
+ end
151
+
152
+ should "log about restoring old traps" do
153
+ Signal.trap "HUP", proc {}
154
+ Signal.trap "TERM", "DEFAULT"
155
+ @log.expects(:debug).with(regexp_matches(/^Restoring old trap #<Proc:.+> for HUP$/))
156
+ @log.expects(:debug).with('Restoring old trap DEFAULT for TERM')
157
+ Cromwell.protect("HUP", "TERM") { i = 1 }
158
+ end
159
+ end # with a logger
160
+
118
161
  end # method protect
119
162
 
120
- context "method protect with block" do
163
+ context "method protect with a block" do
121
164
  should "yield to block" do
122
165
  im_in_ur_blok_touchin_ur_vars = false
123
166
  Cromwell.protect {
@@ -136,6 +179,28 @@ class TestCromwell < Test::Unit::TestCase
136
179
  assert Cromwell.protected?
137
180
  }
138
181
  end
182
+
183
+ context "with a logger" do
184
+ setup do
185
+ @log = stub :debug => true
186
+ Cromwell.logger = @log
187
+ end
188
+
189
+ teardown do
190
+ Cromwell.logger = nil
191
+ end
192
+
193
+ should "log before yield" do
194
+ @log.expects(:debug).with('About to yield to block.')
195
+ Cromwell.protect { i = 1 }
196
+ end
197
+
198
+ should "log after yield" do
199
+ @log.expects(:debug).with('After yielding to block.')
200
+ Cromwell.protect { i = 1 }
201
+ end
202
+ end # with a logger
203
+
139
204
  end # method protect with block
140
205
 
141
206
  context "method unprotect" do
@@ -150,6 +215,28 @@ class TestCromwell < Test::Unit::TestCase
150
215
  Cromwell.expects(:exit)
151
216
  Cromwell.unprotect
152
217
  end
218
+
219
+ context "with a logger" do
220
+ setup do
221
+ @log = stub :debug => true
222
+ Cromwell.logger = @log
223
+ Cromwell.should_exit = false
224
+ end
225
+
226
+ teardown do
227
+ Cromwell.logger = nil
228
+ end
229
+
230
+ should "log about being called" do
231
+ @log.expects(:debug).with("Unprotect called")
232
+ Cromwell.unprotect
233
+ end
234
+
235
+ should "log about should_exit value" do
236
+ @log.expects(:debug).with("should_exit? = false")
237
+ Cromwell.unprotect
238
+ end
239
+ end # with a logger
153
240
  end # method unprotect
154
241
 
155
242
  context "should_exit=" do
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: cromwell
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.2.0
4
+ version: 0.3.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Przemyslaw Kowalczyk
@@ -9,7 +9,7 @@ autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
11
 
12
- date: 2010-01-08 00:00:00 +01:00
12
+ date: 2010-01-14 00:00:00 +01:00
13
13
  default_executable:
14
14
  dependencies:
15
15
  - !ruby/object:Gem::Dependency
@@ -54,6 +54,7 @@ files:
54
54
  - examples/example3.rb
55
55
  - examples/example4.rb
56
56
  - examples/example5.rb
57
+ - examples/example6.rb
57
58
  - lib/cromwell.rb
58
59
  - test/helper.rb
59
60
  - test/test_cromwell.rb
@@ -93,3 +94,4 @@ test_files:
93
94
  - examples/example3.rb
94
95
  - examples/example4.rb
95
96
  - examples/example5.rb
97
+ - examples/example6.rb