sneakers_packer 0.1.4 → 0.1.5
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.
- checksums.yaml +4 -4
- data/.travis.yml +4 -1
- data/CHANGELOG.md +4 -0
- data/{LICENSE.txt → LICENSE.md} +1 -1
- data/README.md +14 -3
- data/lib/sneakers_packer/rpc_client.rb +22 -76
- data/lib/sneakers_packer/rpc_reply_subscriber.rb +48 -0
- data/lib/sneakers_packer/rpc_request.rb +36 -0
- data/lib/sneakers_packer/version.rb +1 -1
- data/lib/sneakers_packer.rb +56 -27
- metadata +5 -5
- data/bin/console +0 -14
- data/bin/setup +0 -8
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: a4ac9997eb8d9b7257a00b04c991d19220c2f22d
|
4
|
+
data.tar.gz: e3c3c1b1cbd97310b3d1bbd240d9c90168a93e3d
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: f1c24ad78b837d918ec14ca8fcce97548394848bb3954074d1a79b58195d4d64d61fe8c25667a682a8e59472254e38eedc623b69fa9a41981a5d939974453a61
|
7
|
+
data.tar.gz: b765f498e08c52302dea54e7641dc4925c79f8f844541af1022801dde214c94d6878a3dcd15b7f2688810544360c43fffb736818b075919782fc5dfd18afda89
|
data/.travis.yml
CHANGED
data/CHANGELOG.md
CHANGED
data/{LICENSE.txt → LICENSE.md}
RENAMED
data/README.md
CHANGED
@@ -1,4 +1,8 @@
|
|
1
|
-
# SneakersPacker
|
1
|
+
# SneakersPacker [![Build Status][travis-image]][travis-link]
|
2
|
+
|
3
|
+
[travis-image]: https://travis-ci.org/xiewenwei/sneakers_packer.svg?branch=master
|
4
|
+
[travis-link]: http://travis-ci.org/xiewenwei/sneakers_packer
|
5
|
+
[travis-home]: http://travis-ci.org/
|
2
6
|
|
3
7
|
SneakersPacker is a gem for using sneakers to realize 3 message communication patterns job message, broadcast and RPC(remote procedure call).
|
4
8
|
|
@@ -125,9 +129,16 @@ remote call with custom timeouit.
|
|
125
129
|
|
126
130
|
## Development
|
127
131
|
|
128
|
-
|
132
|
+
**How to run test?**
|
133
|
+
|
134
|
+
1.start RabbitMQ Server. for mac
|
135
|
+
`rabbitmq-server`
|
136
|
+
|
137
|
+
2.start test workers
|
138
|
+
`ruby test/sneakers_test_workers.rb`
|
129
139
|
|
130
|
-
|
140
|
+
3.run test
|
141
|
+
`bundle exec rake test`
|
131
142
|
|
132
143
|
## Contributing
|
133
144
|
|
@@ -1,18 +1,15 @@
|
|
1
1
|
module SneakersPacker
|
2
2
|
class RpcClient
|
3
|
-
|
4
|
-
attr_reader :reply_queue
|
5
|
-
attr_accessor :response, :call_id
|
6
|
-
attr_reader :lock, :condition
|
3
|
+
attr_reader :client_lock, :request_hash
|
7
4
|
|
8
5
|
def initialize(publisher)
|
9
6
|
@publisher = publisher
|
10
|
-
|
11
|
-
@
|
12
|
-
@
|
13
|
-
end
|
7
|
+
@client_lock = Mutex.new
|
8
|
+
@request_lock = Mutex.new
|
9
|
+
@request_hash = {}
|
14
10
|
|
15
|
-
|
11
|
+
@subscriber = RpcReplySubscriber.new self, publisher
|
12
|
+
end
|
16
13
|
|
17
14
|
# call remote service via rabbitmq rpc
|
18
15
|
# @param name route_key for service
|
@@ -20,86 +17,35 @@ module SneakersPacker
|
|
20
17
|
# @param options{timeout} [int] timeout. seconds. optional
|
21
18
|
# @return result of service
|
22
19
|
# @raise RemoteCallTimeoutError if timeout
|
23
|
-
def call(
|
24
|
-
|
25
|
-
self.response = NO_RESPONSE
|
20
|
+
def call(request, options = {})
|
21
|
+
add_request(request)
|
26
22
|
|
27
|
-
|
28
|
-
|
29
|
-
|
30
|
-
|
31
|
-
correlation_id: call_id,
|
32
|
-
reply_to: @reply_queue.name)
|
23
|
+
@publisher.publish(request.message,
|
24
|
+
routing_key: request.name,
|
25
|
+
correlation_id: request.call_id,
|
26
|
+
reply_to: @subscriber.reply_queue_name)
|
33
27
|
|
34
28
|
timeout = (options[:timeout] || SneakersPacker.conf.rpc_timeout).to_i
|
35
29
|
|
36
|
-
|
30
|
+
client_lock.synchronize { request.condition.wait(client_lock, timeout) }
|
37
31
|
|
38
|
-
|
39
|
-
|
32
|
+
remove_request(request)
|
33
|
+
|
34
|
+
if request.processed?
|
35
|
+
request.response_data
|
40
36
|
else
|
41
|
-
|
37
|
+
raise RemoteCallTimeoutError, "Remote call timeouts.Exceed #{timeout} seconds."
|
42
38
|
end
|
43
39
|
end
|
44
40
|
|
45
41
|
private
|
46
42
|
|
47
|
-
def
|
48
|
-
|
49
|
-
channel = nil
|
50
|
-
exchange = nil
|
51
|
-
|
52
|
-
@publisher.instance_eval do
|
53
|
-
if @bunny.nil? || !@bunny.automatically_recover?
|
54
|
-
# ensure_connection connection first
|
55
|
-
@mutex.synchronize do
|
56
|
-
unless connected?
|
57
|
-
ensure_connection!
|
58
|
-
reconnected = true
|
59
|
-
channel = @channel
|
60
|
-
exchange = @exchange
|
61
|
-
end
|
62
|
-
end
|
63
|
-
end
|
64
|
-
end
|
65
|
-
|
66
|
-
# rebuid reply_queue when reconnecting occur
|
67
|
-
if reconnected
|
68
|
-
@consumer = build_reply_queue(channel, exchange)
|
69
|
-
end
|
70
|
-
end
|
71
|
-
|
72
|
-
def build_reply_queue(channel, exchange)
|
73
|
-
@channel, @exchange = channel, exchange
|
74
|
-
|
75
|
-
@reply_queue = channel.queue(@queue_name, exclusive: true)
|
76
|
-
@reply_queue.bind(exchange, routing_key: @reply_queue.name)
|
77
|
-
|
78
|
-
@lock = Mutex.new
|
79
|
-
@condition = ConditionVariable.new
|
80
|
-
that = self
|
81
|
-
|
82
|
-
@reply_queue.subscribe(manual_ack: false) do |delivery_info, properties, payload|
|
83
|
-
if properties[:correlation_id] == that.call_id
|
84
|
-
that.response = payload
|
85
|
-
that.lock.synchronize { that.condition.signal }
|
86
|
-
end
|
87
|
-
end
|
43
|
+
def add_request(request)
|
44
|
+
@request_lock.synchronize { @request_hash[request.call_id] = request }
|
88
45
|
end
|
89
46
|
|
90
|
-
|
91
|
-
|
92
|
-
ret = nil
|
93
|
-
|
94
|
-
@publisher.instance_eval do
|
95
|
-
# ensure_connection connection first
|
96
|
-
@mutex.synchronize do
|
97
|
-
ensure_connection! unless connected?
|
98
|
-
end
|
99
|
-
ret = [@channel, @exchange]
|
100
|
-
end
|
101
|
-
|
102
|
-
ret
|
47
|
+
def remove_request(request)
|
48
|
+
@request_lock.synchronize { @request_hash.delete request.call_id }
|
103
49
|
end
|
104
50
|
end
|
105
51
|
end
|
@@ -0,0 +1,48 @@
|
|
1
|
+
module SneakersPacker
|
2
|
+
class RpcReplySubscriber
|
3
|
+
|
4
|
+
def initialize(client, publisher)
|
5
|
+
@client = client
|
6
|
+
@publisher = publisher
|
7
|
+
@queue_name = "rpc.#{SecureRandom.uuid}"
|
8
|
+
|
9
|
+
initialize_reply_queue
|
10
|
+
end
|
11
|
+
|
12
|
+
def reply_queue_name
|
13
|
+
@queue_name
|
14
|
+
end
|
15
|
+
|
16
|
+
private
|
17
|
+
|
18
|
+
def initialize_reply_queue
|
19
|
+
# ensure_connection
|
20
|
+
@publisher.instance_eval do
|
21
|
+
@mutex.synchronize { ensure_connection! unless connected? }
|
22
|
+
end
|
23
|
+
|
24
|
+
channel = @publisher.instance_variable_get :@channel
|
25
|
+
exchange = @publisher.instance_variable_get :@exchange
|
26
|
+
build_reply_queue(channel, exchange)
|
27
|
+
end
|
28
|
+
|
29
|
+
def build_reply_queue(channel, exchange)
|
30
|
+
@reply_queue = channel.queue(@queue_name, exclusive: true)
|
31
|
+
|
32
|
+
@reply_queue.bind(exchange, routing_key: @reply_queue.name)
|
33
|
+
|
34
|
+
that = @client
|
35
|
+
|
36
|
+
@reply_queue.subscribe(manual_ack: false) do |delivery_info, properties, payload|
|
37
|
+
request = that.request_hash[properties[:correlation_id]]
|
38
|
+
if request
|
39
|
+
request.response = payload
|
40
|
+
request.set_processed!
|
41
|
+
that.client_lock.synchronize { request.condition.signal }
|
42
|
+
else
|
43
|
+
Sneakers.logger.warn "#{properties[:correlation_id]}'s request is not found"
|
44
|
+
end
|
45
|
+
end
|
46
|
+
end
|
47
|
+
end
|
48
|
+
end
|
@@ -0,0 +1,36 @@
|
|
1
|
+
module SneakersPacker
|
2
|
+
class RpcRequest
|
3
|
+
attr_reader :name, :call_id, :condition
|
4
|
+
attr_reader :response_data, :from, :status
|
5
|
+
|
6
|
+
def initialize(name, data)
|
7
|
+
@name = name.to_s
|
8
|
+
@data = data
|
9
|
+
@call_id = SecureRandom.uuid
|
10
|
+
|
11
|
+
@response = nil
|
12
|
+
@processed = false
|
13
|
+
@condition = ConditionVariable.new
|
14
|
+
end
|
15
|
+
|
16
|
+
def message
|
17
|
+
SneakersPacker.message_packer.pack_request(@data)
|
18
|
+
end
|
19
|
+
|
20
|
+
def processed?
|
21
|
+
@processed
|
22
|
+
end
|
23
|
+
|
24
|
+
def set_processed!
|
25
|
+
@processed = true
|
26
|
+
end
|
27
|
+
|
28
|
+
def response=(value)
|
29
|
+
@response_data, @from, @status = nil, nil, nil
|
30
|
+
@response = value
|
31
|
+
if value
|
32
|
+
@response_data, @from, @status = SneakersPacker.message_packer.unpack_response(value)
|
33
|
+
end
|
34
|
+
end
|
35
|
+
end
|
36
|
+
end
|
data/lib/sneakers_packer.rb
CHANGED
@@ -3,42 +3,71 @@ require "sneakers_packer/version"
|
|
3
3
|
require "sneakers_packer/configuration"
|
4
4
|
require "sneakers_packer/message_packer"
|
5
5
|
require "sneakers_packer/common_worker"
|
6
|
+
|
6
7
|
require "sneakers_packer/rpc_worker"
|
8
|
+
require "sneakers_packer/rpc_request"
|
9
|
+
require "sneakers_packer/rpc_reply_subscriber"
|
7
10
|
require "sneakers_packer/rpc_client"
|
8
11
|
|
9
12
|
module SneakersPacker
|
10
13
|
class RemoteCallTimeoutError < StandardError; end
|
11
14
|
|
12
|
-
#
|
13
|
-
|
14
|
-
|
15
|
-
def self.publish(name, data)
|
16
|
-
message = message_packer.pack_request(data)
|
15
|
+
# sneakers_packer_mutex is mutex for class instance variables initialization
|
16
|
+
@sneakers_packer_mutex = Mutex.new
|
17
|
+
@publish_mutex = Mutex.new
|
17
18
|
|
18
|
-
|
19
|
-
|
19
|
+
class << self
|
20
|
+
# sender message to sneaker exchange
|
21
|
+
# @param name route_key for message
|
22
|
+
# @param data
|
23
|
+
def publish(name, data)
|
24
|
+
message = message_packer.pack_request(data)
|
25
|
+
@publish_mutex.synchronize do
|
26
|
+
publisher.publish message, to_queue: name
|
27
|
+
end
|
28
|
+
end
|
20
29
|
|
21
|
-
|
22
|
-
|
23
|
-
|
24
|
-
|
25
|
-
|
26
|
-
|
27
|
-
|
28
|
-
|
29
|
-
|
30
|
-
message = message_packer.pack_request(data)
|
31
|
-
response = @client.call name, message, options
|
32
|
-
response_data, from, status = message_packer.unpack_response(response)
|
33
|
-
response_data
|
34
|
-
end
|
30
|
+
# call remote service via rabbitmq rpc
|
31
|
+
# @param name route_key for service
|
32
|
+
# @param data
|
33
|
+
# @param options{timeout} [int] timeout. seconds. optional
|
34
|
+
# @return result of service
|
35
|
+
# @raise RemoteCallTimeoutError if timeout
|
36
|
+
#
|
37
|
+
def remote_call(name, data, options = {})
|
38
|
+
request = RpcRequest.new name, data
|
35
39
|
|
36
|
-
|
37
|
-
|
38
|
-
|
40
|
+
rpc_client.call request, options
|
41
|
+
end
|
42
|
+
|
43
|
+
# publisher is a singleton object
|
44
|
+
def publisher
|
45
|
+
if !@publisher
|
46
|
+
@sneakers_packer_mutex.synchronize {
|
47
|
+
@publisher ||= ::Sneakers::Publisher.new
|
48
|
+
}
|
49
|
+
end
|
50
|
+
@publisher
|
51
|
+
end
|
52
|
+
|
53
|
+
# message_packer is a singleton object
|
54
|
+
def message_packer
|
55
|
+
if !@message_packer
|
56
|
+
@sneakers_packer_mutex.synchronize {
|
57
|
+
@message_packer ||= MessagePacker.new(self.conf.app_name)
|
58
|
+
}
|
59
|
+
end
|
60
|
+
@message_packer
|
61
|
+
end
|
39
62
|
|
40
|
-
|
41
|
-
|
42
|
-
|
63
|
+
def rpc_client
|
64
|
+
if !@rpc_client
|
65
|
+
_publisher = publisher
|
66
|
+
@sneakers_packer_mutex.synchronize {
|
67
|
+
@rpc_client ||= RpcClient.new(_publisher)
|
68
|
+
}
|
69
|
+
end
|
70
|
+
@rpc_client
|
71
|
+
end
|
43
72
|
end
|
44
73
|
end
|
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: sneakers_packer
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.1.
|
4
|
+
version: 0.1.5
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- vincent
|
8
8
|
autorequire:
|
9
9
|
bindir: exe
|
10
10
|
cert_chain: []
|
11
|
-
date: 2016-
|
11
|
+
date: 2016-07-12 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: sneakers
|
@@ -106,16 +106,16 @@ files:
|
|
106
106
|
- ".travis.yml"
|
107
107
|
- CHANGELOG.md
|
108
108
|
- Gemfile
|
109
|
-
- LICENSE.
|
109
|
+
- LICENSE.md
|
110
110
|
- README.md
|
111
111
|
- Rakefile
|
112
|
-
- bin/console
|
113
|
-
- bin/setup
|
114
112
|
- lib/sneakers_packer.rb
|
115
113
|
- lib/sneakers_packer/common_worker.rb
|
116
114
|
- lib/sneakers_packer/configuration.rb
|
117
115
|
- lib/sneakers_packer/message_packer.rb
|
118
116
|
- lib/sneakers_packer/rpc_client.rb
|
117
|
+
- lib/sneakers_packer/rpc_reply_subscriber.rb
|
118
|
+
- lib/sneakers_packer/rpc_request.rb
|
119
119
|
- lib/sneakers_packer/rpc_worker.rb
|
120
120
|
- lib/sneakers_packer/version.rb
|
121
121
|
- sneakers_packer.gemspec
|
data/bin/console
DELETED
@@ -1,14 +0,0 @@
|
|
1
|
-
#!/usr/bin/env ruby
|
2
|
-
|
3
|
-
require "bundler/setup"
|
4
|
-
require "sneakers_packer"
|
5
|
-
|
6
|
-
# You can add fixtures and/or initialization code here to make experimenting
|
7
|
-
# with your gem easier. You can also use a different console, if you like.
|
8
|
-
|
9
|
-
# (If you use this, don't forget to add pry to your Gemfile!)
|
10
|
-
# require "pry"
|
11
|
-
# Pry.start
|
12
|
-
|
13
|
-
require "irb"
|
14
|
-
IRB.start
|