fluffle 0.2.0 → 0.2.1

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: 2de3913524a4ba8c3270b96d5272f806c1b307e1
4
- data.tar.gz: f2d2d81a77fed5dd7ed95a79e70e986c53c5bca4
3
+ metadata.gz: 255eee82ad3d15d6a7b9623e2abc52327c0b029c
4
+ data.tar.gz: 9d0496f43f6f63e85b8de2d861d516959ec92cb5
5
5
  SHA512:
6
- metadata.gz: b33a3af2b4958527059766387e030d491d56ee05dbfc6e3141f57255f0c664680e575319fd2aa4cd38bbe7ae1466e6e00da17d82c111c81fc29bfa7c33b9a263
7
- data.tar.gz: a92a7984a455c82071dd492b50fa87ad9d81aa86bb7a6059fdc51a707a056e4fc9b505aa62678d2c1689cfad228cbb1a1953459f01143a93fa55ae5fdae32032
6
+ metadata.gz: 5dad9fde293a176c4b3f9cfe1c8dcc3cee2359f683db422d3e8a1f0273be9d84e57b5c24b1bd044a8f7416db58fa9d96551c87d4c1c19ee1e75ad31df9165e8c
7
+ data.tar.gz: 1d5e676a4db1978eda8e987c56d045ae137cd06345917ad10a0678db108d1b18d8240f9c2361ed47b00f4d512690443e3910fa99450e412198bd460b86e8cce7
data/README.md CHANGED
@@ -14,8 +14,10 @@ An implementation of [JSON-RPC][] over RabbitMQ through the [Bunny][] library. P
14
14
 
15
15
  ## Features
16
16
 
17
- - Client: Thread-safe blocking client (via [concurrent-ruby][])
18
- - Server: One-thread-per-queue implementation (multi-threaded coming soon)
17
+ Both the client and server implementations should be thread-safe, as their behavior is implemented on top of the excellent [concurrent-ruby][] gem's data structures.
18
+
19
+ - Client: Thread-safe client that can perform multiple requests concurrently
20
+ - Server: Single or multi-threaded server (one request/response per thread)
19
21
  - Server: Easy-to-use built-in handlers and straightforward API for building custom handlers
20
22
 
21
23
  [concurrent-ruby]: https://github.com/ruby-concurrency/concurrent-ruby
@@ -26,9 +28,41 @@ See the [`examples`](examples/) directory.
26
28
 
27
29
  The server provides a few options for handling RPC requests:
28
30
 
29
- - Dispatcher pattern: `dispatcher.handle('upcase') { |str| str.upcase }`
30
- - Delegator pattern: delegate will receive the `#upcase` message with a single argument (the string)
31
- - Custom: any handler needs to implement the API described in `Fluffle::Handlers::Base`
31
+ - [Dispatcher](lib/fluffle/handlers/dispatcher.rb): `dispatcher.handle('upcase') { |str| str.upcase }`
32
+ - [Delegator](lib/fluffle/handlers/delegator.rb): delegate will receive the `#upcase` message with a single argument (the string)
33
+ - Custom: any handler needs to implement the API described in [`Fluffle::Handlers::Base`](lib/fluffle/handlers/base.rb)
34
+
35
+ ### Basic server and client
36
+
37
+ A server has two basic requirements: the URL of a RabbitMQ server to connect to and one or more queues to drain (with a handler for each queue).
38
+
39
+ Below is a basic server providing an `upcase` method to return the upper cased version of its argument:
40
+
41
+ ```ruby
42
+ require 'fluffle'
43
+
44
+ server = Fluffle::Server.new url: 'amqp://localhost'
45
+
46
+ server.drain do |dispatcher|
47
+ dispatcher.handle('upcase') { |str| str.upcase }
48
+ end
49
+
50
+ server.start
51
+ ```
52
+
53
+ This example relies on a couple features of `Server#drain`:
54
+
55
+ 1. By default it will drain the `default` queue.
56
+ 2. You can provide a block to the method to have it set up a [`Dispatcher`](lib/fluffle/handlers/dispatcher.rb) handler and pass that in to the block.
57
+
58
+ And client to call that `upcase` method looks like:
59
+
60
+ ```ruby
61
+ client = Fluffle::Client.new url: 'amqp://localhost'
62
+
63
+ client.call 'upcase', ['Hello world!']
64
+ # => "HELLO WORLD!"
65
+ ```
32
66
 
33
67
  ## License
34
68
 
data/examples/client.rb CHANGED
@@ -4,6 +4,8 @@ $LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
4
4
  require 'fluffle'
5
5
 
6
6
  client = Fluffle::Client.new url: 'amqp://localhost'
7
+ # You can also pass `connection:` to use an existing Bunny connection:
8
+ # Fluffle::Client.new(connection: Bunny.new('amqp://localhost', heartbeat: 2))
7
9
 
8
10
  timings = 10.times.map do
9
11
  t0 = Time.now
data/examples/server.rb CHANGED
@@ -3,7 +3,7 @@ $LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
3
3
 
4
4
  require 'fluffle'
5
5
 
6
- server = Fluffle::Server.new url: 'amqp://localhost'
6
+ server = Fluffle::Server.new url: 'amqp://localhost', concurrency: 5
7
7
 
8
8
  server.drain do |dispatcher|
9
9
  dispatcher.handle('foo') { 'bar' }
@@ -12,12 +12,12 @@ module Fluffle
12
12
  attr_accessor :default_timeout
13
13
  attr_accessor :logger
14
14
 
