carrot_rpc 0.4.1 → 0.5.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.
- checksums.yaml +4 -4
- data/CHANGELOG.md +30 -0
- data/README.md +16 -3
- data/carrot_rpc.gemspec +2 -0
- data/lib/carrot_rpc/client_actions.rb +34 -0
- data/lib/carrot_rpc/configuration.rb +6 -3
- data/lib/carrot_rpc/error/code.rb +1 -1
- data/lib/carrot_rpc/exception.rb +5 -0
- data/lib/carrot_rpc/rpc_client.rb +72 -47
- data/lib/carrot_rpc/server_runner/pid.rb +1 -1
- data/lib/carrot_rpc/server_runner/signals.rb +1 -1
- data/lib/carrot_rpc/version.rb +1 -1
- data/lib/carrot_rpc.rb +2 -0
- metadata +18 -2
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 7021e60c18d67242d796d0a7989d0b6ba411bd2f
|
4
|
+
data.tar.gz: 2a857193768aafda74326c94339132e71d30ba65
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: d244349b6f223b3bc3104075a766084054d7e15aab8d419c7e2a0c12c8cc63ac9b2554366ad56975dff3972463d40867aaa1a931c608a661695e25f6c358168f
|
7
|
+
data.tar.gz: 3f74c94e6af796112817eb92de1401767e837fe06ee4d9356473cffabdecb8ce8e896a16f86c3c74d007cd3f1fab899c8bbcca9a8f0f4f020031a6f35f60f248
|
data/CHANGELOG.md
CHANGED
@@ -34,6 +34,36 @@
|
|
34
34
|
# Changelog
|
35
35
|
All significant changes in the project are documented here.
|
36
36
|
|
37
|
+
## v.0.5.0
|
38
|
+
### Enhancements
|
39
|
+
* [#25](https://github.com/C-S-D/carrot_rpc/pull/25) - [shamil614](https://github.com/shamil614)
|
40
|
+
* Timeout RpcClient requests when response is not received.
|
41
|
+
* Default timeout is 5 seconds.
|
42
|
+
* Timeout is configurable.
|
43
|
+
* [#27](https://github.com/C-S-D/carrot_rpc/pull/27) - [shamil614](https://github.com/shamil614)
|
44
|
+
* Simplify RpcClient usage.
|
45
|
+
* Each request which goes through `RpcClient.remote_request` ultimately needs to use a unique `reply_queue` on eqch request.
|
46
|
+
* By closing the channel and opening a new channel on each request we ensure that cleanup takes place by the deletion of the `reply_queue`.
|
47
|
+
* [#29](https://github.com/C-S-D/carrot_rpc/pull/29) - [shamil614](https://github.com/shamil614)
|
48
|
+
* Implementations of the RpcClient need to be flexible with the key formatter.
|
49
|
+
* Formatting can be set globally via `Configuration`, overridden via passing Configuration object upon initializing client, or redefine `response_key_formatter` `request_key_formatter` methods.
|
50
|
+
|
51
|
+
### Incompatible Changes
|
52
|
+
* [#27](https://github.com/C-S-D/carrot_rpc/pull/27) - [shamil614](https://github.com/shamil614)
|
53
|
+
* Calling `rpc_client.start` and `rpc_client.channel.close` are no longer required when calling `rpc_client.remote_call` or the methods that call it (`index` `create`, etc).
|
54
|
+
* Calling `rpc_client.channel.close` after `rpc_client.remote_call` will cause an Exception to be raised as the channel is already closed.
|
55
|
+
* [#29](https://github.com/C-S-D/carrot_rpc/pull/29) - [shamil614](https://github.com/shamil614)
|
56
|
+
* Replaced hard coded key formatter in place of a configurable option.
|
57
|
+
* Need to set the following in config to maintain previous behavior
|
58
|
+
```ruby
|
59
|
+
CarrotRpc.configure do |config|
|
60
|
+
# RpcServers expect the params to be dashed.
|
61
|
+
config.rpc_client_request_key_format = :dasherize
|
62
|
+
# In most cases the RpcClient instances use JSONAPI::Resource classes and the keys need to be transformed.
|
63
|
+
config.rpc_client_response_key_format = :underscore
|
64
|
+
end
|
65
|
+
```
|
66
|
+
|
37
67
|
## v0.4.1
|
38
68
|
### Bug Fixes
|
39
69
|
* [#23](https://githb.com/C-S-D/carrot_rpc/pull/23) - [shamil614](https://github.com/shamil614)
|
data/README.md
CHANGED
@@ -86,6 +86,12 @@ CarrotRpc.configure do |config|
|
|
86
86
|
config.logger = CarrotRpc::TaggedLog.new(logger: Rails.logger, tags: ["Carrot RPC Client"])
|
87
87
|
# Set a Proc to allow manipulation of the params on the RpcClient before the request is sent.
|
88
88
|
config.before_request = proc { |params| params.merge(foo: "bar") }
|
89
|
+
# Number of seconds to wait before a RPC Client request timesout. Default 5 seconds.
|
90
|
+
config.rpc_client_timeout = 5
|
91
|
+
# Formats hash keys to stringified and replaces "_" with "-". Default is `:none` for no formatting.
|
92
|
+
config.rpc_client_request_key_format = :dasherize
|
93
|
+
# Formats hash keys to stringified and replaces "-" with "_". Default is `:none` for no formatting.
|
94
|
+
config.rpc_client_response_key_format = :underscore
|
89
95
|
|
90
96
|
# Don't use. Server implementation only. The values below are set via CLI:
|
91
97
|
# config.pidfile = nil
|
@@ -160,14 +166,21 @@ class CarsController < ApplicationController
|
|
160
166
|
|
161
167
|
def show
|
162
168
|
car_client = CarClient.new
|
163
|
-
car_client.start
|
164
169
|
result = car_client.show({id: 1})
|
165
|
-
# Good idea to clean up connections when finished.
|
166
|
-
car_client.channel.close
|
167
170
|
end
|
168
171
|
end
|
169
172
|
```
|
170
173
|
|
174
|
+
One way to implement a RpcClient is to override the default configuration.
|
175
|
+
```ruby
|
176
|
+
config = CarrotRPC.configuration.clone
|
177
|
+
# Now only this one object will format keys as dashes
|
178
|
+
config.rpc_client_response_key_format = :dasherize
|
179
|
+
|
180
|
+
car_client = CarClient.new(config)
|
181
|
+
```
|
182
|
+
By duplicating the `Configuration` instance you can override the global configuration and pass a custom configuration to the RpcClient instance.
|
183
|
+
|
171
184
|
### Support for JSONAPI::Resources
|
172
185
|
In the case that you're writing an application that uses the `jsonapi-resources` gem and you want the `RpcServer` to have the same functionality, then we got you covered. All you need to do is import a few modules. See [jsonapi-resources](https://github.com/cerebris/jsonapi-resources) for details on how to implement resources for your models.
|
173
186
|
|
data/carrot_rpc.gemspec
CHANGED
@@ -44,6 +44,8 @@ Gem::Specification.new do |spec|
|
|
44
44
|
spec.add_development_dependency "rspec"
|
45
45
|
# Style-checker
|
46
46
|
spec.add_development_dependency "rubocop", "~> 0.36.0"
|
47
|
+
# Documentation
|
48
|
+
spec.add_development_dependency "yard", "~> 0.8"
|
47
49
|
|
48
50
|
spec.required_ruby_version = "~> 2.2"
|
49
51
|
end
|
@@ -0,0 +1,34 @@
|
|
1
|
+
# Methods similar to rails controller actions for RpcClient
|
2
|
+
module CarrotRpc::ClientActions
|
3
|
+
# Convience method as a resource alias for index action.
|
4
|
+
# To customize, override the method in your class.
|
5
|
+
#
|
6
|
+
# @param params [Hash] the arguments for the method being called.
|
7
|
+
def index(params)
|
8
|
+
remote_call("index", params)
|
9
|
+
end
|
10
|
+
|
11
|
+
# Convience method as a resource alias for show action.
|
12
|
+
# To customize, override the method in your class.
|
13
|
+
#
|
14
|
+
# @param params [Hash] the arguments for the method being called.
|
15
|
+
def show(params)
|
16
|
+
remote_call("show", params)
|
17
|
+
end
|
18
|
+
|
19
|
+
# Convience method as a resource alias for create action.
|
20
|
+
# To customize, override the method in your class.
|
21
|
+
#
|
22
|
+
# @param params [Hash] the arguments for the method being called.
|
23
|
+
def create(params)
|
24
|
+
remote_call("create", params)
|
25
|
+
end
|
26
|
+
|
27
|
+
# Convience method as a resource alias for update action.
|
28
|
+
# To customize, override the method in your class.
|
29
|
+
#
|
30
|
+
# @param params [Hash] the arguments for the method being called.
|
31
|
+
def update(params)
|
32
|
+
remote_call("update", params)
|
33
|
+
end
|
34
|
+
end
|
@@ -1,11 +1,11 @@
|
|
1
1
|
# Global configuration for {CarrotRpc}. Access with {CarrotRpc.configuration}.
|
2
2
|
class CarrotRpc::Configuration
|
3
3
|
attr_accessor :logger, :logfile, :loglevel, :daemonize, :pidfile, :runloop_sleep, :autoload_rails, :bunny,
|
4
|
-
:before_request
|
4
|
+
:before_request, :rpc_client_timeout, :rpc_client_response_key_format, :rpc_client_request_key_format
|
5
5
|
|
6
6
|
# logfile - set logger to a file. overrides rails logger.
|
7
7
|
|
8
|
-
def initialize
|
8
|
+
def initialize # rubocop:disable Metrics/MethodLength
|
9
9
|
@logfile = nil
|
10
10
|
@loglevel = Logger::DEBUG
|
11
11
|
@logger = nil
|
@@ -15,5 +15,8 @@ class CarrotRpc::Configuration
|
|
15
15
|
@autoload_rails = true
|
16
16
|
@bunny = nil
|
17
17
|
@before_request = nil
|
18
|
-
|
18
|
+
@rpc_client_timeout = 5
|
19
|
+
@rpc_client_response_key_format = :none
|
20
|
+
@rpc_client_request_key_format = :none
|
21
|
+
end # rubocop:enable Metrics/MethodLength
|
19
22
|
end
|
@@ -9,6 +9,7 @@ class CarrotRpc::RpcClient
|
|
9
9
|
attr_reader :channel, :server_queue, :logger
|
10
10
|
|
11
11
|
extend CarrotRpc::ClientServer
|
12
|
+
include CarrotRpc::ClientActions
|
12
13
|
|
13
14
|
def self.before_request(*proc)
|
14
15
|
if proc.length == 0
|
@@ -20,12 +21,44 @@ class CarrotRpc::RpcClient
|
|
20
21
|
end
|
21
22
|
end
|
22
23
|
|
23
|
-
#
|
24
|
-
#
|
25
|
-
|
26
|
-
|
27
|
-
|
28
|
-
|
24
|
+
# Logic to process the renaming of keys in a hash.
|
25
|
+
# @param format [Symbol] :dasherize changes keys that have "_" to "-"
|
26
|
+
# @param format [Symbol] :underscore changes keys that have "-" to "_"
|
27
|
+
# @param format [Symbol] :skip, will not rename the keys
|
28
|
+
# @param data [Hash] data structure to be transformed
|
29
|
+
# @return [Hash] the transformed data
|
30
|
+
def self.format_keys(format, data)
|
31
|
+
case format
|
32
|
+
when :dasherize
|
33
|
+
data.rename_keys("_", "-")
|
34
|
+
when :underscore
|
35
|
+
data.rename_keys("-", "_")
|
36
|
+
when :none
|
37
|
+
data
|
38
|
+
else
|
39
|
+
data
|
40
|
+
end
|
41
|
+
end
|
42
|
+
|
43
|
+
# Use defaults for application level connection to RabbitMQ.
|
44
|
+
#
|
45
|
+
# @example pass custom {Configuration} class as an argument to override.
|
46
|
+
# config = CarrotRpc::Configuration.new
|
47
|
+
# config.rpc_client_timeout = 10
|
48
|
+
# CarrotRpc::RpcClient.new(config)
|
49
|
+
def initialize(config = nil)
|
50
|
+
@config = config || CarrotRpc.configuration
|
51
|
+
@logger = @config.logger
|
52
|
+
end
|
53
|
+
|
54
|
+
# Starts the connection to listen for messages.
|
55
|
+
#
|
56
|
+
# All RpcClient requests go to the a single @server_queue
|
57
|
+
# Responses come back over a unique queue name.
|
58
|
+
def start
|
59
|
+
# Create a new channel on each request because the channel should be closed after each request.
|
60
|
+
@channel = @config.bunny.create_channel
|
61
|
+
|
29
62
|
# auto_delete => false keeps the queue around until RabbitMQ restarts or explicitly deleted
|
30
63
|
@server_queue = @channel.queue(self.class.queue_name, auto_delete: false)
|
31
64
|
|
@@ -33,8 +66,7 @@ class CarrotRpc::RpcClient
|
|
33
66
|
@exchange = @channel.default_exchange
|
34
67
|
end
|
35
68
|
|
36
|
-
|
37
|
-
def start
|
69
|
+
def subscribe
|
38
70
|
# Empty queue name ends up creating a randomly named queue by RabbitMQ
|
39
71
|
# Exclusive => queue will be deleted when connection closes. Allows for automatic "cleanup".
|
40
72
|
@reply_queue = @channel.queue("", exclusive: true)
|
@@ -45,9 +77,10 @@ class CarrotRpc::RpcClient
|
|
45
77
|
# setup subscribe block to Service
|
46
78
|
# block => false is a non blocking IO option.
|
47
79
|
@reply_queue.subscribe(block: false) do |_delivery_info, properties, payload|
|
48
|
-
response = JSON.parse(payload).
|
80
|
+
response = JSON.parse(payload).with_indifferent_access
|
49
81
|
|
50
82
|
result = parse_response(response)
|
83
|
+
result = response_key_formatter(result).with_indifferent_access if result.is_a? Hash
|
51
84
|
@results[properties[:correlation_id]].push(result)
|
52
85
|
end
|
53
86
|
end
|
@@ -61,20 +94,44 @@ class CarrotRpc::RpcClient
|
|
61
94
|
# @param params [Hash] the arguments for the method being called.
|
62
95
|
# @return [Object] the result of the method call.
|
63
96
|
def remote_call(remote_method, params)
|
97
|
+
start
|
98
|
+
subscribe
|
64
99
|
correlation_id = SecureRandom.uuid
|
65
100
|
params = self.class.before_request.call(params) if self.class.before_request
|
66
|
-
publish(correlation_id: correlation_id, method: remote_method, params: params
|
101
|
+
publish(correlation_id: correlation_id, method: remote_method, params: request_key_formatter(params))
|
67
102
|
wait_for_result(correlation_id)
|
68
103
|
end
|
69
104
|
|
70
105
|
def wait_for_result(correlation_id)
|
71
|
-
#
|
72
|
-
|
73
|
-
|
74
|
-
|
75
|
-
|
106
|
+
# Should be good to timeout here because we're blocking in the main thread here.
|
107
|
+
Timeout.timeout(@config.rpc_client_timeout, CarrotRpc::Exception::RpcClientTimeout) do
|
108
|
+
# `pop` is `Queue#pop`, so it is blocking on the receiving thread
|
109
|
+
# and this must happend before the `Hash.delete` or
|
110
|
+
# the receiving thread won't be able to find the correlation_id in @results
|
111
|
+
result = @results[correlation_id].pop
|
112
|
+
@results.delete correlation_id # remove item from hash. prevents memory leak.
|
113
|
+
result
|
114
|
+
end
|
115
|
+
ensure
|
116
|
+
@channel.close
|
117
|
+
end
|
118
|
+
|
119
|
+
# Formats keys in the response data.
|
120
|
+
# @param payload [Hash] response data received from the remote server.
|
121
|
+
# @return [Hash] formatted data structure.
|
122
|
+
def response_key_formatter(payload)
|
123
|
+
self.class.format_keys @config.rpc_client_response_key_format, payload
|
124
|
+
end
|
125
|
+
|
126
|
+
# Formats keys in the request data.
|
127
|
+
# @param payload [Hash] request data to be sent to the remote server.
|
128
|
+
# @return [Hash] formatted data structure.
|
129
|
+
def request_key_formatter(params)
|
130
|
+
self.class.format_keys @config.rpc_client_request_key_format, params
|
76
131
|
end
|
77
132
|
|
133
|
+
# A @reply_queue is deleted when the channel is closed.
|
134
|
+
# Closing the channel accounts for cleanup of the client @reply_queue.
|
78
135
|
def publish(correlation_id:, method:, params:)
|
79
136
|
message = message(
|
80
137
|
correlation_id: correlation_id,
|
@@ -96,38 +153,6 @@ class CarrotRpc::RpcClient
|
|
96
153
|
}
|
97
154
|
end
|
98
155
|
|
99
|
-
# Convience method as a resource alias for index action.
|
100
|
-
# To customize, override the method in your class.
|
101
|
-
#
|
102
|
-
# @param params [Hash] the arguments for the method being called.
|
103
|
-
def index(params)
|
104
|
-
remote_call("index", params)
|
105
|
-
end
|
106
|
-
|
107
|
-
# Convience method as a resource alias for show action.
|
108
|
-
# To customize, override the method in your class.
|
109
|
-
#
|
110
|
-
# @param params [Hash] the arguments for the method being called.
|
111
|
-
def show(params)
|
112
|
-
remote_call("show", params)
|
113
|
-
end
|
114
|
-
|
115
|
-
# Convience method as a resource alias for create action.
|
116
|
-
# To customize, override the method in your class.
|
117
|
-
#
|
118
|
-
# @param params [Hash] the arguments for the method being called.
|
119
|
-
def create(params)
|
120
|
-
remote_call("create", params)
|
121
|
-
end
|
122
|
-
|
123
|
-
# Convience method as a resource alias for update action.
|
124
|
-
# To customize, override the method in your class.
|
125
|
-
#
|
126
|
-
# @param params [Hash] the arguments for the method being called.
|
127
|
-
def update(params)
|
128
|
-
remote_call("update", params)
|
129
|
-
end
|
130
|
-
|
131
156
|
private
|
132
157
|
|
133
158
|
# Logic to find the data from the RPC response.
|
@@ -75,7 +75,7 @@ class CarrotRpc::ServerRunner::Pid
|
|
75
75
|
|
76
76
|
## Instance Methods
|
77
77
|
|
78
|
-
# Exits if
|
78
|
+
# Exits if status indicates server is already running, otherwise deletes {#path}.
|
79
79
|
#
|
80
80
|
# @return [void]
|
81
81
|
def check
|
data/lib/carrot_rpc/version.rb
CHANGED
data/lib/carrot_rpc.rb
CHANGED
@@ -18,9 +18,11 @@ module CarrotRpc
|
|
18
18
|
extend ActiveSupport::Autoload
|
19
19
|
|
20
20
|
autoload :CLI
|
21
|
+
autoload :ClientActions
|
21
22
|
autoload :ClientServer
|
22
23
|
autoload :Configuration
|
23
24
|
autoload :Error
|
25
|
+
autoload :Exception
|
24
26
|
autoload :HashExtensions
|
25
27
|
autoload :RpcClient
|
26
28
|
autoload :RpcServer
|
metadata
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: carrot_rpc
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.
|
4
|
+
version: 0.5.0
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Scott Hamilton
|
@@ -9,7 +9,7 @@ authors:
|
|
9
9
|
autorequire:
|
10
10
|
bindir: bin
|
11
11
|
cert_chain: []
|
12
|
-
date: 2016-
|
12
|
+
date: 2016-05-02 00:00:00.000000000 Z
|
13
13
|
dependencies:
|
14
14
|
- !ruby/object:Gem::Dependency
|
15
15
|
name: activesupport
|
@@ -109,6 +109,20 @@ dependencies:
|
|
109
109
|
- - "~>"
|
110
110
|
- !ruby/object:Gem::Version
|
111
111
|
version: 0.36.0
|
112
|
+
- !ruby/object:Gem::Dependency
|
113
|
+
name: yard
|
114
|
+
requirement: !ruby/object:Gem::Requirement
|
115
|
+
requirements:
|
116
|
+
- - "~>"
|
117
|
+
- !ruby/object:Gem::Version
|
118
|
+
version: '0.8'
|
119
|
+
type: :development
|
120
|
+
prerelease: false
|
121
|
+
version_requirements: !ruby/object:Gem::Requirement
|
122
|
+
requirements:
|
123
|
+
- - "~>"
|
124
|
+
- !ruby/object:Gem::Version
|
125
|
+
version: '0.8'
|
112
126
|
description: Streamlined approach to setting up RPC over RabbitMQ.
|
113
127
|
email:
|
114
128
|
- shamil614@gmail.com
|
@@ -138,10 +152,12 @@ files:
|
|
138
152
|
- circle.yml
|
139
153
|
- lib/carrot_rpc.rb
|
140
154
|
- lib/carrot_rpc/cli.rb
|
155
|
+
- lib/carrot_rpc/client_actions.rb
|
141
156
|
- lib/carrot_rpc/client_server.rb
|
142
157
|
- lib/carrot_rpc/configuration.rb
|
143
158
|
- lib/carrot_rpc/error.rb
|
144
159
|
- lib/carrot_rpc/error/code.rb
|
160
|
+
- lib/carrot_rpc/exception.rb
|
145
161
|
- lib/carrot_rpc/hash_extensions.rb
|
146
162
|
- lib/carrot_rpc/rpc_client.rb
|
147
163
|
- lib/carrot_rpc/rpc_server.rb
|