rabbit_messaging 0.6.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 +7 -0
- data/.gitignore +11 -0
- data/.rspec +3 -0
- data/.rubocop.yml +17 -0
- data/.travis.yml +19 -0
- data/Gemfile +4 -0
- data/LICENSE.md +21 -0
- data/README.md +148 -0
- data/Rakefile +22 -0
- data/bin/console +7 -0
- data/bin/setup +8 -0
- data/environments/development.rb +17 -0
- data/lib/rabbit.rb +77 -0
- data/lib/rabbit/daemon.rb +48 -0
- data/lib/rabbit/event_handler.rb +27 -0
- data/lib/rabbit/extensions/bunny/channel.rb +14 -0
- data/lib/rabbit/publishing.rb +79 -0
- data/lib/rabbit/publishing/job.rb +11 -0
- data/lib/rabbit/publishing/message.rb +63 -0
- data/lib/rabbit/receiving.rb +6 -0
- data/lib/rabbit/receiving/handler_resolver.rb +35 -0
- data/lib/rabbit/receiving/job.rb +24 -0
- data/lib/rabbit/receiving/malformed_message.rb +30 -0
- data/lib/rabbit/receiving/message.rb +36 -0
- data/lib/rabbit/receiving/worker.rb +54 -0
- data/lib/rabbit/test_helpers.rb +20 -0
- data/lib/rabbit/version.rb +5 -0
- data/lib/rabbit_messaging.rb +3 -0
- data/rabbit_messaging.gemspec +38 -0
- metadata +280 -0
checksums.yaml
ADDED
@@ -0,0 +1,7 @@
|
|
1
|
+
---
|
2
|
+
SHA256:
|
3
|
+
metadata.gz: '081fdf833501fd681239cacf04348b5736d2f445f8b4f995c9cb20f5a4decf2d'
|
4
|
+
data.tar.gz: 566727c03028779e6334f4c89fc2cb2a569dfc7c8dfa92f3399841b610b23f6a
|
5
|
+
SHA512:
|
6
|
+
metadata.gz: 118a2d651ce38c6cb60b76464ff1db259865374b0ab8454d9208a7811ee55790796bb8be3cdad0cfbec92750e3a0a97ba36491c9b0e9e697faddbbc3cb7d53aa
|
7
|
+
data.tar.gz: 5e56e561d5077c826d8b1ed5a13dcdf640f14093d5b05fe689fa4d55adc3d9830379e3cafcf289097a56ca78494b4cb33a63ad966456bd8730be1d749007f7dd
|
data/.gitignore
ADDED
data/.rspec
ADDED
data/.rubocop.yml
ADDED
@@ -0,0 +1,17 @@
|
|
1
|
+
inherit_gem:
|
2
|
+
rubocop-config-umbrellio: lib/rubocop.yml
|
3
|
+
|
4
|
+
AllCops:
|
5
|
+
DisplayCopNames: true
|
6
|
+
TargetRubyVersion: 2.3
|
7
|
+
Include:
|
8
|
+
- lib/**/*.rb
|
9
|
+
- spec/**/*.rb
|
10
|
+
- Gemfile
|
11
|
+
- Rakefile
|
12
|
+
- rabbit_messaging.gemspec
|
13
|
+
- bin/console
|
14
|
+
- environments/*.rb
|
15
|
+
|
16
|
+
Style/Alias:
|
17
|
+
EnforcedStyle: prefer_alias_method
|
data/.travis.yml
ADDED
@@ -0,0 +1,19 @@
|
|
1
|
+
language: ruby
|
2
|
+
matrix:
|
3
|
+
fast_finish: true
|
4
|
+
include:
|
5
|
+
- rvm: 2.3
|
6
|
+
- rvm: 2.4
|
7
|
+
- rvm: 2.5
|
8
|
+
- rvm: 2.6
|
9
|
+
- rvm: ruby-head
|
10
|
+
allow_failures:
|
11
|
+
- rvm: ruby-head
|
12
|
+
sudo: false
|
13
|
+
cache: bundler
|
14
|
+
before_install: gem install bundler
|
15
|
+
script:
|
16
|
+
- mkdir log
|
17
|
+
- bundle exec rake bundle:audit
|
18
|
+
- bundle exec rubocop
|
19
|
+
- bundle exec rspec
|
data/Gemfile
ADDED
data/LICENSE.md
ADDED
@@ -0,0 +1,21 @@
|
|
1
|
+
The MIT License (MIT)
|
2
|
+
|
3
|
+
Copyright (c) 2019 Umbrellio
|
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,148 @@
|
|
1
|
+
# Rabbit (Rabbit Messaging) · [](https://badge.fury.io/rb/rabbit_messaging) [](https://travis-ci.org/umbrellio/rabbit_messaging) [](https://coveralls.io/github/umbrellio/rabbit_messaging?branch=master)
|
2
|
+
|
3
|
+
Provides client and server support for RabbitMQ
|
4
|
+
|
5
|
+
## Installation
|
6
|
+
|
7
|
+
```ruby
|
8
|
+
gem "rabbit_messaging"
|
9
|
+
```
|
10
|
+
|
11
|
+
```shell
|
12
|
+
$ bundle install
|
13
|
+
# --- or ---
|
14
|
+
$ gem install "rabbit_messaging"
|
15
|
+
```
|
16
|
+
|
17
|
+
```ruby
|
18
|
+
require "rabbit_messaging"
|
19
|
+
```
|
20
|
+
|
21
|
+
## Usage
|
22
|
+
|
23
|
+
- [Configuration](#configuration)
|
24
|
+
- [Client](#client)
|
25
|
+
- [Server](#server)
|
26
|
+
|
27
|
+
---
|
28
|
+
|
29
|
+
### Configuration
|
30
|
+
|
31
|
+
- RabbitMQ connection configuration fetched from the `bunny_options` section
|
32
|
+
of `/config/sneakers.yml`
|
33
|
+
|
34
|
+
- `Rabbit.config` provides setters for following options:
|
35
|
+
|
36
|
+
* `group_id` (`Symbol`), *required*
|
37
|
+
|
38
|
+
Shared identifier which used to select api. As usual, it should be same as default project_id
|
39
|
+
(I.e. we have project 'support', which runs only one application in production.
|
40
|
+
So on, it's group_id should be :support)
|
41
|
+
|
42
|
+
* `project_id` (`Symbol`), *required*
|
43
|
+
|
44
|
+
Personal identifier which used to select exact service.
|
45
|
+
As usual, it should be same as default project_id with optional stage_id.
|
46
|
+
(I.e. we have project 'support', in production it's project_id is :support,
|
47
|
+
but in staging it uses :support1 and :support2 ids for corresponding stages)
|
48
|
+
|
49
|
+
* `hooks` (`Hash`)
|
50
|
+
|
51
|
+
:before_fork and :after_fork hooks, used same way as in unicorn / puma / que / etc
|
52
|
+
|
53
|
+
* `environment` (one of `:test`, `:development`, `:production`), *default:* `:production`
|
54
|
+
|
55
|
+
Internal environment of gem.
|
56
|
+
|
57
|
+
* `:test` environment stubs publishing and does not suppress errors
|
58
|
+
* `:development` environment auto-creates queues and uses default exchange
|
59
|
+
* `:production` environment enables handlers caching and gets maximum strictness
|
60
|
+
|
61
|
+
* `receiving_job_class_callable` (`Proc`)
|
62
|
+
|
63
|
+
Custom ActiveJob subclass to work with received messages.
|
64
|
+
|
65
|
+
* `exception_notifier` (`Proc`)
|
66
|
+
|
67
|
+
By default, exceptions are reported using `ExceptionNotifier` (see exception_notification gem).
|
68
|
+
You can provide your own notifier like this:
|
69
|
+
|
70
|
+
```ruby
|
71
|
+
config.exception_notifier = proc { |e| MyCoolNotifier.notify!(e) }
|
72
|
+
```
|
73
|
+
|
74
|
+
---
|
75
|
+
|
76
|
+
### Client
|
77
|
+
|
78
|
+
```ruby
|
79
|
+
Rabbit.publish(
|
80
|
+
routing_key: :support,
|
81
|
+
event: :ping,
|
82
|
+
data: { foo: :bar }, # default is {}
|
83
|
+
exchange_name: 'fanout', # default is fine too
|
84
|
+
confirm_select: true, # setting this to false grants you great speed up and absolutelly no guarantees
|
85
|
+
headers: { "foo" => "bar" }, # custom arguments for routing, default is {}
|
86
|
+
)
|
87
|
+
```
|
88
|
+
|
89
|
+
- This code sends messages via basic_publish with following parameters:
|
90
|
+
|
91
|
+
* `routing_key`: `"support"`
|
92
|
+
* `exchange`: `"group_id.project_id.fanout"` (default is `"group_id.poject_id"`)
|
93
|
+
* `mandatory`: `true` (same as confirm_select)
|
94
|
+
|
95
|
+
It is set to raise error if routing failed
|
96
|
+
|
97
|
+
* `persistent`: `true`
|
98
|
+
* `type`: `"ping"`
|
99
|
+
* `content_type`: `"application/json"` (always)
|
100
|
+
* `app_id`: `"group_id.project_id"`
|
101
|
+
|
102
|
+
- Messages are logged to `/log/rabbit.log`
|
103
|
+
|
104
|
+
---
|
105
|
+
|
106
|
+
### Server
|
107
|
+
|
108
|
+
- Server is supposed to run inside a daemon via the `daemons-rails` gem. Server is run with
|
109
|
+
`Rabbit::Daemon.run`. `before_fork` and `after_fork` procs in `Rabbit.config` are used
|
110
|
+
to teardown and setup external connections between daemon restarts, for example ORM connections
|
111
|
+
|
112
|
+
- After the server runs, received messages are handled by `Rabbit::EventHandler` subclasses.
|
113
|
+
Subclasses are selected by following code:
|
114
|
+
```ruby
|
115
|
+
"rabbit/handler/#{group_id}/#{event}".camelize.constantize
|
116
|
+
```
|
117
|
+
|
118
|
+
They use powerful `Tainbox` api to handle message data. Project_id also passed to them.
|
119
|
+
|
120
|
+
If you wish so, you can override `initialize(message)`, where message is an object
|
121
|
+
with simple api (@see lib/rabbit/receiving/message.rb)
|
122
|
+
|
123
|
+
Handlers can specify a queue their messages will be put in via a `queue_as` class macro (accepts
|
124
|
+
a string / symbol / block with `|message, arguments|` params)
|
125
|
+
|
126
|
+
- Received messages are logged to `/log/sneakers.log`, malformed messages are logged to
|
127
|
+
`/log/malformed_messages.log` and deleted from queue
|
128
|
+
|
129
|
+
---
|
130
|
+
|
131
|
+
## Contributing
|
132
|
+
|
133
|
+
Bug reports and pull requests are welcome on GitHub at https://github.com/umbrellio/rabbit_messaging.
|
134
|
+
|
135
|
+
## License
|
136
|
+
|
137
|
+
Released under MIT License
|
138
|
+
|
139
|
+
## Authors
|
140
|
+
|
141
|
+
Team Umbrellio
|
142
|
+
|
143
|
+
---
|
144
|
+
|
145
|
+
<a href="https://github.com/umbrellio/">
|
146
|
+
<img style="float: left;" src="https://umbrellio.github.io/Umbrellio/supported_by_umbrellio.svg"
|
147
|
+
alt="Supported by Umbrellio" width="439" height="72">
|
148
|
+
</a>
|
data/Rakefile
ADDED
@@ -0,0 +1,22 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require "bundler/gem_tasks"
|
4
|
+
require "bundler/audit/task"
|
5
|
+
require "rspec/core/rake_task"
|
6
|
+
require "rubocop"
|
7
|
+
require "rubocop-rspec"
|
8
|
+
require "rubocop-performance"
|
9
|
+
require "rubocop/rake_task"
|
10
|
+
|
11
|
+
RuboCop::RakeTask.new(:rubocop) do |t|
|
12
|
+
config_path = File.expand_path(File.join(".rubocop.yml"), __dir__)
|
13
|
+
|
14
|
+
t.options = ["--config", config_path]
|
15
|
+
t.requires << "rubocop-rspec"
|
16
|
+
t.requires << "rubocop-performance"
|
17
|
+
end
|
18
|
+
|
19
|
+
RSpec::Core::RakeTask.new(:rspec)
|
20
|
+
Bundler::Audit::Task.new
|
21
|
+
|
22
|
+
task default: :rspec
|
data/bin/console
ADDED
data/bin/setup
ADDED
@@ -0,0 +1,17 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require "bundler/setup"
|
4
|
+
|
5
|
+
Bundler.require(:default, :development)
|
6
|
+
require "active_job"
|
7
|
+
require "active_record"
|
8
|
+
|
9
|
+
def Rails.root
|
10
|
+
Pathname.new(__dir__).join("..")
|
11
|
+
end
|
12
|
+
|
13
|
+
ActiveJob::Base.queue_adapter = :inline
|
14
|
+
ActiveJob::Base.logger = Logger.new("/dev/null")
|
15
|
+
|
16
|
+
Rabbit.config.project_id = "test_project_id"
|
17
|
+
Rabbit.config.group_id = "test_group_id"
|
data/lib/rabbit.rb
ADDED
@@ -0,0 +1,77 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require "tainbox"
|
4
|
+
|
5
|
+
require "rabbit/version"
|
6
|
+
require "rabbit/daemon"
|
7
|
+
require "rabbit/publishing"
|
8
|
+
require "rabbit/event_handler"
|
9
|
+
|
10
|
+
require "rabbit/extensions/bunny/channel"
|
11
|
+
|
12
|
+
module Rabbit
|
13
|
+
InvalidConfig = Class.new(StandardError)
|
14
|
+
MessageNotDelivered = Class.new(StandardError)
|
15
|
+
|
16
|
+
class Config
|
17
|
+
include Tainbox
|
18
|
+
|
19
|
+
attribute :group_id, Symbol
|
20
|
+
attribute :project_id, Symbol
|
21
|
+
attribute :hooks, default: {}
|
22
|
+
attribute :environment, Symbol, default: :production
|
23
|
+
attribute :queue_name_conversion
|
24
|
+
attribute :receiving_job_class_callable
|
25
|
+
attribute :exception_notifier, default: -> { default_exception_notifier }
|
26
|
+
|
27
|
+
def validate!
|
28
|
+
raise InvalidConfig, "mising project_id" unless project_id
|
29
|
+
raise InvalidConfig, "mising group_id" unless group_id
|
30
|
+
|
31
|
+
unless environment.in? %i[test development production]
|
32
|
+
raise "environment should be one of (test, development, production)"
|
33
|
+
end
|
34
|
+
end
|
35
|
+
|
36
|
+
def app_name
|
37
|
+
[group_id, project_id].join(".")
|
38
|
+
end
|
39
|
+
|
40
|
+
alias_method :read_queue, :app_name
|
41
|
+
|
42
|
+
private
|
43
|
+
|
44
|
+
def default_exception_notifier
|
45
|
+
-> (e) { ExceptionNotifier.notify_exception(e) }
|
46
|
+
end
|
47
|
+
end
|
48
|
+
|
49
|
+
extend self
|
50
|
+
|
51
|
+
def config
|
52
|
+
@config ||= Config.new
|
53
|
+
yield(@config) if block_given?
|
54
|
+
@config
|
55
|
+
end
|
56
|
+
|
57
|
+
alias_method :configure, :config
|
58
|
+
|
59
|
+
def publish(message_options)
|
60
|
+
message = Publishing::Message.new(message_options)
|
61
|
+
|
62
|
+
if message.realtime?
|
63
|
+
Publishing.publish(message)
|
64
|
+
else
|
65
|
+
Publishing::Job.set(queue: default_queue_name).perform_later(message.to_hash)
|
66
|
+
end
|
67
|
+
end
|
68
|
+
|
69
|
+
def queue_name(queue, ignore_conversion: false)
|
70
|
+
return queue if ignore_conversion
|
71
|
+
config.queue_name_conversion ? config.queue_name_conversion.call(queue) : queue
|
72
|
+
end
|
73
|
+
|
74
|
+
def default_queue_name(ignore_conversion: false)
|
75
|
+
queue_name(:default, ignore_conversion: ignore_conversion)
|
76
|
+
end
|
77
|
+
end
|
@@ -0,0 +1,48 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require "sneakers"
|
4
|
+
require "lamian"
|
5
|
+
require "sneakers/runner"
|
6
|
+
|
7
|
+
require "rabbit/extensions/bunny/channel"
|
8
|
+
require "rabbit/receiving/worker"
|
9
|
+
|
10
|
+
module Rabbit
|
11
|
+
module Daemon
|
12
|
+
extend self
|
13
|
+
|
14
|
+
def run
|
15
|
+
Sneakers.configure(
|
16
|
+
connection: connection,
|
17
|
+
env: Rails.env,
|
18
|
+
exchange_type: :direct,
|
19
|
+
exchange: Rabbit.config.app_name,
|
20
|
+
hooks: Rabbit.config.hooks,
|
21
|
+
supervisor: true,
|
22
|
+
daemonize: false,
|
23
|
+
exit_on_detach: true,
|
24
|
+
**config,
|
25
|
+
)
|
26
|
+
|
27
|
+
Sneakers.logger = Logger.new(Rails.root.join("log", "sneakers.log"))
|
28
|
+
Sneakers.logger.level = Logger::DEBUG
|
29
|
+
Lamian.extend_logger(Sneakers.logger)
|
30
|
+
|
31
|
+
Sneakers.server = true
|
32
|
+
|
33
|
+
Rabbit.config.validate!
|
34
|
+
Receiving::Worker.from_queue(Rabbit.config.read_queue)
|
35
|
+
|
36
|
+
Sneakers::Runner.new([Receiving::Worker]).run
|
37
|
+
end
|
38
|
+
|
39
|
+
def config
|
40
|
+
Rails.application.config_for("sneakers").symbolize_keys
|
41
|
+
end
|
42
|
+
|
43
|
+
def connection
|
44
|
+
bunny_config = config.delete(:bunny_options).to_h.symbolize_keys
|
45
|
+
Bunny.new(bunny_config)
|
46
|
+
end
|
47
|
+
end
|
48
|
+
end
|
@@ -0,0 +1,27 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require "tainbox"
|
4
|
+
require "active_support/core_ext/class/attribute"
|
5
|
+
|
6
|
+
class Rabbit::EventHandler
|
7
|
+
include Tainbox
|
8
|
+
|
9
|
+
attribute :project_id
|
10
|
+
attr_accessor :data
|
11
|
+
class_attribute :queue
|
12
|
+
class_attribute :ignore_queue_conversion, default: false
|
13
|
+
|
14
|
+
class << self
|
15
|
+
private
|
16
|
+
|
17
|
+
def queue_as(queue = nil, &block)
|
18
|
+
self.queue = queue || block
|
19
|
+
end
|
20
|
+
end
|
21
|
+
|
22
|
+
def initialize(message)
|
23
|
+
self.attributes = message.data
|
24
|
+
self.data = message.data
|
25
|
+
self.project_id = message.project_id
|
26
|
+
end
|
27
|
+
end
|
@@ -0,0 +1,14 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require "bunny/channel"
|
4
|
+
|
5
|
+
class Bunny::Channel
|
6
|
+
module RabbitExtensions
|
7
|
+
def handle_basic_return(*)
|
8
|
+
@unconfirmed_set_mutex.synchronize { @only_acks_received = false } # fails confirm_select
|
9
|
+
super
|
10
|
+
end
|
11
|
+
end
|
12
|
+
|
13
|
+
prepend(RabbitExtensions)
|
14
|
+
end
|
@@ -0,0 +1,79 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require "rabbit/publishing/message"
|
4
|
+
|
5
|
+
module Rabbit
|
6
|
+
module Publishing
|
7
|
+
autoload :Job, "rabbit/publishing/job"
|
8
|
+
|
9
|
+
MUTEX = Mutex.new
|
10
|
+
|
11
|
+
extend self
|
12
|
+
|
13
|
+
def publish(message)
|
14
|
+
return unless client
|
15
|
+
|
16
|
+
channel = channel(message.confirm_select?)
|
17
|
+
channel.basic_publish(*message.basic_publish_args)
|
18
|
+
|
19
|
+
if message.confirm_select? && !channel.wait_for_confirms
|
20
|
+
raise MessageNotDelivered, "RabbitMQ message not delivered: #{message}"
|
21
|
+
else
|
22
|
+
log(message)
|
23
|
+
end
|
24
|
+
rescue Timeout::Error
|
25
|
+
raise MessageNotDelivered, <<~MESSAGE
|
26
|
+
Timeout while sending message #{message}. Possible reasons:
|
27
|
+
- #{message.real_exchange_name} exchange is not found
|
28
|
+
- RabbitMQ is extremely high loaded
|
29
|
+
MESSAGE
|
30
|
+
end
|
31
|
+
|
32
|
+
def client
|
33
|
+
MUTEX.synchronize { @client ||= create_client }
|
34
|
+
end
|
35
|
+
|
36
|
+
def channel(confirm)
|
37
|
+
Thread.current[:bunny_channels] ||= {}
|
38
|
+
channel = Thread.current[:bunny_channels][confirm]
|
39
|
+
Thread.current[:bunny_channels][confirm] = create_channel(confirm) unless channel&.open?
|
40
|
+
Thread.current[:bunny_channels][confirm]
|
41
|
+
end
|
42
|
+
|
43
|
+
private
|
44
|
+
|
45
|
+
def create_queue_if_not_exists(channel, message)
|
46
|
+
channel.queue(message.routing_key, durable: true)
|
47
|
+
end
|
48
|
+
|
49
|
+
def create_client
|
50
|
+
return if Rabbit.config.environment == :test
|
51
|
+
|
52
|
+
config = Rails.application.config_for("sneakers") rescue {}
|
53
|
+
config = config["bunny_options"].to_h.symbolize_keys
|
54
|
+
|
55
|
+
begin
|
56
|
+
Bunny.new(config).start
|
57
|
+
rescue
|
58
|
+
raise unless Rabbit.config.environment == :development
|
59
|
+
end
|
60
|
+
end
|
61
|
+
|
62
|
+
def create_channel(confirm)
|
63
|
+
channel = client.create_channel
|
64
|
+
channel.confirm_select if confirm
|
65
|
+
channel
|
66
|
+
end
|
67
|
+
|
68
|
+
def log(message)
|
69
|
+
@logger ||= Logger.new(Rails.root.join("log", "rabbit.log"))
|
70
|
+
|
71
|
+
headers = [
|
72
|
+
message.real_exchange_name, message.routing_key, message.event,
|
73
|
+
message.confirm_select? ? "confirm" : "no-confirm"
|
74
|
+
]
|
75
|
+
|
76
|
+
@logger.debug "#{headers.join ' / '}: #{message.data}"
|
77
|
+
end
|
78
|
+
end
|
79
|
+
end
|
@@ -0,0 +1,63 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require "tainbox"
|
4
|
+
|
5
|
+
module Rabbit::Publishing
|
6
|
+
class Message
|
7
|
+
include Tainbox
|
8
|
+
|
9
|
+
attribute :routing_key, String
|
10
|
+
attribute :event, String
|
11
|
+
attribute :data, default: {}
|
12
|
+
attribute :exchange_name, default: []
|
13
|
+
attribute :confirm_select, default: true
|
14
|
+
attribute :realtime, default: false
|
15
|
+
attribute :headers
|
16
|
+
|
17
|
+
alias_method :confirm_select?, :confirm_select
|
18
|
+
alias_method :realtime?, :realtime
|
19
|
+
|
20
|
+
def to_hash
|
21
|
+
{
|
22
|
+
**attributes,
|
23
|
+
data: JSON.parse(data.to_json),
|
24
|
+
}
|
25
|
+
end
|
26
|
+
|
27
|
+
def to_s
|
28
|
+
"#{real_exchange_name} -> #{routing_key} -> #{event}"
|
29
|
+
end
|
30
|
+
|
31
|
+
def basic_publish_args
|
32
|
+
Rabbit.config.validate!
|
33
|
+
|
34
|
+
raise "Routing key not specified" unless routing_key
|
35
|
+
raise "Event name not specified" unless event
|
36
|
+
|
37
|
+
options = {
|
38
|
+
mandatory: confirm_select?,
|
39
|
+
persistent: true,
|
40
|
+
type: event,
|
41
|
+
content_type: "application/json",
|
42
|
+
app_id: Rabbit.config.app_name,
|
43
|
+
headers: headers,
|
44
|
+
}
|
45
|
+
|
46
|
+
[JSON.dump(data), real_exchange_name, routing_key.to_s, options]
|
47
|
+
end
|
48
|
+
|
49
|
+
def exchange_name=(names)
|
50
|
+
super(Array(names).map(&:to_s))
|
51
|
+
end
|
52
|
+
|
53
|
+
def real_exchange_name
|
54
|
+
[Rabbit.config.group_id, Rabbit.config.project_id, *exchange_name].join(".")
|
55
|
+
end
|
56
|
+
|
57
|
+
private
|
58
|
+
|
59
|
+
def headers
|
60
|
+
super || {}
|
61
|
+
end
|
62
|
+
end
|
63
|
+
end
|
@@ -0,0 +1,35 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require "rabbit"
|
4
|
+
require "rabbit/receiving"
|
5
|
+
require "rabbit/event_handler"
|
6
|
+
|
7
|
+
module Rabbit::Receiving::HandlerResolver
|
8
|
+
UnsupportedEvent = Class.new(StandardError)
|
9
|
+
|
10
|
+
class << self
|
11
|
+
def handler_for(message)
|
12
|
+
@handler_cache ||= Hash.new do |cache, (group_id, event)|
|
13
|
+
handler = unmemoized_handler_for(group_id, event)
|
14
|
+
cache[[group_id, event]] = handler if Rabbit.config.environment == :production
|
15
|
+
handler
|
16
|
+
end
|
17
|
+
|
18
|
+
@handler_cache[[message.group_id, message.event]]
|
19
|
+
end
|
20
|
+
|
21
|
+
private
|
22
|
+
|
23
|
+
def unmemoized_handler_for(group_id, event)
|
24
|
+
name = "rabbit/handler/#{group_id}/#{event}".camelize
|
25
|
+
handler = name.safe_constantize
|
26
|
+
if handler && handler < Rabbit::EventHandler
|
27
|
+
handler
|
28
|
+
else
|
29
|
+
raise UnsupportedEvent, "#{event.inspect} event from #{group_id.inspect} group is not " \
|
30
|
+
"supported, it requires a #{name.inspect} class inheriting from " \
|
31
|
+
"\"Rabbit::EventHandler\" to be defined"
|
32
|
+
end
|
33
|
+
end
|
34
|
+
end
|
35
|
+
end
|
@@ -0,0 +1,24 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require "lamian"
|
4
|
+
|
5
|
+
require "rabbit"
|
6
|
+
require "rabbit/receiving"
|
7
|
+
require "rabbit/receiving/message"
|
8
|
+
require "rabbit/receiving/handler_resolver"
|
9
|
+
require "rabbit/receiving/malformed_message"
|
10
|
+
|
11
|
+
class Rabbit::Receiving::Job < ActiveJob::Base
|
12
|
+
def perform(message, arguments)
|
13
|
+
Lamian.run do
|
14
|
+
begin
|
15
|
+
message = Rabbit::Receiving::Message.build(message, arguments)
|
16
|
+
handler = Rabbit::Receiving::HandlerResolver.handler_for(message)
|
17
|
+
handler.new(message).call
|
18
|
+
rescue Rabbit::Receiving::MalformedMessage => error
|
19
|
+
raise if Rabbit.config.environment == :test
|
20
|
+
Rabbit.config.exception_notifier.call(error)
|
21
|
+
end
|
22
|
+
end
|
23
|
+
end
|
24
|
+
end
|
@@ -0,0 +1,30 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module Rabbit::Receiving
|
4
|
+
class MalformedMessage < StandardError
|
5
|
+
attr_accessor :message_model, :errors
|
6
|
+
|
7
|
+
def self.logger
|
8
|
+
@logger ||= Logger.new(Rails.root.join("log", "malformed_messages.log"))
|
9
|
+
end
|
10
|
+
|
11
|
+
def self.raise!(message_model, errors, backtrace = caller(1))
|
12
|
+
error = new(message_model, errors)
|
13
|
+
logger.error error.message
|
14
|
+
raise error, error.message, backtrace
|
15
|
+
end
|
16
|
+
|
17
|
+
def initialize(message_model, errors)
|
18
|
+
self.message_model = message_model
|
19
|
+
self.errors = Array(errors)
|
20
|
+
|
21
|
+
errors_list = Array(errors).map { |e| " - #{e}" }.join("\n")
|
22
|
+
|
23
|
+
super(<<~MESSAGE)
|
24
|
+
Malformed message rejected for following reasons:
|
25
|
+
#{errors_list}
|
26
|
+
Message: #{message_model.attributes.inspect}
|
27
|
+
MESSAGE
|
28
|
+
end
|
29
|
+
end
|
30
|
+
end
|
@@ -0,0 +1,36 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require "tainbox"
|
4
|
+
|
5
|
+
require "rabbit/receiving/malformed_message"
|
6
|
+
|
7
|
+
module Rabbit::Receiving
|
8
|
+
class Message
|
9
|
+
include Tainbox
|
10
|
+
|
11
|
+
attribute :group_id
|
12
|
+
attribute :project_id
|
13
|
+
attribute :event
|
14
|
+
attribute :data
|
15
|
+
attribute :original_message
|
16
|
+
|
17
|
+
attr_accessor :original_message
|
18
|
+
|
19
|
+
def self.build(message, type:, app_id:, **)
|
20
|
+
group_id, project_id = app_id.split(".")
|
21
|
+
|
22
|
+
new(group_id: group_id, project_id: project_id, event: type, data: message)
|
23
|
+
end
|
24
|
+
|
25
|
+
def data=(value)
|
26
|
+
self.original_message = value
|
27
|
+
super(JSON.parse(value).deep_symbolize_keys)
|
28
|
+
rescue JSON::ParserError => error
|
29
|
+
mark_as_malformed!("JSON::ParserError: #{error.message}")
|
30
|
+
end
|
31
|
+
|
32
|
+
def mark_as_malformed!(errors = "Error not specified")
|
33
|
+
MalformedMessage.raise!(self, errors, caller(1))
|
34
|
+
end
|
35
|
+
end
|
36
|
+
end
|
@@ -0,0 +1,54 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require "sneakers"
|
4
|
+
|
5
|
+
require "rabbit"
|
6
|
+
require "rabbit/receiving/message"
|
7
|
+
require "rabbit/receiving/malformed_message"
|
8
|
+
require "rabbit/receiving/handler_resolver"
|
9
|
+
|
10
|
+
module Rabbit::Receiving
|
11
|
+
autoload :Job, "rabbit/receiving/job"
|
12
|
+
|
13
|
+
class Worker
|
14
|
+
include Sneakers::Worker
|
15
|
+
|
16
|
+
def self.logger
|
17
|
+
@logger ||= Logger.new(Rails.root.join("log", "incoming_rabbit_messages.log"))
|
18
|
+
end
|
19
|
+
|
20
|
+
def work_with_params(message, delivery_info, arguments)
|
21
|
+
message = message.dup.force_encoding("UTF-8")
|
22
|
+
self.class.logger.debug([message, delivery_info, arguments].join(" / "))
|
23
|
+
job_class.set(queue: queue(message, arguments)).perform_later(message, arguments.to_h)
|
24
|
+
ack!
|
25
|
+
rescue => error
|
26
|
+
raise if Rabbit.config.environment == :test
|
27
|
+
Rabbit.config.exception_notifier.call(error)
|
28
|
+
requeue!
|
29
|
+
end
|
30
|
+
|
31
|
+
private
|
32
|
+
|
33
|
+
def queue(message, arguments)
|
34
|
+
message = Rabbit::Receiving::Message.build(message, arguments)
|
35
|
+
handler = Rabbit::Receiving::HandlerResolver.handler_for(message)
|
36
|
+
queue_name = handler.queue
|
37
|
+
ignore_conversion = handler.ignore_queue_conversion
|
38
|
+
|
39
|
+
return Rabbit.default_queue_name(ignore_conversion: ignore_conversion) unless queue_name
|
40
|
+
|
41
|
+
calculated_queue = begin
|
42
|
+
queue_name.is_a?(Proc) ? queue_name.call(message, arguments) : queue_name
|
43
|
+
end
|
44
|
+
|
45
|
+
Rabbit.queue_name(calculated_queue, ignore_conversion: ignore_conversion)
|
46
|
+
rescue
|
47
|
+
Rabbit.default_queue_name
|
48
|
+
end
|
49
|
+
|
50
|
+
def job_class
|
51
|
+
Rabbit.config.receiving_job_class_callable&.call || Job
|
52
|
+
end
|
53
|
+
end
|
54
|
+
end
|
@@ -0,0 +1,20 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module Rabbit::TestHelpers
|
4
|
+
def send_rabbit_message(sender_id, event, data)
|
5
|
+
Rabbit::Receiving::Worker.new.work_with_params(data.to_json, {}, type: event, app_id: sender_id)
|
6
|
+
end
|
7
|
+
|
8
|
+
def expect_rabbit_message(args, strict: true)
|
9
|
+
expectation = if strict
|
10
|
+
args
|
11
|
+
else
|
12
|
+
-> (received_args) { expect(received_args).to match(args) }
|
13
|
+
end
|
14
|
+
expect(Rabbit).to receive(:publish).with(expectation).once
|
15
|
+
end
|
16
|
+
|
17
|
+
def expect_no_rabbit_messages
|
18
|
+
expect(Rabbit).not_to receive(:publish)
|
19
|
+
end
|
20
|
+
end
|
@@ -0,0 +1,38 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
lib = File.expand_path("lib", __dir__)
|
4
|
+
$LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
|
5
|
+
require "rabbit/version"
|
6
|
+
|
7
|
+
Gem::Specification.new do |spec|
|
8
|
+
spec.required_ruby_version = ">= 2.3.8"
|
9
|
+
|
10
|
+
spec.name = "rabbit_messaging"
|
11
|
+
spec.version = Rabbit::VERSION
|
12
|
+
spec.authors = ["Umbrellio"]
|
13
|
+
spec.email = ["oss@umbrellio.biz"]
|
14
|
+
|
15
|
+
spec.summary = "Rabbit (Rabbit Messaging)"
|
16
|
+
spec.description = "Rabbit (Rabbit Messaging)"
|
17
|
+
spec.homepage = "https://github.com/umbrellio/rabbit_messaging"
|
18
|
+
|
19
|
+
spec.files = `git ls-files -z`.split("\x0").reject { |f| f.match(%r{^spec/}) }
|
20
|
+
spec.require_paths = ["lib"]
|
21
|
+
|
22
|
+
spec.add_runtime_dependency "bunny", "~> 2.0"
|
23
|
+
spec.add_runtime_dependency "exception_notification"
|
24
|
+
spec.add_runtime_dependency "lamian"
|
25
|
+
spec.add_runtime_dependency "rails"
|
26
|
+
spec.add_runtime_dependency "sneakers", "~> 2.0"
|
27
|
+
spec.add_runtime_dependency "tainbox"
|
28
|
+
|
29
|
+
spec.add_development_dependency "bundler"
|
30
|
+
spec.add_development_dependency "bundler-audit"
|
31
|
+
spec.add_development_dependency "coveralls"
|
32
|
+
spec.add_development_dependency "pry"
|
33
|
+
spec.add_development_dependency "rake"
|
34
|
+
spec.add_development_dependency "rspec"
|
35
|
+
spec.add_development_dependency "rspec-its"
|
36
|
+
spec.add_development_dependency "rubocop-config-umbrellio"
|
37
|
+
spec.add_development_dependency "simplecov"
|
38
|
+
end
|
metadata
ADDED
@@ -0,0 +1,280 @@
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
2
|
+
name: rabbit_messaging
|
3
|
+
version: !ruby/object:Gem::Version
|
4
|
+
version: 0.6.0
|
5
|
+
platform: ruby
|
6
|
+
authors:
|
7
|
+
- Umbrellio
|
8
|
+
autorequire:
|
9
|
+
bindir: bin
|
10
|
+
cert_chain: []
|
11
|
+
date: 2019-06-05 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: '2.0'
|
20
|
+
type: :runtime
|
21
|
+
prerelease: false
|
22
|
+
version_requirements: !ruby/object:Gem::Requirement
|
23
|
+
requirements:
|
24
|
+
- - "~>"
|
25
|
+
- !ruby/object:Gem::Version
|
26
|
+
version: '2.0'
|
27
|
+
- !ruby/object:Gem::Dependency
|
28
|
+
name: exception_notification
|
29
|
+
requirement: !ruby/object:Gem::Requirement
|
30
|
+
requirements:
|
31
|
+
- - ">="
|
32
|
+
- !ruby/object:Gem::Version
|
33
|
+
version: '0'
|
34
|
+
type: :runtime
|
35
|
+
prerelease: false
|
36
|
+
version_requirements: !ruby/object:Gem::Requirement
|
37
|
+
requirements:
|
38
|
+
- - ">="
|
39
|
+
- !ruby/object:Gem::Version
|
40
|
+
version: '0'
|
41
|
+
- !ruby/object:Gem::Dependency
|
42
|
+
name: lamian
|
43
|
+
requirement: !ruby/object:Gem::Requirement
|
44
|
+
requirements:
|
45
|
+
- - ">="
|
46
|
+
- !ruby/object:Gem::Version
|
47
|
+
version: '0'
|
48
|
+
type: :runtime
|
49
|
+
prerelease: false
|
50
|
+
version_requirements: !ruby/object:Gem::Requirement
|
51
|
+
requirements:
|
52
|
+
- - ">="
|
53
|
+
- !ruby/object:Gem::Version
|
54
|
+
version: '0'
|
55
|
+
- !ruby/object:Gem::Dependency
|
56
|
+
name: rails
|
57
|
+
requirement: !ruby/object:Gem::Requirement
|
58
|
+
requirements:
|
59
|
+
- - ">="
|
60
|
+
- !ruby/object:Gem::Version
|
61
|
+
version: '0'
|
62
|
+
type: :runtime
|
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: sneakers
|
71
|
+
requirement: !ruby/object:Gem::Requirement
|
72
|
+
requirements:
|
73
|
+
- - "~>"
|
74
|
+
- !ruby/object:Gem::Version
|
75
|
+
version: '2.0'
|
76
|
+
type: :runtime
|
77
|
+
prerelease: false
|
78
|
+
version_requirements: !ruby/object:Gem::Requirement
|
79
|
+
requirements:
|
80
|
+
- - "~>"
|
81
|
+
- !ruby/object:Gem::Version
|
82
|
+
version: '2.0'
|
83
|
+
- !ruby/object:Gem::Dependency
|
84
|
+
name: tainbox
|
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: bundler
|
99
|
+
requirement: !ruby/object:Gem::Requirement
|
100
|
+
requirements:
|
101
|
+
- - ">="
|
102
|
+
- !ruby/object:Gem::Version
|
103
|
+
version: '0'
|
104
|
+
type: :development
|
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: bundler-audit
|
113
|
+
requirement: !ruby/object:Gem::Requirement
|
114
|
+
requirements:
|
115
|
+
- - ">="
|
116
|
+
- !ruby/object:Gem::Version
|
117
|
+
version: '0'
|
118
|
+
type: :development
|
119
|
+
prerelease: false
|
120
|
+
version_requirements: !ruby/object:Gem::Requirement
|
121
|
+
requirements:
|
122
|
+
- - ">="
|
123
|
+
- !ruby/object:Gem::Version
|
124
|
+
version: '0'
|
125
|
+
- !ruby/object:Gem::Dependency
|
126
|
+
name: coveralls
|
127
|
+
requirement: !ruby/object:Gem::Requirement
|
128
|
+
requirements:
|
129
|
+
- - ">="
|
130
|
+
- !ruby/object:Gem::Version
|
131
|
+
version: '0'
|
132
|
+
type: :development
|
133
|
+
prerelease: false
|
134
|
+
version_requirements: !ruby/object:Gem::Requirement
|
135
|
+
requirements:
|
136
|
+
- - ">="
|
137
|
+
- !ruby/object:Gem::Version
|
138
|
+
version: '0'
|
139
|
+
- !ruby/object:Gem::Dependency
|
140
|
+
name: pry
|
141
|
+
requirement: !ruby/object:Gem::Requirement
|
142
|
+
requirements:
|
143
|
+
- - ">="
|
144
|
+
- !ruby/object:Gem::Version
|
145
|
+
version: '0'
|
146
|
+
type: :development
|
147
|
+
prerelease: false
|
148
|
+
version_requirements: !ruby/object:Gem::Requirement
|
149
|
+
requirements:
|
150
|
+
- - ">="
|
151
|
+
- !ruby/object:Gem::Version
|
152
|
+
version: '0'
|
153
|
+
- !ruby/object:Gem::Dependency
|
154
|
+
name: rake
|
155
|
+
requirement: !ruby/object:Gem::Requirement
|
156
|
+
requirements:
|
157
|
+
- - ">="
|
158
|
+
- !ruby/object:Gem::Version
|
159
|
+
version: '0'
|
160
|
+
type: :development
|
161
|
+
prerelease: false
|
162
|
+
version_requirements: !ruby/object:Gem::Requirement
|
163
|
+
requirements:
|
164
|
+
- - ">="
|
165
|
+
- !ruby/object:Gem::Version
|
166
|
+
version: '0'
|
167
|
+
- !ruby/object:Gem::Dependency
|
168
|
+
name: rspec
|
169
|
+
requirement: !ruby/object:Gem::Requirement
|
170
|
+
requirements:
|
171
|
+
- - ">="
|
172
|
+
- !ruby/object:Gem::Version
|
173
|
+
version: '0'
|
174
|
+
type: :development
|
175
|
+
prerelease: false
|
176
|
+
version_requirements: !ruby/object:Gem::Requirement
|
177
|
+
requirements:
|
178
|
+
- - ">="
|
179
|
+
- !ruby/object:Gem::Version
|
180
|
+
version: '0'
|
181
|
+
- !ruby/object:Gem::Dependency
|
182
|
+
name: rspec-its
|
183
|
+
requirement: !ruby/object:Gem::Requirement
|
184
|
+
requirements:
|
185
|
+
- - ">="
|
186
|
+
- !ruby/object:Gem::Version
|
187
|
+
version: '0'
|
188
|
+
type: :development
|
189
|
+
prerelease: false
|
190
|
+
version_requirements: !ruby/object:Gem::Requirement
|
191
|
+
requirements:
|
192
|
+
- - ">="
|
193
|
+
- !ruby/object:Gem::Version
|
194
|
+
version: '0'
|
195
|
+
- !ruby/object:Gem::Dependency
|
196
|
+
name: rubocop-config-umbrellio
|
197
|
+
requirement: !ruby/object:Gem::Requirement
|
198
|
+
requirements:
|
199
|
+
- - ">="
|
200
|
+
- !ruby/object:Gem::Version
|
201
|
+
version: '0'
|
202
|
+
type: :development
|
203
|
+
prerelease: false
|
204
|
+
version_requirements: !ruby/object:Gem::Requirement
|
205
|
+
requirements:
|
206
|
+
- - ">="
|
207
|
+
- !ruby/object:Gem::Version
|
208
|
+
version: '0'
|
209
|
+
- !ruby/object:Gem::Dependency
|
210
|
+
name: simplecov
|
211
|
+
requirement: !ruby/object:Gem::Requirement
|
212
|
+
requirements:
|
213
|
+
- - ">="
|
214
|
+
- !ruby/object:Gem::Version
|
215
|
+
version: '0'
|
216
|
+
type: :development
|
217
|
+
prerelease: false
|
218
|
+
version_requirements: !ruby/object:Gem::Requirement
|
219
|
+
requirements:
|
220
|
+
- - ">="
|
221
|
+
- !ruby/object:Gem::Version
|
222
|
+
version: '0'
|
223
|
+
description: Rabbit (Rabbit Messaging)
|
224
|
+
email:
|
225
|
+
- oss@umbrellio.biz
|
226
|
+
executables: []
|
227
|
+
extensions: []
|
228
|
+
extra_rdoc_files: []
|
229
|
+
files:
|
230
|
+
- ".gitignore"
|
231
|
+
- ".rspec"
|
232
|
+
- ".rubocop.yml"
|
233
|
+
- ".travis.yml"
|
234
|
+
- Gemfile
|
235
|
+
- LICENSE.md
|
236
|
+
- README.md
|
237
|
+
- Rakefile
|
238
|
+
- bin/console
|
239
|
+
- bin/setup
|
240
|
+
- environments/development.rb
|
241
|
+
- lib/rabbit.rb
|
242
|
+
- lib/rabbit/daemon.rb
|
243
|
+
- lib/rabbit/event_handler.rb
|
244
|
+
- lib/rabbit/extensions/bunny/channel.rb
|
245
|
+
- lib/rabbit/publishing.rb
|
246
|
+
- lib/rabbit/publishing/job.rb
|
247
|
+
- lib/rabbit/publishing/message.rb
|
248
|
+
- lib/rabbit/receiving.rb
|
249
|
+
- lib/rabbit/receiving/handler_resolver.rb
|
250
|
+
- lib/rabbit/receiving/job.rb
|
251
|
+
- lib/rabbit/receiving/malformed_message.rb
|
252
|
+
- lib/rabbit/receiving/message.rb
|
253
|
+
- lib/rabbit/receiving/worker.rb
|
254
|
+
- lib/rabbit/test_helpers.rb
|
255
|
+
- lib/rabbit/version.rb
|
256
|
+
- lib/rabbit_messaging.rb
|
257
|
+
- rabbit_messaging.gemspec
|
258
|
+
homepage: https://github.com/umbrellio/rabbit_messaging
|
259
|
+
licenses: []
|
260
|
+
metadata: {}
|
261
|
+
post_install_message:
|
262
|
+
rdoc_options: []
|
263
|
+
require_paths:
|
264
|
+
- lib
|
265
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
266
|
+
requirements:
|
267
|
+
- - ">="
|
268
|
+
- !ruby/object:Gem::Version
|
269
|
+
version: 2.3.8
|
270
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
271
|
+
requirements:
|
272
|
+
- - ">="
|
273
|
+
- !ruby/object:Gem::Version
|
274
|
+
version: '0'
|
275
|
+
requirements: []
|
276
|
+
rubygems_version: 3.0.3
|
277
|
+
signing_key:
|
278
|
+
specification_version: 4
|
279
|
+
summary: Rabbit (Rabbit Messaging)
|
280
|
+
test_files: []
|