parallizer 0.1.0 → 0.2.0

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
@@ -137,6 +137,22 @@ http_service.get('www.google.com', '/search?q=foobar') # makes an HTTP request a
137
137
  ```
138
138
 
139
139
 
140
+ ### Service Method Retries
141
+
142
+ Parallize also allows you to retry methods that fail (any exception raised is considered a failure).
143
+
144
+ ```ruby
145
+ require 'net/http'
146
+ require 'parallizer'
147
+
148
+ parallizer = Parallizer.new(Net::HTTP, :retries => 3)
149
+ parallizer.add.get('www.google.com', '/?q=foo')
150
+ http_service = parallizer.create_proxy
151
+
152
+ http_service.get('www.google.com', '/?q=foo') # Will be called up to 4 times
153
+ ```
154
+
155
+
140
156
  # Credits
141
157
 
142
158
  [Parallizer](https://github.com/michaelgpearce/parallizer) is maintained by [Michael Pearce](http://github.com/michaelgpearce) and is funded by [Rafter](http://www.rafter.com "Rafter").
data/VERSION CHANGED
@@ -1 +1 @@
1
- 0.1.0
1
+ 0.2.0
data/lib/parallizer.rb CHANGED
@@ -3,10 +3,11 @@ require 'parallizer/proxy'
3
3
  require 'parallizer/method_call_notifier'
4
4
 
5
5
  class Parallizer
6
- attr_reader :calls, :call_infos, :client, :proxy
6
+ attr_reader :calls, :call_infos, :client, :proxy, :options
7
7
 
8
- def initialize(client)
8
+ def initialize(client, options = {})
9
9
  @client = client
10
+ @options = {:retries => 0}.merge(options)
10
11
  @call_infos = {}
11
12
  end
12
13
 
@@ -30,22 +31,12 @@ class Parallizer
30
31
  :result => nil,
31
32
  :exception => nil,
32
33
  :condition_variable => ConditionVariable.new,
33
- :mutex => Mutex.new
34
+ :mutex => Mutex.new,
35
+ :retries => options[:retries]
34
36
  }
35
37
  call_infos[method_name_and_args] = call_info
36
38
 
37
- Parallizer.work_queue.enqueue_b do
38
- call_info[:mutex].synchronize do
39
- begin
40
- call_info[:result] = client.send(*method_name_and_args)
41
- rescue Exception => e
42
- call_info[:exception] = e
43
- ensure
44
- call_info[:complete?] = true
45
- call_info[:condition_variable].signal
46
- end
47
- end
48
- end
39
+ enqueue_call_info(call_info, method_name_and_args)
49
40
  end
50
41
 
51
42
  def create_proxy
@@ -57,4 +48,27 @@ class Parallizer
57
48
  def self.work_queue
58
49
  @parallizer_work_queue ||= WorkQueue.new(10)
59
50
  end
51
+
52
+ private
53
+
54
+ def enqueue_call_info(call_info, method_name_and_args)
55
+ Parallizer.work_queue.enqueue_b do
56
+ call_info[:mutex].synchronize do
57
+ begin
58
+ (call_info[:retries] + 1).times do
59
+ begin
60
+ call_info[:exception] = nil # reset exception before each send attempt
61
+ call_info[:result] = client.send(*method_name_and_args)
62
+ break # success
63
+ rescue Exception => e
64
+ call_info[:exception] = e
65
+ end
66
+ end
67
+ ensure
68
+ call_info[:complete?] = true
69
+ call_info[:condition_variable].signal
70
+ end
71
+ end
72
+ end
73
+ end
60
74
  end
@@ -19,7 +19,12 @@ class Parallizer
19
19
  end
20
20
  # we now have our result from the worker thread
21
21
 
22
- raise call_info[:exception] if call_info[:exception]
22
+ if call_info[:exception]
23
+ # add the current call stack to the exception backtrace
24
+ exception = call_info[:exception].clone
25
+ exception.set_backtrace((call_info[:exception].backtrace || []) + caller)
26
+ raise exception
27
+ end
23
28
 
24
29
  value = call_info[:result]
25
30
  end
data/parallizer.gemspec CHANGED
@@ -5,11 +5,11 @@
5
5
 
6
6
  Gem::Specification.new do |s|
7
7
  s.name = "parallizer"
8
- s.version = "0.1.0"
8
+ s.version = "0.2.0"
9
9
 
10
10
  s.required_rubygems_version = Gem::Requirement.new(">= 0") if s.respond_to? :required_rubygems_version=
11
11
  s.authors = ["Michael Pearce"]
12
- s.date = "2012-08-04"
12
+ s.date = "2012-08-15"
13
13
  s.description = "Execute your service layer in parallel."
14
14
  s.email = "michael.pearce@bookrenter.com"
15
15
  s.extra_rdoc_files = [
@@ -49,10 +49,26 @@ class Parallizer::ProxyTest < Test::Unit::TestCase
49
49
  context "with an exception" do
50
50
  setup do
51
51
  @call_info[:exception] = StandardError.new('An Exception')
52
+ @call_info[:exception].set_backtrace(["/tmp/foo.rb:123:in `in a_worker_thread_method'"])
52
53
  end
