easy_bunny_rpc 0.1.0.alpha
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 +7 -0
- data/.gitignore +5 -0
- data/ChangeLog.rdoc +4 -0
- data/Gemfile +3 -0
- data/LICENSE.txt +20 -0
- data/README.md +103 -0
- data/Rakefile +24 -0
- data/easy_bunny_rpc.gemspec +25 -0
- data/lib/easy_bunny_rpc.rb +5 -0
- data/lib/easy_bunny_rpc/client.rb +72 -0
- data/lib/easy_bunny_rpc/timed_queue.rb +37 -0
- data/lib/easy_bunny_rpc/version.rb +4 -0
- data/lib/easy_bunny_rpc/worker.rb +58 -0
- metadata +113 -0
checksums.yaml
ADDED
@@ -0,0 +1,7 @@
|
|
1
|
+
---
|
2
|
+
SHA1:
|
3
|
+
metadata.gz: 2c7753440ae7622d08014667722d7d607b5e2ff7
|
4
|
+
data.tar.gz: d6f58efefd2f73e5f2cc0dea692acae2dc14852d
|
5
|
+
SHA512:
|
6
|
+
metadata.gz: 605aba5b4e0aa19e103e7e83c7c5cff7483d66fe104fabdf420f1bdab4489d464391e5f057c60376ee1648fbeefecd24a0df92efd1e43b2fed415a259027fa4c
|
7
|
+
data.tar.gz: 2c53c15a9dd254a7a6a6032faca6e3b13ee23f00a72a24e00adf6620308e02ddc2e3aa3b36e8304a5a565c3b6816fcfb683165d4982818774b7d1ad44ca524ce
|
data/.gitignore
ADDED
data/ChangeLog.rdoc
ADDED
data/Gemfile
ADDED
data/LICENSE.txt
ADDED
@@ -0,0 +1,20 @@
|
|
1
|
+
Copyright (c) 2015 Tom van Leeuwen
|
2
|
+
|
3
|
+
Permission is hereby granted, free of charge, to any person obtaining
|
4
|
+
a copy of this software and associated documentation files (the
|
5
|
+
"Software"), to deal in the Software without restriction, including
|
6
|
+
without limitation the rights to use, copy, modify, merge, publish,
|
7
|
+
distribute, sublicense, and/or sell copies of the Software, and to
|
8
|
+
permit persons to whom the Software is furnished to do so, subject to
|
9
|
+
the following conditions:
|
10
|
+
|
11
|
+
The above copyright notice and this permission notice shall be
|
12
|
+
included in all copies or substantial portions of the Software.
|
13
|
+
|
14
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
15
|
+
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
16
|
+
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
17
|
+
NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
|
18
|
+
LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
|
19
|
+
OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
|
20
|
+
WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
data/README.md
ADDED
@@ -0,0 +1,103 @@
|
|
1
|
+
easy\_bunny\_rpc
|
2
|
+
=================
|
3
|
+
[](https://rubygems.org/gems/easy_bunny_rpc)
|
4
|
+
|
5
|
+
Generic RPC client/worker library handling data serialization built on top of bunny.
|
6
|
+
|
7
|
+
Example usage
|
8
|
+
-----
|
9
|
+
|
10
|
+
Create an EchoWorker class which simply echoes whatever is received:
|
11
|
+
|
12
|
+
``` ruby
|
13
|
+
class EchoWorker < EasyBunnyRPC::Worker
|
14
|
+
def mediate
|
15
|
+
subscribe do |payload|
|
16
|
+
publish_success(payload) # Send a success message to the client
|
17
|
+
# publish_failure(payload) # Send a failure message to the client
|
18
|
+
end
|
19
|
+
rescue Interrupt => _
|
20
|
+
# close
|
21
|
+
end
|
22
|
+
end
|
23
|
+
```
|
24
|
+
|
25
|
+
Now you can initialize it. Please note the :bunny key Hash is directly fed to Bunny.new:
|
26
|
+
|
27
|
+
``` ruby
|
28
|
+
options = {
|
29
|
+
queue: 'echo',
|
30
|
+
bunny: {
|
31
|
+
user: 'user',
|
32
|
+
password: 'secret',
|
33
|
+
host: 'localhost'
|
34
|
+
}
|
35
|
+
}
|
36
|
+
|
37
|
+
echo_worker = EchoWorker.new options
|
38
|
+
echo_worker.mediate
|
39
|
+
```
|
40
|
+
|
41
|
+
|
42
|
+
Create an EchoClient class:
|
43
|
+
|
44
|
+
``` ruby
|
45
|
+
class EchoClient < EasyBunnyRPC::Client
|
46
|
+
def perform
|
47
|
+
set_timeout(2) # timeout in seconds, default is 5
|
48
|
+
|
49
|
+
# The first argument is the payload, the send argument is the correlation_id
|
50
|
+
# The correlation_id is always send back as-is by the worker
|
51
|
+
# This way you can correlate the replies with your requests
|
52
|
+
publish('hi there', 'call 1')
|
53
|
+
publish('hi there again', 'call 2')
|
54
|
+
|
55
|
+
# Pop will raise a ::Timeout::Error when a timeout occurs and no message is received
|
56
|
+
p pop
|
57
|
+
p pop
|
58
|
+
end
|
59
|
+
end
|
60
|
+
```
|
61
|
+
|
62
|
+
Now you can initialize it:
|
63
|
+
|
64
|
+
``` ruby
|
65
|
+
options = {
|
66
|
+
queue: 'echo',
|
67
|
+
bunny: {
|
68
|
+
user: 'user',
|
69
|
+
password: 'secret',
|
70
|
+
host: 'localhost'
|
71
|
+
}
|
72
|
+
}
|
73
|
+
|
74
|
+
echo_client = EchoClient.new(options)
|
75
|
+
echo_client.perform
|
76
|
+
```
|
77
|
+
|
78
|
+
Output:
|
79
|
+
``` text
|
80
|
+
{"success"=>true, "payload"=>"hi there", "correlation_id"=>"call 1"}
|
81
|
+
{"success"=>true, "payload"=>"hi there again", "correlation_id"=>"call 2"}
|
82
|
+
```
|
83
|
+
|
84
|
+
|
85
|
+
Notes
|
86
|
+
_____
|
87
|
+
|
88
|
+
- Tested with RabbitMQ
|
89
|
+
- Uses the expiration feature of RabbitMQ to expire messages sent by the client
|
90
|
+
|
91
|
+
|
92
|
+
Install
|
93
|
+
-------
|
94
|
+
|
95
|
+
```
|
96
|
+
$ gem install easy_bunny_rpc
|
97
|
+
```
|
98
|
+
|
99
|
+
|
100
|
+
Author
|
101
|
+
------
|
102
|
+
|
103
|
+
Tom van Leeuwen, [@tvl2386](https://twitter.com/tvl2386)
|
data/Rakefile
ADDED
@@ -0,0 +1,24 @@
|
|
1
|
+
# encoding: utf-8
|
2
|
+
|
3
|
+
require 'rubygems'
|
4
|
+
|
5
|
+
begin
|
6
|
+
require 'bundler'
|
7
|
+
rescue LoadError => e
|
8
|
+
warn e.message
|
9
|
+
warn "Run `gem install bundler` to install Bundler."
|
10
|
+
exit -1
|
11
|
+
end
|
12
|
+
|
13
|
+
begin
|
14
|
+
Bundler.setup(:development)
|
15
|
+
rescue Bundler::BundlerError => e
|
16
|
+
warn e.message
|
17
|
+
warn "Run `bundle install` to install missing gems."
|
18
|
+
exit e.status_code
|
19
|
+
end
|
20
|
+
|
21
|
+
require 'rake'
|
22
|
+
|
23
|
+
require 'rubygems/tasks'
|
24
|
+
Gem::Tasks.new
|
@@ -0,0 +1,25 @@
|
|
1
|
+
# -*- encoding: utf-8 -*-
|
2
|
+
|
3
|
+
require File.expand_path('../lib/easy_bunny_rpc/version', __FILE__)
|
4
|
+
|
5
|
+
Gem::Specification.new do |gem|
|
6
|
+
gem.name = 'easy_bunny_rpc'
|
7
|
+
gem.version = EasyBunnyRPC::VERSION
|
8
|
+
gem.summary = %q{A simple rabbitmq rpc server/client library built on bunny with message serialization using json}
|
9
|
+
gem.description = gem.summary
|
10
|
+
gem.license = 'MIT'
|
11
|
+
gem.authors = ['Tom van Leeuwen']
|
12
|
+
gem.email = 'tom@vleeuwen.eu'
|
13
|
+
gem.homepage = 'https://rubygems.org/gems/easy_bunny_rpc'
|
14
|
+
|
15
|
+
gem.files = `git ls-files`.split($/)
|
16
|
+
gem.executables = gem.files.grep(%r{^bin/}).map{ |f| File.basename(f) }
|
17
|
+
gem.test_files = gem.files.grep(%r{^(test|spec|features)/})
|
18
|
+
gem.require_paths = ['lib']
|
19
|
+
|
20
|
+
gem.add_dependency 'bunny', '~> 1.7'
|
21
|
+
|
22
|
+
gem.add_development_dependency 'bundler', '~> 1.10'
|
23
|
+
gem.add_development_dependency 'rake', '~> 10.4'
|
24
|
+
gem.add_development_dependency 'rubygems-tasks', '~> 0.2'
|
25
|
+
end
|
@@ -0,0 +1,72 @@
|
|
1
|
+
require 'bunny'
|
2
|
+
require 'json'
|
3
|
+
require 'securerandom'
|
4
|
+
|
5
|
+
module EasyBunnyRPC
|
6
|
+
class Client
|
7
|
+
def initialize options={}
|
8
|
+
@options = options
|
9
|
+
@subscribed = false
|
10
|
+
|
11
|
+
# The timed queue which will collect incoming messages
|
12
|
+
@timed_queue = EasyBunnyRPC::TimedQueue.new
|
13
|
+
|
14
|
+
# Need to set a default timeout. How about 5 seconds?
|
15
|
+
set_timeout(5)
|
16
|
+
end
|
17
|
+
|
18
|
+
private
|
19
|
+
|
20
|
+
def pop
|
21
|
+
correlation_id, payload = @timed_queue.pop_with_timeout(@timeout)
|
22
|
+
|
23
|
+
JSON.parse(payload).merge!({ 'correlation_id' => correlation_id })
|
24
|
+
end
|
25
|
+
|
26
|
+
def set_timeout(value)
|
27
|
+
@timeout = value
|
28
|
+
end
|
29
|
+
|
30
|
+
def start_subscription
|
31
|
+
queue.subscribe(block: false) do |delivery_info, properties, payload|
|
32
|
+
@timed_queue.push([properties.correlation_id, payload])
|
33
|
+
end
|
34
|
+
|
35
|
+
@subscribed = true
|
36
|
+
end
|
37
|
+
|
38
|
+
def publish(payload, correlation_id=default_correlation_id)
|
39
|
+
start_subscription unless @subscribed
|
40
|
+
exchange.publish([payload].to_json, routing_key: @options[:queue], correlation_id: correlation_id, reply_to: queue.name, expiration: (@timeout*1000).to_i)
|
41
|
+
end
|
42
|
+
|
43
|
+
def connection
|
44
|
+
return @connection if defined?(@connection)
|
45
|
+
|
46
|
+
@connection = Bunny.new(@options[:bunny])
|
47
|
+
@connection.start
|
48
|
+
@connection
|
49
|
+
end
|
50
|
+
|
51
|
+
def channel
|
52
|
+
@channel ||= connection.create_channel
|
53
|
+
end
|
54
|
+
|
55
|
+
# The exclusive no-name queue that is created for communicating back to me
|
56
|
+
def queue
|
57
|
+
@queue ||= channel.queue(generate_queue_name, exclusive: true)
|
58
|
+
end
|
59
|
+
|
60
|
+
def generate_queue_name
|
61
|
+
[@options[:queue], '-client_', SecureRandom.hex].join
|
62
|
+
end
|
63
|
+
|
64
|
+
def exchange
|
65
|
+
@exchange ||= channel.default_exchange
|
66
|
+
end
|
67
|
+
|
68
|
+
def default_correlation_id
|
69
|
+
''
|
70
|
+
end
|
71
|
+
end
|
72
|
+
end
|
@@ -0,0 +1,37 @@
|
|
1
|
+
require 'thread'
|
2
|
+
require 'timeout'
|
3
|
+
|
4
|
+
module EasyBunnyRPC
|
5
|
+
class TimedQueue
|
6
|
+
def initialize
|
7
|
+
@array = Array.new
|
8
|
+
@mutex = Mutex.new
|
9
|
+
@cv = ConditionVariable.new
|
10
|
+
end
|
11
|
+
|
12
|
+
def push(item)
|
13
|
+
@mutex.synchronize do
|
14
|
+
@array.push(item)
|
15
|
+
@cv.signal
|
16
|
+
end
|
17
|
+
end
|
18
|
+
|
19
|
+
def pop_with_timeout(timeout=0.5)
|
20
|
+
timeout_at = Time.now + timeout
|
21
|
+
|
22
|
+
@mutex.synchronize do
|
23
|
+
loop do
|
24
|
+
if @array.empty?
|
25
|
+
remaining = timeout_at - Time.now
|
26
|
+
|
27
|
+
raise(Timeout::Error, "Waited #{timeout} seconds to pop") if(remaining <= 0)
|
28
|
+
|
29
|
+
@cv.wait(@mutex, remaining)
|
30
|
+
else
|
31
|
+
return @array.pop
|
32
|
+
end
|
33
|
+
end
|
34
|
+
end
|
35
|
+
end
|
36
|
+
end
|
37
|
+
end
|
@@ -0,0 +1,58 @@
|
|
1
|
+
require 'bunny'
|
2
|
+
require 'json'
|
3
|
+
|
4
|
+
module EasyBunnyRPC
|
5
|
+
class Worker
|
6
|
+
def initialize(options={})
|
7
|
+
@options = options
|
8
|
+
end
|
9
|
+
|
10
|
+
private
|
11
|
+
|
12
|
+
def subscribe
|
13
|
+
queue.subscribe(block: true) do |delivery_info, properties, payload|
|
14
|
+
@delivery_info, @properties, @payload = delivery_info, properties, payload
|
15
|
+
|
16
|
+
yield JSON.parse(payload).first
|
17
|
+
end
|
18
|
+
end
|
19
|
+
|
20
|
+
def publish(success, payload)
|
21
|
+
obj = { 'success' => success, 'payload' => payload }.to_json
|
22
|
+
|
23
|
+
exchange.publish(obj, routing_key: @properties.reply_to, correlation_id: @properties.correlation_id)
|
24
|
+
end
|
25
|
+
|
26
|
+
def publish_success(payload)
|
27
|
+
publish true, payload
|
28
|
+
end
|
29
|
+
|
30
|
+
def publish_failure(payload)
|
31
|
+
publish false, payload
|
32
|
+
end
|
33
|
+
|
34
|
+
def connection
|
35
|
+
return @connection if defined?(@connection)
|
36
|
+
|
37
|
+
@connection = Bunny.new(@options[:bunny])
|
38
|
+
@connection.start
|
39
|
+
@connection
|
40
|
+
end
|
41
|
+
|
42
|
+
def channel
|
43
|
+
return @channel if defined?(@channel)
|
44
|
+
|
45
|
+
@channel = connection.create_channel
|
46
|
+
@channel.prefetch(1)
|
47
|
+
@channel
|
48
|
+
end
|
49
|
+
|
50
|
+
def queue
|
51
|
+
@queue ||= channel.queue(@options[:queue])
|
52
|
+
end
|
53
|
+
|
54
|
+
def exchange
|
55
|
+
@exchange ||= channel.default_exchange
|
56
|
+
end
|
57
|
+
end
|
58
|
+
end
|
metadata
ADDED
@@ -0,0 +1,113 @@
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
2
|
+
name: easy_bunny_rpc
|
3
|
+
version: !ruby/object:Gem::Version
|
4
|
+
version: 0.1.0.alpha
|
5
|
+
platform: ruby
|
6
|
+
authors:
|
7
|
+
- Tom van Leeuwen
|
8
|
+
autorequire:
|
9
|
+
bindir: bin
|
10
|
+
cert_chain: []
|
11
|
+
date: 2015-06-21 00:00:00.000000000 Z
|
12
|
+
dependencies:
|
13
|
+
- !ruby/object:Gem::Dependency
|
14
|
+
name: bunny
|
15
|
+
requirement: !ruby/object:Gem::Requirement
|
16
|
+
requirements:
|
17
|
+
- - "~>"
|
18
|
+
- !ruby/object:Gem::Version
|
19
|
+
version: '1.7'
|
20
|
+
type: :runtime
|
21
|
+
prerelease: false
|
22
|
+
version_requirements: !ruby/object:Gem::Requirement
|
23
|
+
requirements:
|
24
|
+
- - "~>"
|
25
|
+
- !ruby/object:Gem::Version
|
26
|
+
version: '1.7'
|
27
|
+
- !ruby/object:Gem::Dependency
|
28
|
+
name: bundler
|
29
|
+
requirement: !ruby/object:Gem::Requirement
|
30
|
+
requirements:
|
31
|
+
- - "~>"
|
32
|
+
- !ruby/object:Gem::Version
|
33
|
+
version: '1.10'
|
34
|
+
type: :development
|
35
|
+
prerelease: false
|
36
|
+
version_requirements: !ruby/object:Gem::Requirement
|
37
|
+
requirements:
|
38
|
+
- - "~>"
|
39
|
+
- !ruby/object:Gem::Version
|
40
|
+
version: '1.10'
|
41
|
+
- !ruby/object:Gem::Dependency
|
42
|
+
name: rake
|
43
|
+
requirement: !ruby/object:Gem::Requirement
|
44
|
+
requirements:
|
45
|
+
- - "~>"
|
46
|
+
- !ruby/object:Gem::Version
|
47
|
+
version: '10.4'
|
48
|
+
type: :development
|
49
|
+
prerelease: false
|
50
|
+
version_requirements: !ruby/object:Gem::Requirement
|
51
|
+
requirements:
|
52
|
+
- - "~>"
|
53
|
+
- !ruby/object:Gem::Version
|
54
|
+
version: '10.4'
|
55
|
+
- !ruby/object:Gem::Dependency
|
56
|
+
name: rubygems-tasks
|
57
|
+
requirement: !ruby/object:Gem::Requirement
|
58
|
+
requirements:
|
59
|
+
- - "~>"
|
60
|
+
- !ruby/object:Gem::Version
|
61
|
+
version: '0.2'
|
62
|
+
type: :development
|
63
|
+
prerelease: false
|
64
|
+
version_requirements: !ruby/object:Gem::Requirement
|
65
|
+
requirements:
|
66
|
+
- - "~>"
|
67
|
+
- !ruby/object:Gem::Version
|
68
|
+
version: '0.2'
|
69
|
+
description: A simple rabbitmq rpc server/client library built on bunny with message
|
70
|
+
serialization using json
|
71
|
+
email: tom@vleeuwen.eu
|
72
|
+
executables: []
|
73
|
+
extensions: []
|
74
|
+
extra_rdoc_files: []
|
75
|
+
files:
|
76
|
+
- ".gitignore"
|
77
|
+
- ChangeLog.rdoc
|
78
|
+
- Gemfile
|
79
|
+
- LICENSE.txt
|
80
|
+
- README.md
|
81
|
+
- Rakefile
|
82
|
+
- easy_bunny_rpc.gemspec
|
83
|
+
- lib/easy_bunny_rpc.rb
|
84
|
+
- lib/easy_bunny_rpc/client.rb
|
85
|
+
- lib/easy_bunny_rpc/timed_queue.rb
|
86
|
+
- lib/easy_bunny_rpc/version.rb
|
87
|
+
- lib/easy_bunny_rpc/worker.rb
|
88
|
+
homepage: https://rubygems.org/gems/easy_bunny_rpc
|
89
|
+
licenses:
|
90
|
+
- MIT
|
91
|
+
metadata: {}
|
92
|
+
post_install_message:
|
93
|
+
rdoc_options: []
|
94
|
+
require_paths:
|
95
|
+
- lib
|
96
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
97
|
+
requirements:
|
98
|
+
- - ">="
|
99
|
+
- !ruby/object:Gem::Version
|
100
|
+
version: '0'
|
101
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
102
|
+
requirements:
|
103
|
+
- - ">"
|
104
|
+
- !ruby/object:Gem::Version
|
105
|
+
version: 1.3.1
|
106
|
+
requirements: []
|
107
|
+
rubyforge_project:
|
108
|
+
rubygems_version: 2.2.0
|
109
|
+
signing_key:
|
110
|
+
specification_version: 4
|
111
|
+
summary: A simple rabbitmq rpc server/client library built on bunny with message serialization
|
112
|
+
using json
|
113
|
+
test_files: []
|