angael 0.0.1 → 0.0.2

Sign up to get free protection for your applications and to get access to all the features.
data/README.md CHANGED
@@ -1,6 +1,8 @@
1
1
  # Angael
2
2
 
3
3
  Angael is a lightweight library for running repetitive background processes.
4
+ It handles the forking and signal catching, allow you to just define what the
5
+ background workers should do.
4
6
 
5
7
  ## Documentation
6
8
 
@@ -10,7 +10,7 @@ Gem::Specification.new do |s|
10
10
  s.email = ["paul@thoughtless.ca"]
11
11
  s.homepage = "http://github.com/thoughtless/angael"
12
12
  s.summary = %q{Lightweight library for running repetitive background processes.}
13
- #s.description = %q{TODO: Write a gem description}
13
+ s.description = %q{Angael is a lightweight library for running repetitive background processes. It handles the forking and signal catching, allow you to just define what the background workers should do.}
14
14
 
15
15
  s.rubyforge_project = "angael"
16
16
 
@@ -1,3 +1,3 @@
1
1
  module Angael
2
- VERSION = "0.0.1"
2
+ VERSION = "0.0.2"
3
3
  end
@@ -11,54 +11,25 @@ module Angael
11
11
  # to do wrap the child process in a block. This is useful for
12
12
  # exception handling. Be sure to actually fork or you may break
13
13
  # something important.
14
+ # #log - If defined, this will be called at various points of interest
15
+ # with 1 String as the argument. Log levels are not supported.
16
+ # #timeout - Number of seconds to wait for the child process to exit after
17
+ # it is sent SIGINT. If you don't define this method, it waits
18
+ # 60 seconds.
14
19
  module Worker
15
20
  class ChildProcessNotStoppedError < StandardError; end
16
21
 
17
22
  attr_reader :pid
18
23
 
19
- # Options:
20
- # :batch_timeout - After this number of seconds, other workers will be able
21
- # to work on the jobs reserved by #process_jobs.
22
- # :batch_timeout_buffer - This is the number of seconds between when the
23
- # worker stops processing jobs and when other workers
24
- # can start processing the jobs that this worker had
25
- # resered. This should be set to the maximum length
26
- # of time a single job should take, plus the maximum
27
- # expected discrepancy between the system clocks on
28
- # all the worker servers.
29
- # :logger => A logger object, which should follow the Logger class in the
30
- # standard library. Default nil, as in no logging.
31
- # :log_level => The log level, as defined by the Logger class in the
32
- # standard library. One of:
33
- # Logger::FATAL
34
- # Logger::ERROR
35
- # Logger::WARN
36
- # Logger::INFO # Default
37
- # Logger::DEBUG
38
- def initialize(attrs={})
39
- @timeout = attrs[:timeout] || 60 # Seconds
40
- @batch_size = attrs[:batch_size] || 1
41
- @batch_timeout = attrs[:batch_timeout] || @batch_size * 5 # Seconds
42
- @batch_timeout_buffer = attrs[:batch_timeout_buffer] || 5 # Seconds
43
- @logger = attrs[:logger]
44
- if @logger
45
- @log_level = attrs[:log_level] || begin
46
- require 'logger' # Only require it if it is absolutely neccessary.
47
- Logger::INFO
48
- end
49
- end
50
- end
51
-
52
-
53
24
  # Loops forever, taking jobs off the queue. SIGINT will stop it after
54
25
  # allowing any jobs already taken from the queue to be processed.
55
26
  def start!
56
27
  trap("CHLD") do
57
- log("trapped SIGCHLD. Child PID #{pid}.")
28
+ __log("trapped SIGCHLD. Child PID #{pid}.")
58
29
 
59
30
  # @stopping is set by #stop!. If it is true, then the child process was
60
31
  # expected to die. If it is false/nil, then this is unexpected.
61
- log("Child process died unexpectedly") unless @stopping
32
+ __log("Child process died unexpectedly") unless @stopping
62
33
  # Reap the child process so that #started? will return false. But we can't
63
34
  # block because this may be called for a Worker when a different Worker's
64
35
  # child is the process that died.
@@ -66,27 +37,27 @@ module Angael
66
37
  end
67
38
 
68
39
  @pid = fork_child do
69
- log("Started")
40
+ __log("Started")
70
41
 
71
42
  if respond_to?(:after_fork)
72
- log("Running after fork callback")
43
+ __log("Running after fork callback")
73
44
  after_fork
74
- log("Finished running after fork callback")
45
+ __log("Finished running after fork callback")
75
46
  end
76
47
 
77
48
  @interrupted = false
78
49
  trap("INT") do
79
- log("SIGINT Received")
50
+ __log("SIGINT Received")
80
51
  @interrupted = true
81
52
  end
82
53
  trap("TERM") do
83
- log("SIGTERM Received")
54
+ __log("SIGTERM Received")
84
55
  @interrupted = true
85
56
  end