53
54
 
55
+ execute do
56
+ def a_calling_thread_method
57
+ call_infos = { @call_key => @call_info }
58
+ proxy = Parallizer::Proxy.new(@client, call_infos)
59
+ proxy.send(*@call_key) rescue $!
60
+ end
61
+ a_calling_thread_method
62
+ end
63
+
54
64
  should "raise exception" do
55
- assert_equal @call_info[:exception], @execute_result
65
+ assert_equal @call_info[:exception].class, @execute_result.class
66
+ assert_equal @call_info[:exception].message, @execute_result.message
67
+ end
68
+
69
+ should "append backtrace of current call" do
70
+ assert @execute_result.backtrace.grep /a_worker_thread_method/
71
+ assert @execute_result.backtrace.grep /a_calling_thread_method/
56
72
  end
57
73
  end
58
74
 
@@ -110,6 +110,43 @@ class ParallizerTest < Test::Unit::TestCase
110
110
  assert_equal ArgumentError, @execute_result.class
111
111
  end
112
112
  end
113
+ end
114
+
115
+ context "with retries" do
116
+ setup do
117
+ @retries = 3
118
+ @client = stub('a client')
119
+ @method = :a_sometimes_failing_method
120
+ end
121
+
122
+ execute do
123
+ parallizer = Parallizer.new(@client, :retries => @retries)
124
+ parallizer.add_call(@method)
125
+ proxy = parallizer.create_proxy
126
+ proxy.send(@method) rescue $!
127
+ end
113
128
 
129
+ context "with success on last retry" do
130
+ setup do
131
+ # NOTE: added reverse order
132
+ @client.expects(@method).returns('success')
133
+ @retries.times { @client.expects(@method).raises('an error') }
134
+ end
135
+
136
+ should "return successful method response" do
137
+ assert_equal 'success', @execute_result
138
+ end
139
+ end
140
+
141
+
142
+ context "with failures greater than retries" do
143
+ setup do
144
+ (@retries + 1).times { @client.expects(@method).raises('an error') }
145
+ end
146
+
147
+ should "return successful method response" do
148
+ assert_equal 'an error', @execute_result.message
149
+ end
150
+ end
114
151
  end
115
152
  end
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: parallizer
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.1.0
4
+ version: 0.2.0
5
5
  prerelease:
6
6
  platform: ruby
7
7
  authors:
@@ -9,7 +9,7 @@ authors:
9
9
  autorequire:
10
10
  bindir: bin
11
11
  cert_chain: []
12
- date: 2012-08-04 00:00:00.000000000 Z
12
+ date: 2012-08-15 00:00:00.000000000 Z
13
13
  dependencies:
14
14
  - !ruby/object:Gem::Dependency
15
15
  name: bundler
@@ -128,7 +128,7 @@ required_ruby_version: !ruby/object:Gem::Requirement
128
128
  version: '0'
129
129
  segments:
130
130
  - 0
131
- hash: -894887093549594031
131
+ hash: 1438464558148381221
132
132
  required_rubygems_version: !ruby/object:Gem::Requirement
133
133
  none: false
134
134
  requirements: