redpack 1.0.3 → 1.0.4

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.
@@ -19,126 +19,126 @@
19
19
  module RedPack
20
20
 
21
21
  class Client
22
- def initialize(name, redis_options = {:host => 'localhost'})
23
- @timeout = 10
24
- @seqid = 0
25
- @reqtable = {}
26
- @transport = RedisClientTransport.new(self, redis_options, name)
27
- end
28
- attr_accessor :timeout
22
+ def initialize(name, redis_options = {:host => 'localhost'})
23
+ @timeout = 10
24
+ @seqid = 0
25
+ @reqtable = {}
26
+ @transport = RedisClientTransport.new(self, redis_options, name)
27
+ end
28
+ attr_accessor :timeout
29
+
30
+ # call-seq:
31
+ # notify(symbol, *args) -> nil
32
+ #
33
+ # Calls remote method with NOTIFY protocol.
34
+ # It doesn't require server to return results.
35
+ # This method is non-blocking and returns nil.
36
+ def notify(method, *args)
37
+ send_notify(method, args)
38
+ nil
39
+ end
29
40
 
30
- # call-seq:
31
- # notify(symbol, *args) -> nil
32
- #
33
- # Calls remote method with NOTIFY protocol.
34
- # It doesn't require server to return results.
35
- # This method is non-blocking and returns nil.
36
- def notify(method, *args)
37
- send_notify(method, args)
38
- nil
39
- end
40
-
41
- # call code like this for sync calls:
42
- # counter = client.increment_remote_counter_sync(1, 2, 3)
43
- #
44
- # call code like this for async non-blocking calls:
45
- # client.increment_remote_counter_async(1, 2, 3) do |error, result|
46
- # if error
47
- # raise "we got an error"
48
- # else
49
- # counter = result
50
- # end
51
- # end
52
- def method_missing(method, *args, &block)
53
- method_name = method.to_s
54
- sync = method_name.end_with?("_sync")
55
- async = method_name.end_with?("_async")
41
+ # call code like this for sync calls:
42
+ # counter = client.increment_remote_counter_sync(1, 2, 3)
43
+ #
44
+ # call code like this for async non-blocking calls:
45
+ # client.increment_remote_counter_async(1, 2, 3) do |error, result|
46
+ # if error
47
+ # raise "we got an error"
48
+ # else
49
+ # counter = result
50
+ # end
51
+ # end
52
+ def method_missing(method, *args, &block)
53
+ method_name = method.to_s
54
+ sync = method_name.end_with?("_sync")
55
+ async = method_name.end_with?("_async")
56
56
  if sync || async
57
- method_name.gsub!(/_sync$/, '') if sync
58
- method_name.gsub!(/_async$/, '') if async
59
- future = send_request(method_name, args, !!sync)
60
- future.attach_callback(block) if block
61
- if sync
62
- @transport.listen_for_return_sync
63
- future.get
64
- if future.error
65
- raise error
66
- else
67
- return future.result
68
- end
69
- elsif async
70
- @transport.listen_for_return_async
71
- return future
57
+ method_name.gsub!(/_sync$/, '') if sync
58
+ method_name.gsub!(/_async$/, '') if async
59
+ future = send_request(method_name, args, !!sync)
60
+ future.attach_callback(block) if block
61
+ if sync
62
+ @transport.listen_for_return_sync
63
+ future.get
64
+ if future.error
65
+ raise error
66
+ else
67
+ return future.result
68
+ end
69
+ elsif async
70
+ @transport.listen_for_return_async
71
+ return future
72
72
  end
73
73
  else
74
74
  super
75
75
  end
76
76
  end
77
-
78
77
 
79
- # Closes underlaying Transport and destroy resources.
80
- def close
81
- @timer.detach if @timer.attached?
82
- @reqtable = {}
83
- @transport.close
84
- @seqid = 0
85
- self
86
- end
87
-
88
- # from ClientTransport
89
- def on_response(sock, msgid, error, result) #:nodoc:
90
- if future = @reqtable.delete(msgid)
91
- future.set_result(error, result)
92
- end
93
- end
94
78
 
95
- # from ClientTransport
96
- def on_connect_failed #:nodoc:
97
- @reqtable.reject! {|msgid, future|
98
- begin
99
- future.set_result ConnectError.new, nil
100
- rescue
101
- end
102
- true
103
- }
104
- nil
105
- end
79
+ # Closes underlaying Transport and destroy resources.
80
+ def close
81
+ @timer.detach if @timer.attached?
82
+ @reqtable = {}
83
+ @transport.close
84
+ @seqid = 0
85
+ self
86
+ end
106
87
 
107
- # from Client, SessionPool
108
- def step_timeout #:nodoc:
109
- timedout = []
110
- @reqtable.reject! {|msgid, future|
111
- if future.step_timeout
112
- timedout.push(future)
113
- true
114
- end
115
- }
116
- timedout.each {|future|
117
- begin
118
- future.set_result TimeoutError.new, nil
119
- rescue
120
- end
121
- }
122
- !@reqtable.empty?
123
- end
88
+ # from ClientTransport
89
+ def on_response(sock, msgid, error, result) #:nodoc:
90
+ if future = @reqtable.delete(msgid)
91
+ future.set_result(error, result)
92
+ end
93
+ end
124
94
 
95
+ # from ClientTransport
96
+ def on_connect_failed #:nodoc:
97
+ @reqtable.reject! {|msgid, future|
98
+ begin
99
+ future.set_result ConnectError.new, nil
100
+ rescue
101
+ end
102
+ true
103
+ }
104
+ nil
105
+ end
106
+
107
+ # from Client, SessionPool
108
+ def step_timeout #:nodoc:
109
+ timedout = []
110
+ @reqtable.reject! {|msgid, future|
111
+ if future.step_timeout
112
+ timedout.push(future)
113
+ true
114
+ end
115
+ }
116
+ timedout.each {|future|
117
+ begin
118
+ future.set_result TimeoutError.new, nil
119
+ rescue
120
+ end
121
+ }
122
+ !@reqtable.empty?
123
+ end
125
124
 
126
- private
127
- def send_request(method, param, sync = false)
128
- method = method.to_s
129
- msgid = @seqid
130
- @seqid += 1; if @seqid >= 1<<31 then @seqid = 0 end
131
- data = [REQUEST, msgid, method, param]
132
- @transport.send_data(data, msgid, sync)
133
- @reqtable[msgid] = Future.new(self)
134
- end
135
125
 
136
- def send_notify(method, param)
137
- method = method.to_s
138
- data = [NOTIFY, method, param]
139
- @transport.send_data(data, nil)
140
- nil
141
- end
126
+ private
127
+ def send_request(method, param, sync = false)
128
+ method = method.to_s
129
+ msgid = @seqid
130
+ @seqid += 1; if @seqid >= 1<<31 then @seqid = 0 end
131
+ data = [REQUEST, msgid, method, param]
132
+ @transport.send_data(data, msgid, sync)
133
+ @reqtable[msgid] = Future.new(self)
134
+ end
135
+
136
+ def send_notify(method, param)
137
+ method = method.to_s
138
+ data = [NOTIFY, method, param]
139
+ @transport.send_data(data, nil)
140
+ nil
141
+ end
142
142
  end
143
143
 
144
144
  end
@@ -23,79 +23,79 @@ module RedPack
23
23
  # because it is not yet received.
24
24
  # You can wait and get the result with get method.
25
25
  class Future
26
- def initialize(session, callback = nil) #:nodoc:
27
- @timeout = session.timeout
28
- @callback_handler = callback
29
- @error_handler = nil
30
- @result_handler = nil
31
- @set = false
32
- @error = nil
33
- @result = nil
34
- end
35
- attr_accessor :result, :error
26
+ def initialize(session, callback = nil) #:nodoc:
27
+ @timeout = session.timeout
28
+ @callback_handler = callback
29
+ @error_handler = nil
30
+ @result_handler = nil
31
+ @set = false
32
+ @error = nil
33
+ @result = nil
34
+ end
35
+ attr_accessor :result, :error
36
36
 