86
57
 
87
58
  loop do
88
59
  if @interrupted
89
- log("Child process exiting gracefully")
60
+ __log("Child process exiting gracefully")
90
61
  exit 0
91
62
  end
92
63
  work
@@ -96,7 +67,7 @@ module Angael
96
67
 
97
68
  def stop!
98
69
  unless started?
99
- log("Called stop for worker with PID #{pid} but it is not started")
70
+ __log("Called stop for worker with PID #{pid} but it is not started")
100
71
  return false
101
72
  end
102
73
 
@@ -105,14 +76,14 @@ module Angael
105
76
  @stopping = true
106
77
 
107
78
  begin
108
- log("Sending SIGINT to child process with pid #{pid}.")
109
- Timeout::timeout(@timeout) do
79
+ __log("Sending SIGINT to child process with pid #{pid}.")
80
+ Timeout::timeout(timeout) do
110
81
  Process.kill('INT', pid)
111
82
  wait_for_child
112
83
  end
113
84
  rescue Timeout::Error
114
85
  begin
115
- log("Child process with pid #{pid} did not stop with #@timeout seconds of SIGINT. Sending SIGKILL to child process.")
86
+ __log("Child process with pid #{pid} did not stop within #{timeout} seconds of SIGINT. Sending SIGKILL to child process.")
116
87
  # This only leaves 1 second for the SIGKILL to take effect. I don't
117
88
  # know if that is enough time (or maybe too much time).
118
89
  Timeout::timeout(1) do
@@ -122,7 +93,7 @@ module Angael
122
93
  rescue Timeout::Error
123
94
  if pid_running?
124
95
  msg = "Unable to kill child process with PID: #{pid}"
125
- log(msg)
96
+ __log(msg)
126
97
  raise ChildProcessNotStoppedError, msg
127
98
  end
128
99
  end
@@ -148,8 +119,14 @@ module Angael
148
119
  end
149
120
 
150
121
 
151
- def log(msg)
152
- @logger.add(@log_level, "#{Time.now.utc} - #{self.class} (pid #{$$}): #{msg}") if @logger
122
+ def __log(msg)
123
+ log(msg) if respond_to?(:log)
124
+ end
125
+
126
+
127
+ # In seconds
128
+ def timeout
129
+ 60
153
130
  end
154
131
 
155
132
 
@@ -166,7 +143,7 @@ module Angael
166
143
  # Will just return if the child process is not running.
167
144
  def wait_for_child(opts={})
168
145
  begin
169
- log("Waiting for child with pid #{pid}.")
146
+ __log("Waiting for child with pid #{pid}.")
170
147
  if opts[:dont_block]
171
148
  # When this is called as the result of a SIGCHLD
172
149
  # we need to pass in Process::WNOHANG as the 2nd argument, otherwise when
@@ -101,7 +101,11 @@ describe Angael::Worker do
101
101
  end
102
102
 
103
103
  context "child process does die within the worker's timeout" do
104
- subject { @worker ||= Angael::TestSupport::SampleWorker.new(:timeout => 2) }
104
+ subject do
105
+ worker = Angael::TestSupport::SampleWorker.new
106
+ worker.stub(:timeout => 2)
107
+ worker
108
+ end
105
109
  before do
106
110
  subject.stub(:work) { nil }
107
111
  subject.start!
@@ -129,7 +133,11 @@ describe Angael::Worker do
129
133
  end
130
134
 
131
135
  context "child process does not die within the worker's timeout" do
132
- subject { @worker ||= Angael::TestSupport::SampleWorker.new(:timeout => 1) }
136
+ subject do
137
+ worker = Angael::TestSupport::SampleWorker.new
138
+ worker.stub(:timeout => 1)
139
+ worker
140
+ end
133
141
  before do
134
142
  subject.stub(:work) { sleep 1000 }
135
143
  subject.start!
metadata CHANGED
@@ -2,7 +2,7 @@
2
2
  name: angael
3
3
  version: !ruby/object:Gem::Version
4
4
  prerelease:
5
- version: 0.0.1
5
+ version: 0.0.2
6
6
  platform: ruby
7
7
  authors:
8
8
  - Paul Cortens
@@ -10,7 +10,7 @@ autorequire:
10
10
  bindir: bin
11
11
  cert_chain: []
12
12
 
13
- date: 2011-05-28 00:00:00 -07:00
13
+ date: 2011-06-08 00:00:00 -07:00
14
14
  default_executable:
15
15
  dependencies:
16
16
  - !ruby/object:Gem::Dependency
@@ -35,7 +35,7 @@ dependencies:
35
35
  version: "0"
36
36
  type: :development
37
37
  version_requirements: *id002
38
- description:
38
+ description: Angael is a lightweight library for running repetitive background processes. It handles the forking and signal catching, allow you to just define what the background workers should do.
39
39
  email:
40
40
  - paul@thoughtless.ca
41
41
  executables: []