15
- def initialize(url:)
15
+ def initialize(url: nil, connection: nil)
16
+ self.connect(url || connection)
17
+
16
18
  @default_timeout = 5
17
19
  @logger = Fluffle.logger
18
20
 
19
- self.connect url
20
-
21
21
  @uuid = UUIDTools::UUID.timestamp_create.to_s
22
22
  @channel = @connection.create_channel
23
23
  @exchange = @channel.default_exchange
@@ -9,7 +9,13 @@ module Fluffle
9
9
  def connect(*args)
10
10
  self.stop if self.connected?
11
11
 
12
- @connection = Bunny.new *args
12
+ @connection =
13
+ if args.first.is_a? Bunny::Session
14
+ args.first
15
+ else
16
+ Bunny.new *args
17
+ end
18
+
13
19
  @connection.start
14
20
  end
15
21
 
@@ -6,8 +6,9 @@ module Fluffle
6
6
 
7
7
  # url: - Optional URL to pass to `Bunny.new` to immediately connect
8
8
  # concurrency: - Number of threads to handle messages on (default: 1)
9
- def initialize(url: nil, concurrency: 1)
10
- self.connect(url) if url
9
+ def initialize(url: nil, connection: nil, concurrency: 1)
10
+ url_or_connection = url || connection
11
+ self.connect(url_or_connection) if url_or_connection
11
12
 
12
13
  @handlers = {}
13
14
  @handler_pool = Concurrent::FixedThreadPool.new concurrency
@@ -1,3 +1,3 @@
1
1
  module Fluffle
2
- VERSION = '0.2.0'
2
+ VERSION = '0.2.1'
3
3
  end
data/spec/client_spec.rb CHANGED
@@ -13,6 +13,33 @@ describe Fluffle::Client do
13
13
  end
14
14
  end
15
15
 
16
+ describe '#initialize' do
17
+ it 'allows user to pass an `amqp://` URL via `url:`' do
18
+ client = Fluffle::Client.new url: 'amqp://localhost'
19
+
20
+ expect(client.connection).to be_a Bunny::Session
21
+ expect(client.connected?).to eq true
22
+ end
23
+
24
+ it 'allows user to provide existing Bunny connection via `connection:`' do
25
+ bunny_channel = double 'Bunny::Channel',
26
+ default_exchange: double('Bunny::Exchange'),
27
+ queue: double('Bunny::Queue', subscribe: nil)
28
+
29
+ bunny_session = double 'Bunny::Session',
30
+ create_channel: bunny_channel,
31
+ start: nil,
32
+ connected?: true
33
+
34
+ allow(bunny_session).to receive(:is_a?).with(Bunny::Session).and_return(true)
35
+
36
+ client = Fluffle::Client.new connection: bunny_session
37
+
38
+ expect(client.connection).to eq bunny_session
39
+ expect(client.connected?).to eq true
40
+ end
41
+ end
42
+
16
43
  describe '#call' do
17
44
  def prepare_response(payload)
18
45
  ->(id) do
@@ -0,0 +1,26 @@
1
+ require 'spec_helper'
2
+
3
+ describe Fluffle::Handlers::Delegator do
4
+ before do
5
+ @delegated_object = double 'Delegated Object'
6
+
7
+ @handler = Fluffle::Handlers::Delegator.new @delegated_object
8
+ end
9
+
10
+ it 'calls the method with the params on the delegated object' do
11
+ param1 = 'One'
12
+ param2 = 'Two'
13
+ result = 'Three'
14
+
15
+ expect(@delegated_object).to receive(:some_method)
16
+ .with(param1, param2)
17
+ .and_return(result)
18
+
19
+ actual_result = @handler.call id: 'abc123',
20
+ method: 'some_method',
21
+ params: [param1, param2],
22
+ meta: {}
23
+
24
+ expect(actual_result).to eq(result)
25
+ end
26
+ end
@@ -0,0 +1,27 @@
1
+ require 'spec_helper'
2
+
3
+ describe Fluffle::Handlers::Dispatcher do
4
+ before do
5
+ @handler = Fluffle::Handlers::Dispatcher.new
6
+
7
+ @handler.handle('double_it') { |arg| arg * 2 }
8
+ end
9
+
10
+ it 'calls the method with the params on the delegated object' do
11
+ result = @handler.call id: 'abc123',
12
+ method: 'double_it',
13
+ params: [2],
14
+ meta: {}
15
+
16
+ expect(result).to eq(4)
17
+ end
18
+
19
+ it 'raises error if method not configured' do
20
+ expect {
21
+ @handler.call id: 'def456',
22
+ method: 'doesnt_exist',
23
+ params: ['whatever'],
24
+ meta: {}
25
+ }.to raise_error(NoMethodError, /doesnt_exist/)
26
+ end
27
+ end
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: fluffle
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.2.0
4
+ version: 0.2.1
5
5
  platform: ruby
6
6
  authors:
7
7
  - Dirk Gadsden
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2016-08-14 00:00:00.000000000 Z
11
+ date: 2016-08-15 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: bunny
@@ -139,6 +139,8 @@ files:
139
139
  - lib/fluffle/testing.rb
140
140
  - lib/fluffle/version.rb
141
141
  - spec/client_spec.rb
142
+ - spec/handlers/delegator_spec.rb
143
+ - spec/handlers/dispatcher_spec.rb
142
144
  - spec/server_spec.rb
143
145
  - spec/spec_helper.rb
144
146
  homepage: https://github.com/Everlane/fluffle