queight 0.12.0

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml ADDED
@@ -0,0 +1,7 @@
1
+ ---
2
+ SHA1:
3
+ metadata.gz: 6cb0a3c9853d05f0b11f8164de1e704e34f7dc9b
4
+ data.tar.gz: 25ec2eab645e637174952df9ac7881bb1d47d50e
5
+ SHA512:
6
+ metadata.gz: fa1500050354a33291a531ef186cc4e3c3556bd4e92e8298063744624b3dd76ced558bda328ce3b8a7c4968f6aed5600c591683e5f5aa8de1c2800ca5dc6ab62
7
+ data.tar.gz: 679c0de375413c5ca565726154c1dc4063e026b13a8a55309274464190567b87fc01cec6dc5e31bd4df1131f16689d8779acf645c8b11ee1da686c82087609e7
data/.env ADDED
@@ -0,0 +1 @@
1
+ RABBITMQ_URL=amqp://guest:guest@localhost?size=10
data/.gitignore ADDED
@@ -0,0 +1,10 @@
1
+ /.bundle/
2
+ /.yardoc
3
+ /Gemfile.lock
4
+ /_yardoc/
5
+ /coverage/
6
+ /doc/
7
+ /pkg/
8
+ /spec/reports/
9
+ /tmp/
10
+ /.rubocop-https*
data/.rspec ADDED
@@ -0,0 +1,2 @@
1
+ --format documentation
2
+ --color
data/.rubocop.yml ADDED
@@ -0,0 +1,20 @@
1
+ inherit_from:
2
+ - https://everydayhero.github.io/styleguide/rubocop.yml
3
+
4
+ Style/FrozenStringLiteralComment:
5
+ Enabled: false
6
+
7
+ Style/RescueModifier:
8
+ Enabled: false
9
+
10
+ # 1.8 compatible :(
11
+ Style/HashSyntax:
12
+ EnforcedStyle: hash_rockets
13
+
14
+ # 1.8 compatible :(
15
+ Style/TrailingCommaInArguments:
16
+ EnforcedStyleForMultiline: no_comma
17
+
18
+ # 1.8 compatible :(
19
+ Style/NumericPredicate:
20
+ Enabled: false
data/.ruby-version ADDED
@@ -0,0 +1 @@
1
+ 2.3.1
data/.travis.yml ADDED
@@ -0,0 +1,9 @@
1
+ sudo: required
2
+ services:
3
+ - rabbitmq
4
+ language: ruby
5
+ rvm:
6
+ - ree
7
+ - 2.2.3
8
+ - 2.3.1
9
+ before_install: gem install bundler -v 1.10.6
@@ -0,0 +1,13 @@
1
+ # Contributor Code of Conduct
2
+
3
+ As contributors and maintainers of this project, we pledge to respect all people who contribute through reporting issues, posting feature requests, updating documentation, submitting pull requests or patches, and other activities.
4
+
5
+ We are committed to making participation in this project a harassment-free experience for everyone, regardless of level of experience, gender, gender identity and expression, sexual orientation, disability, personal appearance, body size, race, ethnicity, age, or religion.
6
+
7
+ Examples of unacceptable behavior by participants include the use of sexual language or imagery, derogatory comments or personal attacks, trolling, public or private harassment, insults, or other unprofessional conduct.
8
+
9
+ Project maintainers have the right and responsibility to remove, edit, or reject comments, commits, code, wiki edits, issues, and other contributions that are not aligned to this Code of Conduct. Project maintainers who do not follow the Code of Conduct may be removed from the project team.
10
+
11
+ Instances of abusive, harassing, or otherwise unacceptable behavior may be reported by opening an issue or contacting one or more of the project maintainers.
12
+
13
+ This Code of Conduct is adapted from the [Contributor Covenant](http://contributor-covenant.org), version 1.0.0, available at [http://contributor-covenant.org/version/1/0/0/](http://contributor-covenant.org/version/1/0/0/)
data/Dockerfile.ruby18 ADDED
@@ -0,0 +1,11 @@
1
+ FROM kneip/ree-1.8.7-2012.02
2
+
3
+ ENV GEM_HOME /usr/local/bundle
4
+ ENV PATH $GEM_HOME/bin:$PATH
5
+
6
+ RUN \
7
+ gem update --system && \
8
+ gem install bundler -v '~> 1.12.5' && \
9
+ bundle config --global path "$GEM_HOME" && \
10
+ bundle config --global bin "$GEM_HOME/bin" && \
11
+ true
data/Gemfile ADDED
@@ -0,0 +1,4 @@
1
+ source "https://rubygems.org"
2
+
3
+ # Specify your gem's dependencies in queight.gemspec
4
+ gemspec
data/LICENSE.txt ADDED
@@ -0,0 +1,21 @@
1
+ The MIT License (MIT)
2
+
3
+ Copyright (c) 2016 Jonathon M. Abbott
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in
13
+ all copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
21
+ THE SOFTWARE.
data/README.md ADDED
@@ -0,0 +1,136 @@
1
+ # Queight
2
+
3
+ [![Build Status](https://travis-ci.org/JonathonMA/queight.svg?branch=master)](https://travis-ci.org/JonathonMA/queight)
4
+
5
+ This is a lightweight wrapper around the `bunny` gem. It tries to handle caching the rabbitmq connection and channels in a sensible way:
6
+
7
+ - The main connection is cached globally.
8
+ - Channels are allocated from a pool since they are not thread safe.
9
+ - Channels for subscribers are allocated one-off and specify a prefetch.
10
+
11
+ This matches our normal usage of rabbitmq, with publishing happening constantly throughout usage, while subscription is usually a dedicated process.
12
+
13
+ ## Installation
14
+
15
+ Add this line to your application's Gemfile:
16
+
17
+ ```ruby
18
+ gem 'queight'
19
+ ```
20
+
21
+ And then execute:
22
+
23
+ $ bundle
24
+
25
+ Or install it yourself as:
26
+
27
+ $ gem install queight
28
+
29
+ ## Usage
30
+
31
+ First configure your environment:
32
+
33
+ RABBITMQ_URL=amqp://username:password@hostname:port
34
+
35
+ You can use the following query parameters to further customize behaviour:
36
+
37
+ | parameter | effect |
38
+ | --------- | --------------------- |
39
+ | size | connection pool size |
40
+ | id | client identification |
41
+
42
+ Then you can get a Queight client:
43
+
44
+ client = Queight.current
45
+
46
+ In order to publish messages you'll need an exchange:
47
+
48
+ topic_exchange = Queight.topic "exchange.topic"
49
+ direct_exchange = Queight.direct "exchange.direct"
50
+
51
+ And in order to subscribe to queues you'll need a queue:
52
+
53
+ queue = Queight.queue("queue.name")
54
+
55
+ Then you can just publish messages using the client and the exchange:
56
+
57
+ client.publish(topic_exchange, "message", "routing.key")
58
+
59
+ Note that publishing uses transactions by default (slow!), so if you're ok with messages hitting the floor and not knowing about it, try:
60
+
61
+ client.publish_without_transaction(topic_exchange, "message", "routing.key")
62
+ client.publish!(topic_exchange, "message", "routing.key")
63
+
64
+ You can also publish to a queue directly (using the default exchange). This will ensure the queue is declared before publishing:
65
+
66
+ client.publish_to_queue(message, queue)
67
+ client.publish_to_queue_without_transaction(message, queue)
68
+ client.publish_to_queue!(message, queue)
69
+
70
+ Queue size can be queried:
71
+
72
+ client.message_count(queue)
73
+
74
+ ### Publishing to a topic exchange
75
+
76
+ ```ruby
77
+ exchange = Queight.topic("test.exchange.topic")
78
+ message = JSON.dump(id: 1, message: "hello")
79
+ routing_key = "message.1"
80
+ client.publish(exchange, message, routing_key)
81
+ queue = Queight.queue("test.queue1")
82
+
83
+ client = Queight.current
84
+ ```
85
+
86
+ ### Binding queues
87
+
88
+ ```ruby
89
+ exchange = Queight.topic("exchange.name")
90
+ # Declare a queue and routing patterns
91
+ queue = Queight.queue("queue.name", routing: ["message.#", "reply.#"])
92
+ client.bind(exchange, queue)
93
+ ```
94
+
95
+ ### Subscribing to messages from a queue
96
+
97
+ Subscribing by default will block and require manual ack.
98
+
99
+ ``` ruby
100
+ client.subscribe(queue) do |channel, delivery_info, properties, payload|
101
+ do_something(payload)
102
+ channel.acknowledge(delivery_info.delivery_tag)
103
+ end
104
+ ```
105
+
106
+ ## Development
107
+
108
+ The `.env` file assumes a rabbitmq running on localhost with a username and password of guest. The provided docker-compose.yml let's you run one with:
109
+
110
+ docker-compose up -d
111
+
112
+ If your docker does not expose ports on localhost you may need to override this, e.g. dinghy on OS X should override in `.env.local` with:
113
+
114
+ RABBITMQ_URL=amqp://guest:guest@queight-rabbitmq-1.docker
115
+
116
+ Alternatively, you can use the provided ruby18 and ruby23 services to run tests:
117
+
118
+ docker-compose run --rm ruby18 bundle
119
+ docker-compose run --rm ruby18
120
+
121
+ docker-compose run --rm ruby23 bundle
122
+ docker-compose run --rm ruby23
123
+
124
+ After checking out the repo, run `bin/setup` to install dependencies. Then, run `rake spec` to run the tests. You can also run `bin/console` for an interactive prompt that will allow you to experiment.
125
+
126
+ To install this gem onto your local machine, run `bundle exec rake install`. To release a new version, update the version number in `version.rb`, and then run `bundle exec rake release`, which will create a git tag for the version, push git commits and tags, and push the `.gem` file to [rubygems.org](https://rubygems.org).
127
+
128
+ ## Contributing
129
+
130
+ Bug reports and pull requests are welcome on GitHub at https://github.com/JonathonMA/queight. This project is intended to be a safe, welcoming space for collaboration, and contributors are expected to adhere to the [Contributor Covenant](contributor-covenant.org) code of conduct.
131
+
132
+
133
+ ## License
134
+
135
+ The gem is available as open source under the terms of the [MIT License](http://opensource.org/licenses/MIT).
136
+
data/Rakefile ADDED
@@ -0,0 +1,12 @@
1
+ require "bundler/gem_tasks"
2
+
3
+ require "rspec/core/rake_task"
4
+ RSpec::Core::RakeTask.new(:spec)
5
+ task :default => :spec
6
+ task :default => :spec
7
+
8
+ if RUBY_VERSION >= "1.9"
9
+ require "rubocop/rake_task"
10
+ RuboCop::RakeTask.new(:rubocop)
11
+ task :default => :rubocop
12
+ end
data/bin/console ADDED
@@ -0,0 +1,14 @@
1
+ #!/usr/bin/env ruby
2
+
3
+ require "bundler/setup"
4
+ require "queight"
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
data/bin/setup ADDED
@@ -0,0 +1,7 @@
1
+ #!/bin/bash
2
+ set -euo pipefail
3
+ IFS=$'\n\t'
4
+
5
+ bundle install
6
+
7
+ # Do any other automated setup that you need to do here
@@ -0,0 +1,37 @@
1
+ version: '2'
2
+
3
+ volumes:
4
+ bundle18:
5
+ driver: local
6
+ bundle23:
7
+ driver: local
8
+
9
+ services:
10
+ rabbitmq:
11
+ image: rabbitmq:3.6
12
+ ports:
13
+ - 5672:5672
14
+ ruby18:
15
+ build:
16
+ context: .
17
+ dockerfile: Dockerfile.ruby18
18
+ links:
19
+ - rabbitmq
20
+ volumes:
21
+ - bundle18:/usr/local/bundle
22
+ - .:/srv/app
23
+ working_dir: /srv/app
24
+ environment:
25
+ - RABBITMQ_URL=amqp://guest:guest@rabbitmq?id=foo&size=10
26
+ command: bundle exec rake
27
+ ruby23:
28
+ image: ruby:2.3.1
29
+ links:
30
+ - rabbitmq
31
+ volumes:
32
+ - bundle23:/usr/local/bundle
33
+ - .:/srv/app
34
+ working_dir: /srv/app
35
+ environment:
36
+ - RABBITMQ_URL=amqp://guest:guest@rabbitmq?id=foo&size=10
37
+ command: bundle exec rake
data/lib/queight.rb ADDED
@@ -0,0 +1,37 @@
1
+ require "queight/version"
2
+ require "queight/client"
3
+ require "queight/connection_cache"
4
+ require "queight/exchange"
5
+ require "queight/queue"
6
+ require "queight/rabbitmq_config"
7
+ require "queight/metadata"
8
+
9
+ module Queight
10
+ GlobalConnectionCache = ConnectionCache.new
11
+
12
+ def self.queue(name, options = {})
13
+ Queue.new(name, options)
14
+ end
15
+
16
+ def self.default_exchange(message_options = {})
17
+ DefaultExchange.new(message_options)
18
+ end
19
+
20
+ def self.topic(name, message_options = {})
21
+ Exchange.new(:topic, name, message_options)
22
+ end
23
+
24
+ def self.direct(name, message_options = {})
25
+ Exchange.new(:direct, name, message_options)
26
+ end
27
+
28
+ def self.fanout(name, message_options = {})
29
+ Exchange.new(:fanout, name, message_options)
30
+ end
31
+
32
+ def self.current
33
+ options = RabbitMQConfig.configure_from!("RABBITMQ_URL").config
34
+ channel_pool = GlobalConnectionCache.call(options)
35
+ Client.new(channel_pool)
36
+ end
37
+ end
@@ -0,0 +1,13 @@
1
+ module Queight
2
+ class CancellableSubscriber
3
+ def initialize(channel, subscriber)
4
+ @channel = channel
5
+ @subscriber = subscriber
6
+ end
7
+
8
+ def cancel
9
+ @subscriber.cancel
10
+ @channel.close
11
+ end
12
+ end
13
+ end
@@ -0,0 +1,127 @@
1
+ require "bunny"
2
+ require "hot_tub"
3
+ require "queight/channel_wrapper"
4
+ require "monitor"
5
+
6
+ module Queight
7
+ class ChannelPool
8
+ DEFAULT_POOL_SIZE = 5
9
+
10
+ def initialize(options)
11
+ @options = options
12
+ @wrappers = []
13
+ @error_count = 0
14
+ @lock = Monitor.new
15
+ end
16
+
17
+ def with_channel
18
+ tracking_bunny_errors do
19
+ channel_pool.run { |channel| yield(channel) }
20
+ end
21
+ end
22
+
23
+ def with_transactional_channel
24
+ tracking_bunny_errors do
25
+ transactional_channel_pool.run { |channel| yield(channel) }
26
+ end
27
+ end
28
+
29
+ def with_subscribe_channel(prefetch)
30
+ tracking_bunny_errors do
31
+ channel = create_channel(prefetch)
32
+ yield(channel)
33
+ end
34
+ ensure
35
+ channel.close
36
+ end
37
+
38
+ def create_channel(prefetch = nil)
39
+ channel = conn.create_channel
40
+ channel.prefetch(prefetch) if prefetch
41
+
42
+ channel
43
+ end
44
+
45
+ def reset_cache!
46
+ @wrappers.each(&:reset_cache!)
47
+ end
48
+
49
+ private
50
+
51
+ def conn
52
+ @conn ||= Bunny.new(bunny_options).tap(&:start)
53
+ end
54
+
55
+ def transactional_channel_pool
56
+ @tx_channel_pool ||= new_pool("pool:tx_channels")
57
+ end
58
+
59
+ def channel_pool
60
+ @channel_pool ||= new_pool("pool:channels")
61
+ end
62
+
63
+ def build_wrapper
64
+ @wrappers << ChannelWrapper.new(conn.create_channel)
65
+ @wrappers.last
66
+ end
67
+
68
+ def bunny_options
69
+ @options.merge(
70
+ :properties => {
71
+ :information => @options.fetch(:id, "Queight (anonymous)"),
72
+ }
73
+ )
74
+ end
75
+
76
+ def new_pool(name)
77
+ HotTub::Pool.new(pool_options.merge(:name => name)) { build_wrapper }
78
+ end
79
+
80
+ def pool_options
81
+ {
82
+ :close => :close,
83
+ :size => pool_size,
84
+ :max_size => (pool_size * 3),
85
+ }
86
+ end
87
+
88
+ def pool_size
89
+ @options.fetch(:size, DEFAULT_POOL_SIZE)
90
+ end
91
+
92
+ def tracking_bunny_errors
93
+ val = yield
94
+
95
+ no_bunny_error
96
+
97
+ return val
98
+ rescue Bunny::Exception => e
99
+ bunny_error
100
+ raise e
101
+ end
102
+
103
+ MAXIMUM_BUNNY_ERRORS = 3
104
+
105
+ def bunny_error
106
+ @error_count += 1
107
+ synch { reconnect! if @error_count > MAXIMUM_BUNNY_ERRORS }
108
+ end
109
+
110
+ def no_bunny_error
111
+ @error_count = 0
112
+ end
113
+
114
+ def synch
115
+ @lock.synchronize { yield }
116
+ end
117
+
118
+ def reconnect!
119
+ channel_pool.drain!
120
+ transactional_channel_pool.drain!
121
+ @conn.close if @conn
122
+ @conn = nil
123
+ @wrappers = []
124
+ @error_count = 0
125
+ end
126
+ end
127
+ end
@@ -0,0 +1,17 @@
1
+ module Queight
2
+ # Adds memoization of exchanges etc.
3
+ class ChannelWrapper < SimpleDelegator
4
+ def initialize(channel)
5
+ super(channel)
6
+ reset_cache!
7
+ end
8
+
9
+ def reset_cache!
10
+ @exchange_cache = {}
11
+ end
12
+
13
+ def exchange(*args)
14
+ @exchange_cache[args] ||= super
15
+ end
16
+ end
17
+ end
@@ -0,0 +1,105 @@
1
+ require "queight/cancellable_subscriber"
2
+
3
+ module Queight
4
+ class Client
5
+ PublishFailure = Class.new(StandardError)
6
+
7
+ def initialize(channel_pool)
8
+ @channel_pool = channel_pool
9
+ end
10
+
11
+ def with_channel
12
+ @channel_pool.with_channel do |channel|
13
+ yield(channel)
14
+ end
15
+ end
16
+
17
+ def with_transactional_channel
18
+ @channel_pool.with_transactional_channel do |channel|
19
+ yield(channel)
20
+ end
21
+ end
22
+
23
+ def with_subscribe_channel(prefetch)
24
+ @channel_pool.with_subscribe_channel(prefetch) do |channel|
25
+ yield(channel)
26
+ end
27
+ end
28
+
29
+ def declare(queue)
30
+ with_channel do |channel|
31
+ queue.declare(channel)
32
+ end
33
+ end
34
+
35
+ def publish(exchange, message, routing_key)
36
+ with_transactional_channel do |channel|
37
+ channel.tx_select
38
+ exchange.publish(channel, message, routing_key)
39
+ raise PublishFailure unless channel.tx_commit
40
+ end
41
+ end
42
+
43
+ def publish_without_transaction(exchange, message, routing_key)
44
+ with_channel do |channel|
45
+ exchange.publish(channel, message, routing_key)
46
+ end
47
+ end
48
+ alias publish! publish_without_transaction
49
+
50
+ def publish_to_queue(message, queue, message_options = {})
51
+ declare(queue)
52
+ publish(Queight.default_exchange(message_options), message, queue.name)
53
+ end
54
+
55
+ def publish_to_queue_without_transaction(message, queue, options = {})
56
+ declare(queue)
57
+ publish_without_transaction(
58
+ Queight.default_exchange(options),
59
+ message,
60
+ queue.name
61
+ )
62
+ end
63
+ alias publish_to_queue! publish_to_queue_without_transaction
64
+
65
+ def subscribe(queue, prefetch = 1, &block)
66
+ with_subscribe_channel(prefetch) do |channel|
67
+ queue.subscribe(channel, &block)
68
+ end
69
+ end
70
+
71
+ def subscribe_non_blocking(queue, prefetch = 1, &block)
72
+ channel = @channel_pool.create_channel(prefetch)
73
+ channel.prefetch(prefetch)
74
+ consumer = queue.subscribe(channel, :block => false, &block)
75
+
76
+ CancellableSubscriber.new(channel, consumer)
77
+ end
78
+
79
+ def bind(exchange, queue)
80
+ with_channel do |channel|
81
+ exchange.bind(channel, queue)
82
+ end
83
+ end
84
+
85
+ def message_count(queue)
86
+ with_channel { |channel| queue.message_count(channel) }
87
+ end
88
+
89
+ def delete_queue(queue)
90
+ with_channel do |channel|
91
+ queue.delete(channel)
92
+ end
93
+ end
94
+
95
+ def purge(queue)
96
+ with_channel { |channel| queue.purge(channel) }
97
+ end
98
+
99
+ def delete_exchange(exchange)
100
+ with_channel do |channel|
101
+ exchange.delete(channel)
102
+ end
103
+ end
104
+ end
105
+ end
@@ -0,0 +1,17 @@
1
+ require "queight/channel_pool"
2
+
3
+ module Queight
4
+ class ConnectionCache
5
+ def initialize
6
+ @cache ||= {}
7
+ end
8
+
9
+ def reset_cache!
10
+ @cache.values.each(&:reset_cache!)
11
+ end
12
+
13
+ def call(options)
14
+ @cache[options] ||= ChannelPool.new(options)
15
+ end
16
+ end
17
+ end
@@ -0,0 +1,67 @@
1
+ module Queight
2
+ class Exchange
3
+ def initialize(type, name, message_options = {})
4
+ @type = type
5
+ @name = name
6
+ @message_options = {
7
+ :content_type => "application/json",
8
+ :persistent => true,
9
+ }.merge(message_options)
10
+ end
11
+
12
+ def publish(channel, message, routing_key)
13
+ exchange(channel).publish(message, message_options_for(routing_key))
14
+ end
15
+
16
+ def exchange(channel)
17
+ channel.exchange(@name, exchange_options)
18
+ end
19
+
20
+ def delete(channel)
21
+ channel.exchange(@name, exchange_options).delete
22
+ end
23
+
24
+ def bind(channel, queue)
25
+ if queue.routing_patterns.any?
26
+ queue.routing_patterns.each do |routing_pattern|
27
+ queue.queue(channel).bind(
28
+ exchange(channel),
29
+ :routing_key => routing_pattern
30
+ )
31
+ end
32
+ else
33
+ queue.queue(channel).bind(exchange(channel))
34
+ end
35
+ end
36
+
37
+ private
38
+
39
+ def exchange_options
40
+ {
41
+ :auto_delete => false,
42
+ :durable => true,
43
+ :type => @type,
44
+ }
45
+ end
46
+
47
+ def message_options_for(routing_key)
48
+ @message_options.merge(:routing_key => routing_key)
49
+ end
50
+ end
51
+
52
+ class DefaultExchange < Exchange
53
+ def initialize(message_options = {})
54
+ super(nil, nil, message_options)
55
+ end
56
+
57
+ def delete(_channel)
58
+ end
59
+
60
+ def bind(_channel, _queue)
61
+ end
62
+
63
+ def exchange(channel)
64
+ channel.default_exchange
65
+ end
66
+ end
67
+ end
@@ -0,0 +1,23 @@
1
+ module Queight
2
+ # Provides interface like AMQP::Header
3
+ class Metadata
4
+ def initialize(channel, delivery_info, properties)
5
+ @channel = channel
6
+ @delivery_info = delivery_info
7
+ @properties = properties
8
+ end
9
+
10
+ def ack
11
+ @channel.acknowledge(@delivery_info.delivery_tag)
12
+ end
13
+
14
+ def reject(options = {})
15
+ requeue = options.fetch(:requeue, false)
16
+ @channel.reject(@delivery_info.delivery_tag, requeue)
17
+ end
18
+
19
+ def redelivered?
20
+ @delivery_info.redelivered?
21
+ end
22
+ end
23
+ end
@@ -0,0 +1,55 @@
1
+ module Queight
2
+ class Queue
3
+ def initialize(name, options = {})
4
+ @name = name
5
+ @routing_patterns = Array(options.delete(:routing))
6
+ @queue_options = options
7
+ end
8
+
9
+ attr_reader :routing_patterns, :name
10
+
11
+ def declare(channel)
12
+ queue(channel)
13
+ end
14
+
15
+ def subscribe(channel, options = {})
16
+ queue = queue(channel)
17
+ queue.subscribe(subscribe_options(options)) do |*args|
18
+ yield(channel, *args)
19
+ end
20
+ end
21
+
22
+ def delete(channel)
23
+ channel.queue(@name).delete
24
+ end
25
+
26
+ def queue(channel)
27
+ channel.queue(@name, queue_options)
28
+ end
29
+
30
+ def message_count(channel)
31
+ queue(channel).message_count
32
+ end
33
+
34
+ def purge(channel)
35
+ queue(channel).purge
36
+ end
37
+
38
+ private
39
+
40
+ def subscribe_options(options)
41
+ {
42
+ :block => true,
43
+ :manual_ack => true,
44
+ }.merge(options)
45
+ end
46
+
47
+ def queue_options
48
+ {
49
+ :auto_delete => false,
50
+ :durable => true,
51
+ :exclusive => false,
52
+ }.merge(@queue_options)
53
+ end
54
+ end
55
+ end
@@ -0,0 +1,22 @@
1
+ require "uri_config/config"
2
+ require "uri"
3
+
4
+ module Queight
5
+ class RabbitMQConfig < URIConfig::Config
6
+ map :user, :from => :username
7
+
8
+ def size
9
+ query["size"].map(&:to_i).last
10
+ end
11
+
12
+ def vhost
13
+ return "/" if path.empty?
14
+
15
+ URI.decode path[1..-1]
16
+ end
17
+
18
+ parameter :id
19
+
20
+ config :user, :password, :port, :host, :vhost, :size, :id
21
+ end
22
+ end
@@ -0,0 +1,3 @@
1
+ module Queight
2
+ VERSION = "0.12.0"
3
+ end
data/queight.gemspec ADDED
@@ -0,0 +1,36 @@
1
+ # coding: utf-8
2
+ lib = File.expand_path("../lib", __FILE__)
3
+ $LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
4
+ require "queight/version"
5
+
6
+ Gem::Specification.new do |spec|
7
+ spec.name = "queight"
8
+ spec.version = Queight::VERSION
9
+ spec.authors = ["Jonathon M. Abbott"]
10
+ spec.email = ["jma@dandaraga.net"]
11
+
12
+ spec.summary = "a lightweight wrapper around bunny"
13
+ spec.description = spec.summary
14
+ spec.homepage = "http://github.com/JonathonMA/queight"
15
+ spec.license = "MIT"
16
+
17
+ spec.files = `git ls-files -z`.split("\x0").reject { |f| f.match(%r{^(test|spec|features)/}) }
18
+ spec.bindir = "exe"
19
+ spec.executables = spec.files.grep(%r{^exe/}) { |f| File.basename(f) }
20
+ spec.require_paths = ["lib"]
21
+
22
+ spec.add_development_dependency "bundler", "~> 1.10"
23
+ spec.add_development_dependency "dotenv", "2.1.1"
24
+ spec.add_development_dependency "json", "< 2" if RUBY_VERSION < "1.9"
25
+ spec.add_development_dependency "rake", "~> 10.0"
26
+ spec.add_development_dependency "rspec"
27
+ spec.add_development_dependency "rubocop", "~> 0.42.0" if RUBY_VERSION >= "1.9"
28
+
29
+ if RUBY_VERSION < "2.0"
30
+ spec.add_dependency "bunny", "~> 1.7"
31
+ else
32
+ spec.add_dependency "bunny"
33
+ end
34
+ spec.add_dependency "hot_tub"
35
+ spec.add_dependency "uri_config", "~> 0.0.11"
36
+ end
metadata ADDED
@@ -0,0 +1,183 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: queight
3
+ version: !ruby/object:Gem::Version
4
+ version: 0.12.0
5
+ platform: ruby
6
+ authors:
7
+ - Jonathon M. Abbott
8
+ autorequire:
9
+ bindir: exe
10
+ cert_chain: []
11
+ date: 2017-03-07 00:00:00.000000000 Z
12
+ dependencies:
13
+ - !ruby/object:Gem::Dependency
14
+ name: bundler
15
+ requirement: !ruby/object:Gem::Requirement
16
+ requirements:
17
+ - - "~>"
18
+ - !ruby/object:Gem::Version
19
+ version: '1.10'
20
+ type: :development
21
+ prerelease: false
22
+ version_requirements: !ruby/object:Gem::Requirement
23
+ requirements:
24
+ - - "~>"
25
+ - !ruby/object:Gem::Version
26
+ version: '1.10'
27
+ - !ruby/object:Gem::Dependency
28
+ name: dotenv
29
+ requirement: !ruby/object:Gem::Requirement
30
+ requirements:
31
+ - - '='
32
+ - !ruby/object:Gem::Version
33
+ version: 2.1.1
34
+ type: :development
35
+ prerelease: false
36
+ version_requirements: !ruby/object:Gem::Requirement
37
+ requirements:
38
+ - - '='
39
+ - !ruby/object:Gem::Version
40
+ version: 2.1.1
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.0'
48
+ type: :development
49
+ prerelease: false
50
+ version_requirements: !ruby/object:Gem::Requirement
51
+ requirements:
52
+ - - "~>"
53
+ - !ruby/object:Gem::Version
54
+ version: '10.0'
55
+ - !ruby/object:Gem::Dependency
56
+ name: rspec
57
+ requirement: !ruby/object:Gem::Requirement
58
+ requirements:
59
+ - - ">="
60
+ - !ruby/object:Gem::Version
61
+ version: '0'
62
+ type: :development
63
+ prerelease: false
64
+ version_requirements: !ruby/object:Gem::Requirement
65
+ requirements:
66
+ - - ">="
67
+ - !ruby/object:Gem::Version
68
+ version: '0'
69
+ - !ruby/object:Gem::Dependency
70
+ name: rubocop
71
+ requirement: !ruby/object:Gem::Requirement
72
+ requirements:
73
+ - - "~>"
74
+ - !ruby/object:Gem::Version
75
+ version: 0.42.0
76
+ type: :development
77
+ prerelease: false
78
+ version_requirements: !ruby/object:Gem::Requirement
79
+ requirements:
80
+ - - "~>"
81
+ - !ruby/object:Gem::Version
82
+ version: 0.42.0
83
+ - !ruby/object:Gem::Dependency
84
+ name: bunny
85
+ requirement: !ruby/object:Gem::Requirement
86
+ requirements:
87
+ - - ">="
88
+ - !ruby/object:Gem::Version
89
+ version: '0'
90
+ type: :runtime
91
+ prerelease: false
92
+ version_requirements: !ruby/object:Gem::Requirement
93
+ requirements:
94
+ - - ">="
95
+ - !ruby/object:Gem::Version
96
+ version: '0'
97
+ - !ruby/object:Gem::Dependency
98
+ name: hot_tub
99
+ requirement: !ruby/object:Gem::Requirement
100
+ requirements:
101
+ - - ">="
102
+ - !ruby/object:Gem::Version
103
+ version: '0'
104
+ type: :runtime
105
+ prerelease: false
106
+ version_requirements: !ruby/object:Gem::Requirement
107
+ requirements:
108
+ - - ">="
109
+ - !ruby/object:Gem::Version
110
+ version: '0'
111
+ - !ruby/object:Gem::Dependency
112
+ name: uri_config
113
+ requirement: !ruby/object:Gem::Requirement
114
+ requirements:
115
+ - - "~>"
116
+ - !ruby/object:Gem::Version
117
+ version: 0.0.11
118
+ type: :runtime
119
+ prerelease: false
120
+ version_requirements: !ruby/object:Gem::Requirement
121
+ requirements:
122
+ - - "~>"
123
+ - !ruby/object:Gem::Version
124
+ version: 0.0.11
125
+ description: a lightweight wrapper around bunny
126
+ email:
127
+ - jma@dandaraga.net
128
+ executables: []
129
+ extensions: []
130
+ extra_rdoc_files: []
131
+ files:
132
+ - ".env"
133
+ - ".gitignore"
134
+ - ".rspec"
135
+ - ".rubocop.yml"
136
+ - ".ruby-version"
137
+ - ".travis.yml"
138
+ - CODE_OF_CONDUCT.md
139
+ - Dockerfile.ruby18
140
+ - Gemfile
141
+ - LICENSE.txt
142
+ - README.md
143
+ - Rakefile
144
+ - bin/console
145
+ - bin/setup
146
+ - docker-compose.yml
147
+ - lib/queight.rb
148
+ - lib/queight/cancellable_subscriber.rb
149
+ - lib/queight/channel_pool.rb
150
+ - lib/queight/channel_wrapper.rb
151
+ - lib/queight/client.rb
152
+ - lib/queight/connection_cache.rb
153
+ - lib/queight/exchange.rb
154
+ - lib/queight/metadata.rb
155
+ - lib/queight/queue.rb
156
+ - lib/queight/rabbitmq_config.rb
157
+ - lib/queight/version.rb
158
+ - queight.gemspec
159
+ homepage: http://github.com/JonathonMA/queight
160
+ licenses:
161
+ - MIT
162
+ metadata: {}
163
+ post_install_message:
164
+ rdoc_options: []
165
+ require_paths:
166
+ - lib
167
+ required_ruby_version: !ruby/object:Gem::Requirement
168
+ requirements:
169
+ - - ">="
170
+ - !ruby/object:Gem::Version
171
+ version: '0'
172
+ required_rubygems_version: !ruby/object:Gem::Requirement
173
+ requirements:
174
+ - - ">="
175
+ - !ruby/object:Gem::Version
176
+ version: '0'
177
+ requirements: []
178
+ rubyforge_project:
179
+ rubygems_version: 2.5.2
180
+ signing_key:
181
+ specification_version: 4
182
+ summary: a lightweight wrapper around bunny
183
+ test_files: []