angael 0.0.1 → 0.0.2

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.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: []