37
- # Wait for receiving result of remote procedure call and returns its result.
38
- # If the remote method raises error, then this method raises RemoteError.
39
- # If the remote procedure call failed with timeout, this method raises TimeoutError.
40
- # Otherwise this method returns the result of remote method.
41
- def get
42
- join
43
- if error.nil?
44
- if @result_handler
45
- return @result_handler.call(@result)
46
- else
47
- return @result
48
- end
49
- end
50
- if @error_handler
51
- return @error_handler.call(self)
52
- else
53
- raise @error if @error.is_a?(Error)
54
- raise RemoteError.new(@error, @result)
55
- end
56
- end
37
+ # Wait for receiving result of remote procedure call and returns its result.
38
+ # If the remote method raises error, then this method raises RemoteError.
39
+ # If the remote procedure call failed with timeout, this method raises TimeoutError.
40
+ # Otherwise this method returns the result of remote method.
41
+ def get
42
+ join
43
+ if error.nil?
44
+ if @result_handler
45
+ return @result_handler.call(@result)
46
+ else
47
+ return @result
48
+ end
49
+ end
50
+ if @error_handler
51
+ return @error_handler.call(self)
52
+ else
53
+ raise @error if @error.is_a?(Error)
54
+ raise RemoteError.new(@error, @result)
55
+ end
56
+ end
57
57
 
58
- # Wait for receiving result of remote procedure call.
59
- # This method returns self.
60
- # If a callback method is attached, it will be called.
61
- def join
62
- until @set
63
- sleep(0.0001)
64
- end
65
- self
66
- end
58
+ # Wait for receiving result of remote procedure call.
59
+ # This method returns self.
60
+ # If a callback method is attached, it will be called.
61
+ def join
62
+ until @set
63
+ sleep(0.0001)
64
+ end
65
+ self
66
+ end
67
67
 
68
- # call-seq:
69
- # attach_callback {|future| }
70
- #
71
- # Attaches a callback method that is called when the result of remote method is received.
72
- def attach_callback(proc = nil, &block)
73
- @callback_handler = proc || block
74
- end
68
+ # call-seq:
69
+ # attach_callback {|future| }
70
+ #
71
+ # Attaches a callback method that is called when the result of remote method is received.
72
+ def attach_callback(proc = nil, &block)
73
+ @callback_handler = proc || block
74
+ end
75
75
 
76
- # For IDL
77
- def attach_error_handler(proc = nil, &block) #:nodoc:
78
- @error_handler = proc || block
79
- end
76
+ # For IDL
77
+ def attach_error_handler(proc = nil, &block) #:nodoc:
78
+ @error_handler = proc || block
79
+ end
80
80
 
81
- # For IDL
82
- def attach_result_handler(proc = nil, &block) #:nodoc:
83
- @result_handler = proc || block
84
- end
81
+ # For IDL
82
+ def attach_result_handler(proc = nil, &block) #:nodoc:
83
+ @result_handler = proc || block
84
+ end
85
85
 
86
- def set_result(err, res) #:nodoc:
87
- @error = err
88
- @result = res
89
- if @callback_handler
90
- if @callback_handler.arity == 2
91
- # FIXME backward compatibility
92
- @callback_handler.call(error, result)
93
- else
94
- @callback_handler.call(self)
95
- end
96
- end
97
- @set = true
98
- end
86
+ def set_result(err, res) #:nodoc:
87
+ @error = err
88
+ @result = res
89
+ if @callback_handler
90
+ if @callback_handler.arity == 2
91
+ # FIXME backward compatibility
92
+ @callback_handler.call(error, result)
93
+ else
94
+ @callback_handler.call(self)
95
+ end
96
+ end
97
+ @set = true
98
+ end
99
99
  end
100
100
 
101
101
  end
@@ -37,9 +37,9 @@ class RedisClientTransport
37
37
  # Pass in {:ignore_return_value => true} as part of the redis_options so that the server doesn't put the return
38
38
  # object in a queue. This is useful if you're doing call_async and never care about the return value. It saves
39
39
  # Redis from adding a key/list pair. A synchronous call will result in an immediate timeout exception.
40
- def initialize(client, redis_options, name)
41
- @client = client
42
- @queue_name = "redpack_request_queue:#{name}"
40
+ def initialize(client, redis_options, name)
41
+ @client = client
42
+ @queue_name = "redpack_request_queue:#{name}"
43
43
  @ignore_return_value = !!redis_options.delete(:ignore_return_value)
