emque-producing 0.0.2
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 +34 -0
- data/Gemfile +3 -0
- data/Gemfile.lock +64 -0
- data/LICENSE.txt +22 -0
- data/README.md +98 -0
- data/Rakefile +10 -0
- data/emque-producing.gemspec +33 -0
- data/lib/emque-producing.rb +1 -0
- data/lib/emque/producing.rb +8 -0
- data/lib/emque/producing/configuration.rb +24 -0
- data/lib/emque/producing/logging.rb +25 -0
- data/lib/emque/producing/message/message.rb +146 -0
- data/lib/emque/producing/producing.rb +43 -0
- data/lib/emque/producing/publisher/base.rb +23 -0
- data/lib/emque/producing/publisher/kafka.rb +25 -0
- data/lib/emque/producing/publisher/rabbitmq.rb +58 -0
- data/lib/emque/producing/version.rb +5 -0
- data/spec/bin/kafka-run-class.sh +67 -0
- data/spec/kafka_spec_helper.rb +33 -0
- data/spec/producing/configuration_spec.rb +21 -0
- data/spec/producing/message/message_spec.rb +88 -0
- data/spec/producing/producing_spec.rb +5 -0
- data/spec/producing/publisher_spec.rb +20 -0
- data/spec/spec_helper.rb +22 -0
- data/spec/test_cluster.rb +201 -0
- metadata +191 -0
checksums.yaml
ADDED
@@ -0,0 +1,7 @@
|
|
1
|
+
---
|
2
|
+
SHA1:
|
3
|
+
metadata.gz: cc3013b37568f755a5f258d0c18b3a8e346ac219
|
4
|
+
data.tar.gz: 28aad21a17a39be148e7d22611df8b4d992c85f6
|
5
|
+
SHA512:
|
6
|
+
metadata.gz: 997635efddaa40fe279c246a3862917666b4c4d154b6809c9c69e7fe6e3a4281ffac27e8a1638c8556467f764be2cdb62a9b8d67edaf90331541e2d581b733da
|
7
|
+
data.tar.gz: 5cebfd302c30b90c1863555cd5b7fce581d67d1278310a05d6ad13f4bf71e573bf9a50311204da6a74e7108de3d7f735654db85905639bf621b14f982e68dfda
|
data/.gitignore
ADDED
@@ -0,0 +1,34 @@
|
|
1
|
+
*.gem
|
2
|
+
*.rbc
|
3
|
+
/.config
|
4
|
+
/coverage/
|
5
|
+
/InstalledFiles
|
6
|
+
/pkg/
|
7
|
+
/spec/reports/
|
8
|
+
/test/tmp/
|
9
|
+
/test/version_tmp/
|
10
|
+
/tmp/
|
11
|
+
|
12
|
+
## Specific to RubyMotion:
|
13
|
+
.dat*
|
14
|
+
.repl_history
|
15
|
+
build/
|
16
|
+
|
17
|
+
## Documentation cache and generated files:
|
18
|
+
/.yardoc/
|
19
|
+
/_yardoc/
|
20
|
+
/doc/
|
21
|
+
/rdoc/
|
22
|
+
|
23
|
+
## Environment normalisation:
|
24
|
+
/.bundle/
|
25
|
+
/lib/bundler/man/
|
26
|
+
|
27
|
+
# for a library or gem, you might want to ignore these files since the code is
|
28
|
+
# intended to run in multiple environments; otherwise, check them in:
|
29
|
+
# Gemfile.lock
|
30
|
+
# .ruby-version
|
31
|
+
# .ruby-gemset
|
32
|
+
|
33
|
+
# unless supporting rvm < 1.11.0 or doing something fancy, ignore this:
|
34
|
+
.rvmrc
|
data/Gemfile
ADDED
data/Gemfile.lock
ADDED
@@ -0,0 +1,64 @@
|
|
1
|
+
PATH
|
2
|
+
remote: .
|
3
|
+
specs:
|
4
|
+
emque-producing (0.0.2)
|
5
|
+
oj (~> 2.10.2)
|
6
|
+
virtus (~> 1.0.3)
|
7
|
+
|
8
|
+
GEM
|
9
|
+
remote: https://rubygems.org/
|
10
|
+
specs:
|
11
|
+
amq-protocol (1.9.2)
|
12
|
+
axiom-types (0.1.1)
|
13
|
+
descendants_tracker (~> 0.0.4)
|
14
|
+
ice_nine (~> 0.11.0)
|
15
|
+
thread_safe (~> 0.3, >= 0.3.1)
|
16
|
+
bunny (1.4.1)
|
17
|
+
amq-protocol (>= 1.9.2)
|
18
|
+
coderay (1.1.0)
|
19
|
+
coercible (1.0.0)
|
20
|
+
descendants_tracker (~> 0.0.1)
|
21
|
+
descendants_tracker (0.0.4)
|
22
|
+
thread_safe (~> 0.3, >= 0.3.1)
|
23
|
+
diff-lcs (1.2.5)
|
24
|
+
equalizer (0.0.9)
|
25
|
+
ice_nine (0.11.0)
|
26
|
+
method_source (0.8.2)
|
27
|
+
oj (2.10.2)
|
28
|
+
poseidon (0.0.4)
|
29
|
+
pry (0.9.12.4)
|
30
|
+
coderay (~> 1.0)
|
31
|
+
method_source (~> 0.8)
|
32
|
+
slop (~> 3.4)
|
33
|
+
rake (10.1.1)
|
34
|
+
rspec (3.1.0)
|
35
|
+
rspec-core (~> 3.1.0)
|
36
|
+
rspec-expectations (~> 3.1.0)
|
37
|
+
rspec-mocks (~> 3.1.0)
|
38
|
+
rspec-core (3.1.5)
|
39
|
+
rspec-support (~> 3.1.0)
|
40
|
+
rspec-expectations (3.1.2)
|
41
|
+
diff-lcs (>= 1.2.0, < 2.0)
|
42
|
+
rspec-support (~> 3.1.0)
|
43
|
+
rspec-mocks (3.1.2)
|
44
|
+
rspec-support (~> 3.1.0)
|
45
|
+
rspec-support (3.1.1)
|
46
|
+
slop (3.4.7)
|
47
|
+
thread_safe (0.3.4)
|
48
|
+
virtus (1.0.3)
|
49
|
+
axiom-types (~> 0.1)
|
50
|
+
coercible (~> 1.0)
|
51
|
+
descendants_tracker (~> 0.0, >= 0.0.3)
|
52
|
+
equalizer (~> 0.0, >= 0.0.9)
|
53
|
+
|
54
|
+
PLATFORMS
|
55
|
+
ruby
|
56
|
+
|
57
|
+
DEPENDENCIES
|
58
|
+
bundler (~> 1.0)
|
59
|
+
bunny (~> 1.4.1)
|
60
|
+
emque-producing!
|
61
|
+
poseidon (= 0.0.4)
|
62
|
+
pry
|
63
|
+
rake
|
64
|
+
rspec (~> 3.1)
|
data/LICENSE.txt
ADDED
@@ -0,0 +1,22 @@
|
|
1
|
+
Copyright (c) 2014 TeamSnap
|
2
|
+
|
3
|
+
MIT License
|
4
|
+
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining
|
6
|
+
a copy of this software and associated documentation files (the
|
7
|
+
"Software"), to deal in the Software without restriction, including
|
8
|
+
without limitation the rights to use, copy, modify, merge, publish,
|
9
|
+
distribute, sublicense, and/or sell copies of the Software, and to
|
10
|
+
permit persons to whom the Software is furnished to do so, subject to
|
11
|
+
the following conditions:
|
12
|
+
|
13
|
+
The above copyright notice and this permission notice shall be
|
14
|
+
included in all copies or substantial portions of the Software.
|
15
|
+
|
16
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
17
|
+
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
18
|
+
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
19
|
+
NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
|
20
|
+
LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
|
21
|
+
OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
|
22
|
+
WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
data/README.md
ADDED
@@ -0,0 +1,98 @@
|
|
1
|
+
[ ](https://www.codeship.io/projects/34115)
|
3
|
+
|
4
|
+
# Emque Producing
|
5
|
+
|
6
|
+
Define and send messages with Ruby to a variety of [message brokers](http://en.wikipedia.org/wiki/Message_broker).
|
7
|
+
Currently supported message brokers are [RabbitMQ](https://www.rabbitmq.com) and
|
8
|
+
[Kafka](http://kafka.apache.org/).
|
9
|
+
|
10
|
+
This is a library that pairs nicely with [Emque
|
11
|
+
Consuming](https://www.github.com/teamsnap/emque-consuming), a framework for
|
12
|
+
consuming and routing messages to your code.
|
13
|
+
|
14
|
+
## Installation
|
15
|
+
|
16
|
+
Add these lines to your application's Gemfile, depending on your message broker:
|
17
|
+
|
18
|
+
# for RabbitMQ, bunny is used
|
19
|
+
gem "emque-producing"
|
20
|
+
gem "bunny", "~> 1.4.1"
|
21
|
+
|
22
|
+
or
|
23
|
+
|
24
|
+
# for Kafka, poseidon is used
|
25
|
+
gem "emque-producing"
|
26
|
+
gem "poseidon", "0.0.4"
|
27
|
+
|
28
|
+
And then execute:
|
29
|
+
|
30
|
+
$ bundle
|
31
|
+
|
32
|
+
Or install it yourself as:
|
33
|
+
|
34
|
+
$ gem install emque-producing
|
35
|
+
|
36
|
+
## Usage
|
37
|
+
|
38
|
+
# configure (likely in a Rails initializer)
|
39
|
+
require 'emque-producing'
|
40
|
+
Emque::Producing.configure do |c|
|
41
|
+
c.app_name = "app"
|
42
|
+
c.publishing_adapter = :rabbitmq
|
43
|
+
c.rabbitmq_options = { :url => "amqp://guest:guest@localhost:5672" }
|
44
|
+
#c.kafka_options = { :seed_brokers => [localhost:9092],
|
45
|
+
# :producer_options => {} }
|
46
|
+
c.error_handlers << Proc.new {|ex,context|
|
47
|
+
# notify/log
|
48
|
+
}
|
49
|
+
end
|
50
|
+
|
51
|
+
# create a message class
|
52
|
+
class MyMessage
|
53
|
+
include Emque::Producing::Message
|
54
|
+
topic "topic1"
|
55
|
+
message_type "mymessage.new"
|
56
|
+
|
57
|
+
attribute :first_property, Integer, :required => true
|
58
|
+
attribute :another_property, String, :required => true
|
59
|
+
end
|
60
|
+
|
61
|
+
# produce message
|
62
|
+
message = MyMessage.new({:first_property => 1, :another_property => "another"})
|
63
|
+
message.publish
|
64
|
+
|
65
|
+
## Requirements
|
66
|
+
|
67
|
+
* Ruby 1.9.3 or higher
|
68
|
+
* RabbitMQ 3.x
|
69
|
+
* Bunny 1.4.x
|
70
|
+
* Kafka 0.8.1
|
71
|
+
* Poseidon 0.0.4
|
72
|
+
|
73
|
+
## Tests
|
74
|
+
|
75
|
+
To run tests...
|
76
|
+
|
77
|
+
```
|
78
|
+
rspec
|
79
|
+
```
|
80
|
+
|
81
|
+
If you would like to test the gem as part of your client, you can update the
|
82
|
+
configuration option `publish_messages` to false like so:
|
83
|
+
```ruby
|
84
|
+
Emque::Producing.configure do |c|
|
85
|
+
c.publish_messages = false
|
86
|
+
...other options
|
87
|
+
end
|
88
|
+
```
|
89
|
+
This will prevent Emque from actually attempting to make the connection to your
|
90
|
+
adapter which may be convenient in the case of CI environments.
|
91
|
+
|
92
|
+
## Contributing
|
93
|
+
|
94
|
+
1. Fork it ( http://github.com/teamsnap/emquemessages/fork )
|
95
|
+
2. Create your feature branch (`git checkout -b my-new-feature`)
|
96
|
+
3. Commit your changes (`git commit -am 'Add some feature'`)
|
97
|
+
4. Push to the branch (`git push origin my-new-feature`)
|
98
|
+
5. Create new Pull Request
|
data/Rakefile
ADDED
@@ -0,0 +1,33 @@
|
|
1
|
+
# coding: utf-8
|
2
|
+
lib = File.expand_path('../lib/', __FILE__)
|
3
|
+
$LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
|
4
|
+
require 'emque/producing/version'
|
5
|
+
|
6
|
+
Gem::Specification.new do |spec|
|
7
|
+
spec.name = "emque-producing"
|
8
|
+
spec.version = Emque::Producing::VERSION
|
9
|
+
spec.platform = Gem::Platform::RUBY
|
10
|
+
spec.authors = ["Emily Dobervich", "Ryan Williams"]
|
11
|
+
spec.email = ["emily@teamsnap.com", "ryan.williams@teamsnap.com"]
|
12
|
+
spec.summary = %q{Define and send messages to a variety of message brokers}
|
13
|
+
spec.description = %q{Define and send messages to a variety of message brokers}
|
14
|
+
spec.homepage = ""
|
15
|
+
spec.license = "MIT"
|
16
|
+
spec.required_ruby_version = '>= 1.9.3'
|
17
|
+
|
18
|
+
# Manifest
|
19
|
+
spec.files = `git ls-files`.split("\n")
|
20
|
+
spec.executables = spec.files.grep(%r{^bin/}) { |f| File.basename(f) }
|
21
|
+
spec.test_files = spec.files.grep(%r{^(test|spec|features)/})
|
22
|
+
spec.require_paths = ["lib"]
|
23
|
+
|
24
|
+
spec.add_dependency "oj", "~> 2.10.2"
|
25
|
+
spec.add_dependency "virtus", "~> 1.0.3"
|
26
|
+
|
27
|
+
spec.add_development_dependency "bundler", "~> 1.0"
|
28
|
+
spec.add_development_dependency "rake"
|
29
|
+
spec.add_development_dependency "rspec", "~> 3.1"
|
30
|
+
spec.add_development_dependency "pry"
|
31
|
+
spec.add_development_dependency "poseidon", "0.0.4"
|
32
|
+
spec.add_development_dependency "bunny", "~> 1.4.1"
|
33
|
+
end
|
@@ -0,0 +1 @@
|
|
1
|
+
require "emque/producing"
|
@@ -0,0 +1,8 @@
|
|
1
|
+
require "virtus"
|
2
|
+
require "oj"
|
3
|
+
require "emque/producing/version"
|
4
|
+
require "emque/producing/producing"
|
5
|
+
require "emque/producing/configuration"
|
6
|
+
require "emque/producing/logging"
|
7
|
+
require "emque/producing/publisher/base"
|
8
|
+
require "emque/producing/message/message"
|
@@ -0,0 +1,24 @@
|
|
1
|
+
module Emque
|
2
|
+
module Producing
|
3
|
+
class Configuration
|
4
|
+
attr_accessor :app_name
|
5
|
+
attr_accessor :publishing_adapter
|
6
|
+
attr_accessor :kafka_options
|
7
|
+
attr_accessor :rabbitmq_options
|
8
|
+
attr_accessor :error_handlers
|
9
|
+
attr_accessor :log_publish_message
|
10
|
+
attr_accessor :publish_messages
|
11
|
+
|
12
|
+
def initialize
|
13
|
+
@app_name = ""
|
14
|
+
@publishing_adapter = :rabbitmq
|
15
|
+
@error_handlers = []
|
16
|
+
@log_publish_message = false
|
17
|
+
@publish_messages = true
|
18
|
+
@kafka_options = { :seed_brokers => ["localhost:9092"],
|
19
|
+
:producer_options => {} }
|
20
|
+
@rabbitmq_options = { :url => "amqp://guest:guest@localhost:5672" }
|
21
|
+
end
|
22
|
+
end
|
23
|
+
end
|
24
|
+
end
|
@@ -0,0 +1,25 @@
|
|
1
|
+
require "logger"
|
2
|
+
|
3
|
+
module Emque
|
4
|
+
module Producing
|
5
|
+
class Logging
|
6
|
+
def self.initialize_logger(log_target = STDOUT)
|
7
|
+
@logger = Logger.new(log_target)
|
8
|
+
@logger.level = Logger::INFO
|
9
|
+
@logger
|
10
|
+
end
|
11
|
+
|
12
|
+
def self.logger
|
13
|
+
defined?(@logger) ? @logger : initialize_logger
|
14
|
+
end
|
15
|
+
|
16
|
+
def self.logger=(log)
|
17
|
+
@logger = log || Logger.new("/dev/null")
|
18
|
+
end
|
19
|
+
|
20
|
+
def logger
|
21
|
+
Emque::Producing::Logging.logger
|
22
|
+
end
|
23
|
+
end
|
24
|
+
end
|
25
|
+
end
|
@@ -0,0 +1,146 @@
|
|
1
|
+
require 'securerandom'
|
2
|
+
|
3
|
+
module Emque
|
4
|
+
module Producing
|
5
|
+
module Message
|
6
|
+
InvalidMessageError = Class.new(StandardError)
|
7
|
+
MessagesNotSentError = Class.new(StandardError)
|
8
|
+
|
9
|
+
module ClassMethods
|
10
|
+
def topic(name)
|
11
|
+
@topic = name
|
12
|
+
end
|
13
|
+
|
14
|
+
def read_topic
|
15
|
+
@topic
|
16
|
+
end
|
17
|
+
|
18
|
+
def message_type(name)
|
19
|
+
@message_type = name
|
20
|
+
end
|
21
|
+
|
22
|
+
def read_message_type
|
23
|
+
@message_type
|
24
|
+
end
|
25
|
+
|
26
|
+
def private_attribute(name, coercion=nil, opts={})
|
27
|
+
@private_attrs ||= []
|
28
|
+
@private_attrs << name
|
29
|
+
attribute(name, coercion, opts)
|
30
|
+
end
|
31
|
+
|
32
|
+
def private_attrs
|
33
|
+
Array(@private_attrs)
|
34
|
+
end
|
35
|
+
end
|
36
|
+
|
37
|
+
def self.included(base)
|
38
|
+
base.extend(ClassMethods)
|
39
|
+
base.send(:include, Virtus.model)
|
40
|
+
base.send(:attribute, :partition_key, String, :default => nil, :required => false)
|
41
|
+
end
|
42
|
+
|
43
|
+
def add_metadata
|
44
|
+
{
|
45
|
+
:metadata =>
|
46
|
+
{
|
47
|
+
:host => host_name,
|
48
|
+
:app => app_name,
|
49
|
+
:topic => topic,
|
50
|
+
:created_at => formatted_time,
|
51
|
+
:uuid => uuid,
|
52
|
+
:type => message_type,
|
53
|
+
:partition_key => partition_key
|
54
|
+
}
|
55
|
+
}.merge(public_attributes)
|
56
|
+
end
|
57
|
+
|
58
|
+
def topic
|
59
|
+
self.class.read_topic
|
60
|
+
end
|
61
|
+
|
62
|
+
def message_type
|
63
|
+
self.class.read_message_type
|
64
|
+
end
|
65
|
+
|
66
|
+
def valid?
|
67
|
+
invalid_attributes.empty? && topic && message_type
|
68
|
+
end
|
69
|
+
|
70
|
+
def invalid_attributes
|
71
|
+
invalid_attrs = self.class.attribute_set.inject([]) do |attrs, attr|
|
72
|
+
attrs << attr.name if attr.required? && self.attributes.fetch(attr.name).nil?
|
73
|
+
attrs
|
74
|
+
end
|
75
|
+
Array(invalid_attrs) - self.class.private_attrs
|
76
|
+
end
|
77
|
+
|
78
|
+
def to_json
|
79
|
+
data = self.add_metadata
|
80
|
+
Oj.dump(data, :mode => :compat)
|
81
|
+
end
|
82
|
+
|
83
|
+
def publish(publisher=Emque::Producing.publisher)
|
84
|
+
log "publishing...", true
|
85
|
+
if valid?
|
86
|
+
log "valid...", true
|
87
|
+
if Emque::Producing.configuration.publish_messages
|
88
|
+
sent = publisher.publish(topic, message_type, to_json, partition_key)
|
89
|
+
log "sent #{sent}"
|
90
|
+
raise MessagesNotSentError.new unless sent
|
91
|
+
end
|
92
|
+
else
|
93
|
+
log "failed...", true
|
94
|
+
raise InvalidMessageError.new(invalid_message)
|
95
|
+
end
|
96
|
+
end
|
97
|
+
|
98
|
+
private
|
99
|
+
|
100
|
+
def invalid_message
|
101
|
+
if !topic
|
102
|
+
"A topic is required"
|
103
|
+
elsif !message_type
|
104
|
+
"A message type is required"
|
105
|
+
else
|
106
|
+
"Required attributes #{invalid_attributes} are missing."
|
107
|
+
end
|
108
|
+
end
|
109
|
+
|
110
|
+
def host_name
|
111
|
+
Socket.gethostbyname(Socket.gethostname).first
|
112
|
+
end
|
113
|
+
|
114
|
+
def formatted_time
|
115
|
+
DateTime.now.new_offset(0).to_time.utc.iso8601
|
116
|
+
end
|
117
|
+
|
118
|
+
def uuid
|
119
|
+
SecureRandom.uuid
|
120
|
+
end
|
121
|
+
|
122
|
+
def app_name
|
123
|
+
Emque::Producing.configuration.app_name || raise("Messages must have an app name configured.")
|
124
|
+
end
|
125
|
+
|
126
|
+
def log(message, include_message = false)
|
127
|
+
if Emque::Producing.configuration.log_publish_message
|
128
|
+
message = "#{message} #{to_json}" if include_message
|
129
|
+
Emque::Producing.logger.info("MESSAGE LOG: #{message}")
|
130
|
+
end
|
131
|
+
end
|
132
|
+
|
133
|
+
def public_attributes
|
134
|
+
public = self.class.attribute_set.select do |attr|
|
135
|
+
attr && !self.class.private_attrs.include?(attr.name)
|
136
|
+
end.map(&:name)
|
137
|
+
slice_attributes(*public)
|
138
|
+
end
|
139
|
+
|
140
|
+
def slice_attributes(*keys)
|
141
|
+
keys.map!(&:to_sym)
|
142
|
+
attributes.select { |key, value| keys.include?(key) }
|
143
|
+
end
|
144
|
+
end
|
145
|
+
end
|
146
|
+
end
|
@@ -0,0 +1,43 @@
|
|
1
|
+
module Emque
|
2
|
+
module Producing
|
3
|
+
class << self
|
4
|
+
attr_accessor :publisher
|
5
|
+
attr_writer :configuration
|
6
|
+
|
7
|
+
def configure
|
8
|
+
yield(configuration)
|
9
|
+
end
|
10
|
+
|
11
|
+
def configuration
|
12
|
+
@configuration ||= Emque::Producing::Configuration.new
|
13
|
+
end
|
14
|
+
|
15
|
+
def host_name
|
16
|
+
Socket.gethostbyname(Socket.gethostname).first
|
17
|
+
end
|
18
|
+
|
19
|
+
def publisher
|
20
|
+
return @publisher unless @publisher.nil?
|
21
|
+
|
22
|
+
if (configuration.publishing_adapter == :kafka)
|
23
|
+
require "emque/producing/publisher/kafka"
|
24
|
+
@publisher = Emque::Producing::Publisher::Kafka.new
|
25
|
+
elsif (configuration.publishing_adapter == :rabbitmq)
|
26
|
+
require "emque/producing/publisher/rabbitmq"
|
27
|
+
@publisher = Emque::Producing::Publisher::RabbitMq.new
|
28
|
+
else
|
29
|
+
raise "No publisher configured"
|
30
|
+
end
|
31
|
+
@publisher
|
32
|
+
end
|
33
|
+
|
34
|
+
def logger
|
35
|
+
Emque::Producing::Logging.logger
|
36
|
+
end
|
37
|
+
|
38
|
+
def logger=(log)
|
39
|
+
Emque::Producing::Logging.logger = log
|
40
|
+
end
|
41
|
+
end
|
42
|
+
end
|
43
|
+
end
|
@@ -0,0 +1,23 @@
|
|
1
|
+
module Emque
|
2
|
+
module Producing
|
3
|
+
module Publisher
|
4
|
+
class Base
|
5
|
+
def host_name
|
6
|
+
Socket.gethostbyname(Socket.gethostname).first
|
7
|
+
end
|
8
|
+
|
9
|
+
def handle_error(e)
|
10
|
+
Emque::Producing.configuration.error_handlers.each do |handler|
|
11
|
+
begin
|
12
|
+
handler.call(e, nil)
|
13
|
+
rescue => ex
|
14
|
+
Emque::Producing.logger.error "Producer error hander raised an error"
|
15
|
+
Emque::Producing.logger.error ex
|
16
|
+
Emque::Producing.logger.error Array(ex.backtrace).join("\n")
|
17
|
+
end
|
18
|
+
end
|
19
|
+
end
|
20
|
+
end
|
21
|
+
end
|
22
|
+
end
|
23
|
+
end
|
@@ -0,0 +1,25 @@
|
|
1
|
+
require "poseidon"
|
2
|
+
|
3
|
+
module Emque
|
4
|
+
module Producing
|
5
|
+
module Publisher
|
6
|
+
class Kafka < Emque::Producing::Publisher::Base
|
7
|
+
def initialize
|
8
|
+
@producer = Poseidon::Producer.new(
|
9
|
+
Emque::Producing.configuration.kafka_options[:seed_brokers],
|
10
|
+
"producer_#{host_name}_#{Process.pid}",
|
11
|
+
Emque::Producing.configuration.kafka_options[:producer_options])
|
12
|
+
end
|
13
|
+
|
14
|
+
def publish(topic, message_type, message, key = nil)
|
15
|
+
begin
|
16
|
+
msg = Poseidon::MessageToSend.new(topic, message, key)
|
17
|
+
@producer.send_messages([msg])
|
18
|
+
rescue => e
|
19
|
+
handle_error(e)
|
20
|
+
end
|
21
|
+
end
|
22
|
+
end
|
23
|
+
end
|
24
|
+
end
|
25
|
+
end
|
@@ -0,0 +1,58 @@
|
|
1
|
+
require "bunny"
|
2
|
+
require "thread"
|
3
|
+
|
4
|
+
module Emque
|
5
|
+
module Producing
|
6
|
+
module Publisher
|
7
|
+
class RabbitMq < Emque::Producing::Publisher::Base
|
8
|
+
CONN = Bunny
|
9
|
+
.new(Emque::Producing.configuration.rabbitmq_options[:url])
|
10
|
+
.tap { |conn|
|
11
|
+
conn.start
|
12
|
+
}
|
13
|
+
|
14
|
+
CHANNEL_POOL = Queue
|
15
|
+
.new
|
16
|
+
.tap { |queue|
|
17
|
+
20.times { |i| queue << CONN.create_channel }
|
18
|
+
}
|
19
|
+
|
20
|
+
def publish(topic, message_type, message, key = nil)
|
21
|
+
ch = CHANNEL_POOL.pop
|
22
|
+
ch.open if ch.closed?
|
23
|
+
begin
|
24
|
+
exchange = ch.fanout(topic, :durable => true, :auto_delete => false)
|
25
|
+
|
26
|
+
# Assumes all messages are mandatory in order to let callers know if
|
27
|
+
# the message was not sent. Uses publisher confirms to wait.
|
28
|
+
ch.confirm_select
|
29
|
+
sent = true
|
30
|
+
exchange.on_return do |return_info, properties, content|
|
31
|
+
sent = false
|
32
|
+
end
|
33
|
+
|
34
|
+
exchange.publish(
|
35
|
+
message,
|
36
|
+
:mandatory => true,
|
37
|
+
:persistent => true,
|
38
|
+
:type => message_type,
|
39
|
+
:app_id => Emque::Producing.configuration.app_name,
|
40
|
+
:content_type => "application/json")
|
41
|
+
|
42
|
+
success = ch.wait_for_confirms
|
43
|
+
unless success
|
44
|
+
Emque::Producing.logger.warn("RabbitMQ Publisher: message was nacked")
|
45
|
+
ch.nacked_set.each do |n|
|
46
|
+
Emque::Producing.logger.warn("message id: #{n}")
|
47
|
+
end
|
48
|
+
end
|
49
|
+
|
50
|
+
return sent
|
51
|
+
ensure
|
52
|
+
CHANNEL_POOL << ch unless ch.nil?
|
53
|
+
end
|
54
|
+
end
|
55
|
+
end
|
56
|
+
end
|
57
|
+
end
|
58
|
+
end
|
@@ -0,0 +1,67 @@
|
|
1
|
+
#!/bin/bash
|
2
|
+
# Licensed to the Apache Software Foundation (ASF) under one or more
|
3
|
+
# contributor license agreements. See the NOTICE file distributed with
|
4
|
+
# this work for additional information regarding copyright ownership.
|
5
|
+
# The ASF licenses this file to You under the Apache License, Version 2.0
|
6
|
+
# (the "License"); you may not use this file except in compliance with
|
7
|
+
# the License. You may obtain a copy of the License at
|
8
|
+
#
|
9
|
+
# http://www.apache.org/licenses/LICENSE-2.0
|
10
|
+
#
|
11
|
+
# Unless required by applicable law or agreed to in writing, software
|
12
|
+
# distributed under the License is distributed on an "AS IS" BASIS,
|
13
|
+
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
14
|
+
# See the License for the specific language governing permissions and
|
15
|
+
# limitations under the License.
|
16
|
+
|
17
|
+
if [ $# -lt 1 ];
|
18
|
+
then
|
19
|
+
echo "USAGE: $0 classname [opts]"
|
20
|
+
exit 1
|
21
|
+
fi
|
22
|
+
|
23
|
+
if [-z "$SCALA_VERSION" ]; then
|
24
|
+
SCALA_VERSION=2.8.0
|
25
|
+
fi
|
26
|
+
|
27
|
+
# assume all dependencies have been packaged into one jar with sbt-assembly's task "assembly-package-dependency"
|
28
|
+
for file in $KAFKA_PATH/core/target/scala-$SCALA_VERSION/*.jar;
|
29
|
+
do
|
30
|
+
CLASSPATH=$CLASSPATH:$file
|
31
|
+
done
|
32
|
+
|
33
|
+
for file in $KAFKA_PATH/perf/target/scala-$SCALA_VERSION/kafka*.jar;
|
34
|
+
do
|
35
|
+
CLASSPATH=$CLASSPATH:$file
|
36
|
+
done
|
37
|
+
|
38
|
+
# classpath addition for release
|
39
|
+
for file in $KAFKA_PATH/libs/*.jar;
|
40
|
+
do
|
41
|
+
CLASSPATH=$CLASSPATH:$file
|
42
|
+
done
|
43
|
+
|
44
|
+
for file in $KAFKA_PATH/kafka*.jar;
|
45
|
+
do
|
46
|
+
CLASSPATH=$CLASSPATH:$file
|
47
|
+
done
|
48
|
+
|
49
|
+
if [ -z "$KAFKA_JMX_OPTS" ]; then
|
50
|
+
KAFKA_JMX_OPTS="-Dcom.sun.management.jmxremote -Dcom.sun.management.jmxremote.authenticate=false -Dcom.sun.management.jmxremote.ssl=false "
|
51
|
+
fi
|
52
|
+
|
53
|
+
if [ -z "$KAFKA_OPTS" ]; then
|
54
|
+
KAFKA_OPTS="-Xmx512M -server -Dlog4j.configuration=file:$KAFKA_PATH/config/log4j.properties"
|
55
|
+
fi
|
56
|
+
|
57
|
+
if [ $JMX_PORT ]; then
|
58
|
+
KAFKA_JMX_OPTS="$KAFKA_JMX_OPTS -Dcom.sun.management.jmxremote.port=$JMX_PORT "
|
59
|
+
fi
|
60
|
+
|
61
|
+
if [ -z "$JAVA_HOME" ]; then
|
62
|
+
JAVA="java"
|
63
|
+
else
|
64
|
+
JAVA="$JAVA_HOME/bin/java"
|
65
|
+
fi
|
66
|
+
|
67
|
+
exec $JAVA $KAFKA_OPTS $KAFKA_JMX_OPTS -cp $CLASSPATH "$@"
|
@@ -0,0 +1,33 @@
|
|
1
|
+
ROOT_DIRECTORY = File.absolute_path(File.dirname(__FILE__) + "/../")
|
2
|
+
|
3
|
+
require "test_cluster"
|
4
|
+
require "spec_helper"
|
5
|
+
|
6
|
+
unless File.directory?(File.join(ROOT_DIRECTORY, "kafka_2.8.0-0.8.1"))
|
7
|
+
puts "\033[0;32m"
|
8
|
+
puts "*" * 83
|
9
|
+
puts "Downloading kafka"
|
10
|
+
puts "*" * 83
|
11
|
+
puts "\033[0;0m"
|
12
|
+
|
13
|
+
system(
|
14
|
+
"cd #{ROOT_DIRECTORY} && curl https://archive.apache.org/dist/kafka/0.8.1/kafka_2.8.0-0.8.1.tgz | tar xz"
|
15
|
+
)
|
16
|
+
end
|
17
|
+
|
18
|
+
ENV["KAFKA_PATH"] = File.join(ROOT_DIRECTORY, "kafka_2.8.0-0.8.1")
|
19
|
+
ENV["SCALA_VERSION"] = "2.8.0"
|
20
|
+
|
21
|
+
RSpec.configure do |config|
|
22
|
+
config.before(:suite) do
|
23
|
+
JavaRunner.remove_tmp
|
24
|
+
JavaRunner.set_kafka_path!
|
25
|
+
$tc = TestCluster.new
|
26
|
+
$tc.start
|
27
|
+
sleep 5
|
28
|
+
end
|
29
|
+
|
30
|
+
config.after(:suite) do
|
31
|
+
$tc.stop
|
32
|
+
end
|
33
|
+
end
|
@@ -0,0 +1,21 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
|
3
|
+
describe Emque::Producing::Configuration do
|
4
|
+
subject { Emque::Producing::Configuration.new }
|
5
|
+
|
6
|
+
it "provides default values" do
|
7
|
+
expect(subject.app_name).to eq ""
|
8
|
+
expect(subject.error_handlers).to eq []
|
9
|
+
expect(subject.kafka_options[:seed_brokers]).to eq ["localhost:9092"]
|
10
|
+
end
|
11
|
+
|
12
|
+
it "allows app_name to be overwritten" do
|
13
|
+
subject.app_name = "my app"
|
14
|
+
expect(subject.app_name).to eq "my app"
|
15
|
+
end
|
16
|
+
|
17
|
+
it "allows seed_brokers to be overwritten" do
|
18
|
+
subject.kafka_options[:seed_brokers] = ["kafka1:9092", "kafka2:9092"]
|
19
|
+
expect(subject.kafka_options[:seed_brokers]).to eq ["kafka1:9092", "kafka2:9092"]
|
20
|
+
end
|
21
|
+
end
|
@@ -0,0 +1,88 @@
|
|
1
|
+
require "spec_helper"
|
2
|
+
require "virtus"
|
3
|
+
require "emque/producing/message/message"
|
4
|
+
|
5
|
+
class TestMessage
|
6
|
+
include Emque::Producing::Message
|
7
|
+
|
8
|
+
topic "queue"
|
9
|
+
message_type "queue.new"
|
10
|
+
|
11
|
+
attribute :test_id, Integer, :required => true
|
12
|
+
private_attribute :extra, String, :default => "value"
|
13
|
+
end
|
14
|
+
|
15
|
+
class MessageNoTopic
|
16
|
+
include Emque::Producing::Message
|
17
|
+
message_type "testing"
|
18
|
+
end
|
19
|
+
|
20
|
+
class MessageNoType
|
21
|
+
include Emque::Producing::Message
|
22
|
+
topic "testing"
|
23
|
+
end
|
24
|
+
|
25
|
+
describe Emque::Producing::Message do
|
26
|
+
before do
|
27
|
+
Emque::Producing.configure do |c|
|
28
|
+
c.app_name = "apiv3"
|
29
|
+
end
|
30
|
+
end
|
31
|
+
|
32
|
+
describe "#to_json" do
|
33
|
+
it "creates the metadata" do
|
34
|
+
message = TestMessage.new(:test_id => 1)
|
35
|
+
metadata = message.add_metadata[:metadata]
|
36
|
+
expect(metadata[:app]).to eql("apiv3")
|
37
|
+
end
|
38
|
+
|
39
|
+
it "can be transformed to json" do
|
40
|
+
message = Oj.load(TestMessage.new().to_json)
|
41
|
+
expect(message["metadata"]["app"]).to eql("apiv3")
|
42
|
+
end
|
43
|
+
|
44
|
+
it "includes valid attributes in json" do
|
45
|
+
produced_message = TestMessage.new(:test_id => 1)
|
46
|
+
json = produced_message.to_json
|
47
|
+
consumed_message = Oj.load(json)
|
48
|
+
expect(consumed_message["test_id"]).to eql(1)
|
49
|
+
end
|
50
|
+
end
|
51
|
+
|
52
|
+
describe "#retry" do
|
53
|
+
pending
|
54
|
+
end
|
55
|
+
|
56
|
+
it "validates the message for missing attributes" do
|
57
|
+
message = TestMessage.new()
|
58
|
+
expect(message).to_not be_valid
|
59
|
+
end
|
60
|
+
|
61
|
+
it "raises a useful message when trying to send an invalid message" do
|
62
|
+
message = TestMessage.new()
|
63
|
+
expected_error = Emque::Producing::Message::InvalidMessageError
|
64
|
+
expect{message.publish(->{})}.to raise_error(expected_error)
|
65
|
+
end
|
66
|
+
|
67
|
+
it "validates that the message has a topic" do
|
68
|
+
message = MessageNoTopic.new
|
69
|
+
expected_error = Emque::Producing::Message::InvalidMessageError
|
70
|
+
expect{message.publish(->{})}.to raise_error(expected_error, "A topic is required")
|
71
|
+
end
|
72
|
+
|
73
|
+
it "validates that the message has a message type" do
|
74
|
+
message = MessageNoType.new
|
75
|
+
expected_error = Emque::Producing::Message::InvalidMessageError
|
76
|
+
expect{message.publish(->{})}.to raise_error(expected_error, "A message type is required")
|
77
|
+
end
|
78
|
+
|
79
|
+
it "applys a uuid per message" do
|
80
|
+
message = TestMessage.new()
|
81
|
+
expect(message.add_metadata[:metadata][:uuid]).to_not be_nil
|
82
|
+
end
|
83
|
+
|
84
|
+
it "has the sub type in the metadata" do
|
85
|
+
message = TestMessage.new()
|
86
|
+
expect(message.add_metadata[:metadata][:type]).to eql("queue.new")
|
87
|
+
end
|
88
|
+
end
|
@@ -0,0 +1,20 @@
|
|
1
|
+
require "spec_helper"
|
2
|
+
require "emque/producing/publisher/kafka"
|
3
|
+
|
4
|
+
describe Emque::Producing::Publisher do
|
5
|
+
describe "#publish" do
|
6
|
+
context "when error handler raises an exception" do
|
7
|
+
it "handles the exception" do
|
8
|
+
expect_any_instance_of(Poseidon::Producer). to receive(:send_messages).and_raise
|
9
|
+
Emque::Producing.configure do |c|
|
10
|
+
c.error_handlers << Proc.new {|ex,context|
|
11
|
+
raise "something"
|
12
|
+
}
|
13
|
+
end
|
14
|
+
Emque::Producing.logger = nil
|
15
|
+
publisher = Emque::Producing::Publisher::Kafka.new
|
16
|
+
publisher.publish("mytopic", "message.type", "mymessage")
|
17
|
+
end
|
18
|
+
end
|
19
|
+
end
|
20
|
+
end
|
data/spec/spec_helper.rb
ADDED
@@ -0,0 +1,22 @@
|
|
1
|
+
$TESTING = true
|
2
|
+
|
3
|
+
require "pry"
|
4
|
+
require "emque-producing"
|
5
|
+
|
6
|
+
ENV["EMQUE_ENV"] = "test"
|
7
|
+
|
8
|
+
module VerifyAndResetHelpers
|
9
|
+
def verify(object)
|
10
|
+
RSpec::Mocks.proxy_for(object).verify
|
11
|
+
end
|
12
|
+
|
13
|
+
def reset(object)
|
14
|
+
RSpec::Mocks.proxy_for(object).reset
|
15
|
+
end
|
16
|
+
end
|
17
|
+
|
18
|
+
RSpec.configure do |config|
|
19
|
+
config.order = "random"
|
20
|
+
|
21
|
+
config.include VerifyAndResetHelpers
|
22
|
+
end
|
@@ -0,0 +1,201 @@
|
|
1
|
+
# from https://github.com/bpot/poseidon
|
2
|
+
|
3
|
+
require 'daemon_controller'
|
4
|
+
|
5
|
+
class TestCluster
|
6
|
+
attr_reader :broker, :zookeeper
|
7
|
+
def initialize
|
8
|
+
@zookeeper = ZookeeperRunner.new
|
9
|
+
@broker = BrokerRunner.new(0, 9092)
|
10
|
+
end
|
11
|
+
|
12
|
+
def start
|
13
|
+
@zookeeper.start
|
14
|
+
@broker.start
|
15
|
+
end
|
16
|
+
|
17
|
+
def stop
|
18
|
+
@zookeeper.stop
|
19
|
+
@broker.stop
|
20
|
+
end
|
21
|
+
end
|
22
|
+
|
23
|
+
class JavaRunner
|
24
|
+
def self.remove_tmp
|
25
|
+
FileUtils.rm_rf("#{ROOT_DIRECTORY}/tmp")
|
26
|
+
end
|
27
|
+
|
28
|
+
def self.set_kafka_path!
|
29
|
+
JavaRunner.kafka_path = File.join(ROOT_DIRECTORY, "kafka-0.8.0-src")
|
30
|
+
end
|
31
|
+
|
32
|
+
def self.kafka_path=(kafka_path)
|
33
|
+
@kafka_path = kafka_path
|
34
|
+
end
|
35
|
+
|
36
|
+
def self.kafka_path
|
37
|
+
@kafka_path
|
38
|
+
end
|
39
|
+
|
40
|
+
attr_reader :pid
|
41
|
+
def initialize(id, start_cmd, port, properties = {})
|
42
|
+
@id = id
|
43
|
+
@properties = properties
|
44
|
+
@pid = nil
|
45
|
+
@start_cmd = start_cmd
|
46
|
+
@port = port
|
47
|
+
end
|
48
|
+
|
49
|
+
def start
|
50
|
+
write_properties
|
51
|
+
run
|
52
|
+
end
|
53
|
+
|
54
|
+
def stop
|
55
|
+
daemon_controller.stop
|
56
|
+
end
|
57
|
+
|
58
|
+
def without_process
|
59
|
+
stop
|
60
|
+
begin
|
61
|
+
yield
|
62
|
+
ensure
|
63
|
+
start
|
64
|
+
sleep 5
|
65
|
+
end
|
66
|
+
end
|
67
|
+
|
68
|
+
private
|
69
|
+
|
70
|
+
def daemon_controller
|
71
|
+
@dc ||= DaemonController.new(
|
72
|
+
:identifier => @id,
|
73
|
+
:start_command => "#{@start_cmd} #{config_path} >>#{log_path} 2>&1 & echo $! > #{pid_path}",
|
74
|
+
:ping_command => [:tcp, '127.0.0.1', @port],
|
75
|
+
:pid_file => pid_path,
|
76
|
+
:log_file => log_path,
|
77
|
+
:start_timeout => 25
|
78
|
+
)
|
79
|
+
end
|
80
|
+
|
81
|
+
def run
|
82
|
+
FileUtils.mkdir_p(log_dir)
|
83
|
+
FileUtils.mkdir_p(pid_dir)
|
84
|
+
daemon_controller.start
|
85
|
+
end
|
86
|
+
|
87
|
+
def write_properties
|
88
|
+
FileUtils.mkdir_p(config_dir)
|
89
|
+
File.open(config_path, "w+") do |f|
|
90
|
+
@properties.each do |k,v|
|
91
|
+
f.puts "#{k}=#{v}"
|
92
|
+
end
|
93
|
+
end
|
94
|
+
end
|
95
|
+
|
96
|
+
def pid_path
|
97
|
+
"#{pid_dir}/#{@id}.pid"
|
98
|
+
end
|
99
|
+
|
100
|
+
def pid_dir
|
101
|
+
"#{file_path}/pid"
|
102
|
+
end
|
103
|
+
|
104
|
+
def log_path
|
105
|
+
"#{log_dir}/#{@id}.log"
|
106
|
+
end
|
107
|
+
|
108
|
+
def log_dir
|
109
|
+
"#{file_path}/log"
|
110
|
+
end
|
111
|
+
|
112
|
+
def config_path
|
113
|
+
"#{config_dir}/#{@id}.properties"
|
114
|
+
end
|
115
|
+
|
116
|
+
def config_dir
|
117
|
+
"#{file_path}/config"
|
118
|
+
end
|
119
|
+
|
120
|
+
def file_path
|
121
|
+
ROOT_DIRECTORY + "/tmp/"
|
122
|
+
end
|
123
|
+
end
|
124
|
+
|
125
|
+
class BrokerRunner
|
126
|
+
DEFAULT_PROPERTIES = {
|
127
|
+
"broker.id" => 0,
|
128
|
+
"port" => 9092,
|
129
|
+
"num.network.threads" => 2,
|
130
|
+
"num.io.threads" => 2,
|
131
|
+
"socket.send.buffer.bytes" => 1048576,
|
132
|
+
"socket.receive.buffer.bytes" => 1048576,
|
133
|
+
"socket.request.max.bytes" => 104857600,
|
134
|
+
"log.dir" => "#{ROOT_DIRECTORY}/tmp/kafka-logs",
|
135
|
+
"num.partitions" => 1,
|
136
|
+
"log.flush.interval.messages" => 10000,
|
137
|
+
"log.flush.interval.ms" => 1000,
|
138
|
+
"log.retention.hours" => 168,
|
139
|
+
"log.segment.bytes" => 536870912,
|
140
|
+
"log.cleanup.interval.mins" => 1,
|
141
|
+
"zookeeper.connect" => "localhost:2181",
|
142
|
+
"zookeeper.connection.timeout.ms" => 1000000,
|
143
|
+
"kafka.metrics.polling.interval.secs" => 5,
|
144
|
+
"kafka.metrics.reporters" => "kafka.metrics.KafkaCSVMetricsReporter",
|
145
|
+
"kafka.csv.metrics.dir" => "#{ROOT_DIRECTORY}/tmp/kafka_metrics",
|
146
|
+
"kafka.csv.metrics.reporter.enabled" => "false",
|
147
|
+
}
|
148
|
+
|
149
|
+
def initialize(id, port, partition_count = 1)
|
150
|
+
@id = id
|
151
|
+
@port = port
|
152
|
+
@jr = JavaRunner.new("broker_#{id}",
|
153
|
+
"#{ROOT_DIRECTORY}/spec/bin/kafka-run-class.sh kafka.Kafka",
|
154
|
+
port,
|
155
|
+
DEFAULT_PROPERTIES.merge(
|
156
|
+
"broker.id" => id,
|
157
|
+
"port" => port,
|
158
|
+
"log.dir" => "#{ROOT_DIRECTORY}/tmp/kafka-logs_#{id}",
|
159
|
+
"num.partitions" => partition_count
|
160
|
+
))
|
161
|
+
end
|
162
|
+
|
163
|
+
def pid
|
164
|
+
@jr.pid
|
165
|
+
end
|
166
|
+
|
167
|
+
def start
|
168
|
+
@jr.start
|
169
|
+
end
|
170
|
+
|
171
|
+
def stop
|
172
|
+
@jr.stop
|
173
|
+
end
|
174
|
+
|
175
|
+
def without_process
|
176
|
+
@jr.without_process { yield }
|
177
|
+
end
|
178
|
+
end
|
179
|
+
|
180
|
+
class ZookeeperRunner
|
181
|
+
def initialize
|
182
|
+
@jr = JavaRunner.new("zookeeper",
|
183
|
+
"#{ROOT_DIRECTORY}/spec/bin/kafka-run-class.sh org.apache.zookeeper.server.quorum.QuorumPeerMain",
|
184
|
+
2181,
|
185
|
+
:dataDir => "#{ROOT_DIRECTORY}/tmp/zookeeper",
|
186
|
+
:clientPort => 2181,
|
187
|
+
:maxClientCnxns => 0)
|
188
|
+
end
|
189
|
+
|
190
|
+
def pid
|
191
|
+
@jr.pid
|
192
|
+
end
|
193
|
+
|
194
|
+
def start
|
195
|
+
@jr.start
|
196
|
+
end
|
197
|
+
|
198
|
+
def stop
|
199
|
+
@jr.stop
|
200
|
+
end
|
201
|
+
end
|
metadata
ADDED
@@ -0,0 +1,191 @@
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
2
|
+
name: emque-producing
|
3
|
+
version: !ruby/object:Gem::Version
|
4
|
+
version: 0.0.2
|
5
|
+
platform: ruby
|
6
|
+
authors:
|
7
|
+
- Emily Dobervich
|
8
|
+
- Ryan Williams
|
9
|
+
autorequire:
|
10
|
+
bindir: bin
|
11
|
+
cert_chain: []
|
12
|
+
date: 2015-02-06 00:00:00.000000000 Z
|
13
|
+
dependencies:
|
14
|
+
- !ruby/object:Gem::Dependency
|
15
|
+
name: oj
|
16
|
+
requirement: !ruby/object:Gem::Requirement
|
17
|
+
requirements:
|
18
|
+
- - "~>"
|
19
|
+
- !ruby/object:Gem::Version
|
20
|
+
version: 2.10.2
|
21
|
+
type: :runtime
|
22
|
+
prerelease: false
|
23
|
+
version_requirements: !ruby/object:Gem::Requirement
|
24
|
+
requirements:
|
25
|
+
- - "~>"
|
26
|
+
- !ruby/object:Gem::Version
|
27
|
+
version: 2.10.2
|
28
|
+
- !ruby/object:Gem::Dependency
|
29
|
+
name: virtus
|
30
|
+
requirement: !ruby/object:Gem::Requirement
|
31
|
+
requirements:
|
32
|
+
- - "~>"
|
33
|
+
- !ruby/object:Gem::Version
|
34
|
+
version: 1.0.3
|
35
|
+
type: :runtime
|
36
|
+
prerelease: false
|
37
|
+
version_requirements: !ruby/object:Gem::Requirement
|
38
|
+
requirements:
|
39
|
+
- - "~>"
|
40
|
+
- !ruby/object:Gem::Version
|
41
|
+
version: 1.0.3
|
42
|
+
- !ruby/object:Gem::Dependency
|
43
|
+
name: bundler
|
44
|
+
requirement: !ruby/object:Gem::Requirement
|
45
|
+
requirements:
|
46
|
+
- - "~>"
|
47
|
+
- !ruby/object:Gem::Version
|
48
|
+
version: '1.0'
|
49
|
+
type: :development
|
50
|
+
prerelease: false
|
51
|
+
version_requirements: !ruby/object:Gem::Requirement
|
52
|
+
requirements:
|
53
|
+
- - "~>"
|
54
|
+
- !ruby/object:Gem::Version
|
55
|
+
version: '1.0'
|
56
|
+
- !ruby/object:Gem::Dependency
|
57
|
+
name: rake
|
58
|
+
requirement: !ruby/object:Gem::Requirement
|
59
|
+
requirements:
|
60
|
+
- - ">="
|
61
|
+
- !ruby/object:Gem::Version
|
62
|
+
version: '0'
|
63
|
+
type: :development
|
64
|
+
prerelease: false
|
65
|
+
version_requirements: !ruby/object:Gem::Requirement
|
66
|
+
requirements:
|
67
|
+
- - ">="
|
68
|
+
- !ruby/object:Gem::Version
|
69
|
+
version: '0'
|
70
|
+
- !ruby/object:Gem::Dependency
|
71
|
+
name: rspec
|
72
|
+
requirement: !ruby/object:Gem::Requirement
|
73
|
+
requirements:
|
74
|
+
- - "~>"
|
75
|
+
- !ruby/object:Gem::Version
|
76
|
+
version: '3.1'
|
77
|
+
type: :development
|
78
|
+
prerelease: false
|
79
|
+
version_requirements: !ruby/object:Gem::Requirement
|
80
|
+
requirements:
|
81
|
+
- - "~>"
|
82
|
+
- !ruby/object:Gem::Version
|
83
|
+
version: '3.1'
|
84
|
+
- !ruby/object:Gem::Dependency
|
85
|
+
name: pry
|
86
|
+
requirement: !ruby/object:Gem::Requirement
|
87
|
+
requirements:
|
88
|
+
- - ">="
|
89
|
+
- !ruby/object:Gem::Version
|
90
|
+
version: '0'
|
91
|
+
type: :development
|
92
|
+
prerelease: false
|
93
|
+
version_requirements: !ruby/object:Gem::Requirement
|
94
|
+
requirements:
|
95
|
+
- - ">="
|
96
|
+
- !ruby/object:Gem::Version
|
97
|
+
version: '0'
|
98
|
+
- !ruby/object:Gem::Dependency
|
99
|
+
name: poseidon
|
100
|
+
requirement: !ruby/object:Gem::Requirement
|
101
|
+
requirements:
|
102
|
+
- - '='
|
103
|
+
- !ruby/object:Gem::Version
|
104
|
+
version: 0.0.4
|
105
|
+
type: :development
|
106
|
+
prerelease: false
|
107
|
+
version_requirements: !ruby/object:Gem::Requirement
|
108
|
+
requirements:
|
109
|
+
- - '='
|
110
|
+
- !ruby/object:Gem::Version
|
111
|
+
version: 0.0.4
|
112
|
+
- !ruby/object:Gem::Dependency
|
113
|
+
name: bunny
|
114
|
+
requirement: !ruby/object:Gem::Requirement
|
115
|
+
requirements:
|
116
|
+
- - "~>"
|
117
|
+
- !ruby/object:Gem::Version
|
118
|
+
version: 1.4.1
|
119
|
+
type: :development
|
120
|
+
prerelease: false
|
121
|
+
version_requirements: !ruby/object:Gem::Requirement
|
122
|
+
requirements:
|
123
|
+
- - "~>"
|
124
|
+
- !ruby/object:Gem::Version
|
125
|
+
version: 1.4.1
|
126
|
+
description: Define and send messages to a variety of message brokers
|
127
|
+
email:
|
128
|
+
- emily@teamsnap.com
|
129
|
+
- ryan.williams@teamsnap.com
|
130
|
+
executables: []
|
131
|
+
extensions: []
|
132
|
+
extra_rdoc_files: []
|
133
|
+
files:
|
134
|
+
- ".gitignore"
|
135
|
+
- Gemfile
|
136
|
+
- Gemfile.lock
|
137
|
+
- LICENSE.txt
|
138
|
+
- README.md
|
139
|
+
- Rakefile
|
140
|
+
- emque-producing.gemspec
|
141
|
+
- lib/emque-producing.rb
|
142
|
+
- lib/emque/producing.rb
|
143
|
+
- lib/emque/producing/configuration.rb
|
144
|
+
- lib/emque/producing/logging.rb
|
145
|
+
- lib/emque/producing/message/message.rb
|
146
|
+
- lib/emque/producing/producing.rb
|
147
|
+
- lib/emque/producing/publisher/base.rb
|
148
|
+
- lib/emque/producing/publisher/kafka.rb
|
149
|
+
- lib/emque/producing/publisher/rabbitmq.rb
|
150
|
+
- lib/emque/producing/version.rb
|
151
|
+
- spec/bin/kafka-run-class.sh
|
152
|
+
- spec/kafka_spec_helper.rb
|
153
|
+
- spec/producing/configuration_spec.rb
|
154
|
+
- spec/producing/message/message_spec.rb
|
155
|
+
- spec/producing/producing_spec.rb
|
156
|
+
- spec/producing/publisher_spec.rb
|
157
|
+
- spec/spec_helper.rb
|
158
|
+
- spec/test_cluster.rb
|
159
|
+
homepage: ''
|
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: 1.9.3
|
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.2.2
|
180
|
+
signing_key:
|
181
|
+
specification_version: 4
|
182
|
+
summary: Define and send messages to a variety of message brokers
|
183
|
+
test_files:
|
184
|
+
- spec/bin/kafka-run-class.sh
|
185
|
+
- spec/kafka_spec_helper.rb
|
186
|
+
- spec/producing/configuration_spec.rb
|
187
|
+
- spec/producing/message/message_spec.rb
|
188
|
+
- spec/producing/producing_spec.rb
|
189
|
+
- spec/producing/publisher_spec.rb
|
190
|
+
- spec/spec_helper.rb
|
191
|
+
- spec/test_cluster.rb
|