44
44
  if @ignore_return_value
45
45
  @client.timeout = 0
@@ -50,12 +50,12 @@ class RedisClientTransport
50
50
  @redis_options = redis_options
51
51
  @redis = Redis.new(redis_options)
52
52
 
53
- # assign a unique client key for this instance which will be used for return values
54
- @identifier = @redis.incr("redpack_response_queue_index")
55
- @return_queue_name = "redpack_response_queue:#{@identifier}"
56
- @unprocessed_requests_name = "#{@return_queue_name}:unprocessed"
57
- @pool = 0
58
- end
53
+ # assign a unique client key for this instance which will be used for return values
54
+ @identifier = @redis.incr("redpack_response_queue_index")
55
+ @return_queue_name = "redpack_response_queue:#{@identifier}"
56
+ @unprocessed_requests_name = "#{@return_queue_name}:unprocessed"
57
+ @pool = 0
58
+ end
59
59
 
60
60
  def process_data(data)
61
61
  # puts "done waiting for #{@return_queue_name}"
@@ -77,26 +77,25 @@ class RedisClientTransport
77
77
  end
78
78
  end
79
79
 
80
- def listen_for_return_sync
80
+ def listen_for_return_sync
81
81
  process_data(@redis.blpop(@return_queue_name, 0))
82
82
  end
83
83
 
84
- def listen_for_return_async
85
- Thread.new do
84
+ def listen_for_return_async
85
+ Thread.new do
86
86
  unless @ignore_return_value
87
- EM.run do
88
- redis = EventMachine::Protocols::Redis.connect(@redis_options)
89
- # puts "waiting for #{@return_queue_name}"
90
- redis.blpop(@return_queue_name, 0) do |data|
91
- process_data(data)
92
- end
93
- end
94
- end
87
+ EM.run do
88
+ redis = EventMachine::Protocols::Redis.connect(@redis_options)
89
+ redis.blpop(@return_queue_name, 0) do |data|
90
+ process_data(data)
91
+ end
92
+ end
93
+ end
95
94
  end
96
95
  end
97
96
 
98
- def redis_push(msgpack_data, msgid = nil)
99
- if msgid
97
+ def redis_push(msgpack_data, msgid = nil)
98
+ if msgid
100
99
  @redis.multi
101
100
  # puts "setting key in #{@unprocessed_requests_name}"
102
101
  @redis.hset(@unprocessed_requests_name, msgid.to_s, msgpack_data)
@@ -108,89 +107,89 @@ class RedisClientTransport
108
107
  end
109
108
  end
110
109
 
111
- def send_data(data, msgid = nil, sync = false)
112
- if sync
110
+ def send_data(data, msgid = nil, sync = false)
111
+ if @ignore_return_value
112
+ redis_push(BSON.serialize({:data => data}), msgid)
113
+ else
113
114
  redis_push(BSON.serialize({:data => data, :return => @return_queue_name}), msgid)
114
- elsif @ignore_return_value || !sync
115
- redis_push(BSON.serialize({:data => data}), msgid)
116
115
  end
117
- end
116
+ end
118
117
 
119
- def close
120
- self
121
- end
118
+ def close
119
+ self
120
+ end
122
121
 
123
- def on_connect(sock)
124
- end
122
+ def on_connect(sock)
123
+ end
125
124
 
126
- def on_response(msgid, error, result)
127
- @client.on_response(self, msgid, error, result)
128
- end
125
+ def on_response(msgid, error, result)
126
+ @client.on_response(self, msgid, error, result)
127
+ end
129
128
 
130
- def on_connect_failed(sock)
131
- end
129
+ def on_connect_failed(sock)
130
+ end
132
131
 
133
- def on_close(sock)
134
- end
132
+ def on_close(sock)
133
+ end
135
134
  end
136
135
 
137
136
  class RedisServerTransport
138
137
  include Util
139
-
140
- def initialize(name, redis_options = {})
141
- @ignore_nil_returns = !!redis_options.delete(:ignore_nil_returns)
138
+
139
+ def initialize(name, redis_options = {})
140
+ @ignore_nil_returns = !!redis_options.delete(:ignore_nil_returns)
142
141
  @redis = Redis.new(redis_options)
143
- @queue_name = "redpack_request_queue:#{name}"
144
- @timeout_mechanism = redis_options[:timeout_mechanism]
145
- end
142
+ @queue_name = "redpack_request_queue:#{name}"
143
+ @timeout_mechanism = redis_options[:timeout_mechanism]
144
+ end
146
145
 
147
- # ServerTransport interface
148
- def listen(server)
149
- @server = server
146
+ # ServerTransport interface
147
+ def listen(server)
148
+ @server = server
150
149
  loop do
151
150
  begin
152
151
  # puts "listening to #{@queue_name}"
153
152
  data = @redis.blpop(@queue_name, 0)
154
153
  # puts "popped item off of #{@queue_name}"
155
- if data && data[1]
156
- redis_packet = BSON.deserialize(data[1])
157
- if redis_packet["data"]
158
- @return_queue_name = redis_packet["return"]
159
- @unprocessed_requests_name = "#{@return_queue_name}:unprocessed"
160
- msg = redis_packet["data"]
161
- case msg[0]
162
- when REQUEST
163
- @server.on_request(self, msg[1], msg[2], msg[3])
164
- when RESPONSE
165
- puts "response message on server session"
166
- when NOTIFY
167
- @server.on_notify(msg[1], msg[2])
168
- else
169
- puts "unknown message type #{msg[0]}"
170
- end
171
- end
172
- end
173
- rescue => e
174
- # probably timed out
175
- p e
176
- @timeout_mechanism.call if @timeout_mechanism
177
- end
154
+ if data && data[1]
155
+ redis_packet = BSON.deserialize(data[1])
156
+ if redis_packet["data"]
157
+ @return_queue_name = redis_packet["return"]
158
+ @unprocessed_requests_name = "#{@return_queue_name}:unprocessed"
159
+ msg = redis_packet["data"]
160
+ case msg[0]
161
+ when REQUEST
162
+ @server.on_request(self, msg[1], msg[2], msg[3])
163
+ when RESPONSE
164
+ puts "response message on server session"
165
+ when NOTIFY
166
+ @server.on_notify(msg[1], msg[2])
167
+ else
168
+ puts "unknown message type #{msg[0]}"
169
+ end
170
+ end
171
+ end
172
+ rescue => e
173
+ # probably timed out
174
+ p e
175
+ @timeout_mechanism.call if @timeout_mechanism
176
+ end
178
177
  end
179
- end
180
-
181
- def finish(msgid)
182
- # puts "removing key from #{@unprocessed_requests_name}"
183
- @redis.hdel(@unprocessed_requests_name, msgid.to_s)
184
178
  end
185
179
 
186
- def send_data(data)
187
- # puts "putting data on #{@return_queue_name}"
180
+ def finish(msgid)
181
+ # puts "removing key from #{@unprocessed_requests_name}"
182
+ @redis.hdel(@unprocessed_requests_name, msgid.to_s)
183
+ end
184
+
185
+ def send_data(data)
186
+ # puts "putting data on #{@return_queue_name}"
188
187
  @redis.rpush(@return_queue_name, BSON.serialize({:data => data})) if @return_queue_name
189
188
  end
190
189
 
191
- # ServerTransport interface
192
- def close
193
- end
190
+ # ServerTransport interface
191
+ def close
192
+ end
194
193
  end
195
194
 
196
- end
195
+ end
metadata CHANGED
@@ -5,8 +5,8 @@ version: !ruby/object:Gem::Version
5
5
  segments:
6
6
  - 1
7
7
  - 0
8
- - 3
9
- version: 1.0.3
8
+ - 4
9
+ version: 1.0.4
10
10
  platform: ruby
11
11
  authors:
12
12
  - Dean Mao
@@ -14,7 +14,7 @@ autorequire:
14
14
  bindir: bin
15
15
  cert_chain: []
16
16
 
17
- date: 2011-01-19 00:00:00 -08:00
17
+ date: 2011-02-01 00:00:00 -08:00
18
18
  default_executable:
19
19
  dependencies:
20
20
  - !ruby/object:Gem::Dependency