stapfen 2.1.1 → 2.2.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 CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: 19bdf4344cf49d95cee8597de1902b9a814a1b90
4
- data.tar.gz: 06ad77a4f72ea1cce8269e92a19ce2cf6872474b
3
+ metadata.gz: 01629a450316fa2089bd559e2ec2df8bb3b79fe7
4
+ data.tar.gz: 84ad17b10f341ca81c599e5aadd7d13fce04cb42
5
5
  SHA512:
6
- metadata.gz: 09b0dfd450a6e4387250b0d0c4b49734891ea5f07db900b7cdb33412b731352b5cd0a192663b898e383030c2938710f29238716b0b793d181adbed35157155aa
7
- data.tar.gz: 79104895c26a380204fe1cddbe0304e255e87d522ada0c1c38fe7dad16457b10d9bec4bdb82cd44b55f21bd21ecc09cba1ec8b8abc2287cf2a23663f23ed10b3
6
+ metadata.gz: 24f9f0557fa24b518b7b957010c4de14db38c04ad4dd81d7f900ece3e783e577f37d2f8fe3226e9896f2409ed1cb92e7e760b078344308d887049e8cef64a890
7
+ data.tar.gz: 82ecce67fb2b23c3cb73d47a356de210ef5ebc6f72a03a3fa1108cc1e87e95e47826000965a8c96884fcb5ff2e6db6777acea7dc5dbebf6507a423e40e7dc14a
data/.gitignore CHANGED
@@ -16,3 +16,4 @@ test/tmp
16
16
  test/version_tmp
17
17
  tmp
18
18
  .rvmrc
19
+ activemq-all-5.8.0.jar
data/Gemfile CHANGED
@@ -8,7 +8,8 @@ gem 'stomp', '>= 1.2.14'
8
8
 
9
9
  group :development do
10
10
  gem 'rake'
11
- gem 'rspec', '~> 2.11'
11
+ gem 'rspec'
12
+ gem 'rspec-its'
12
13
  gem 'pry'
13
14
  gem 'debugger', :platform => :mri
14
15
  gem 'debugger-pry', :platform => :mri
data/README.md CHANGED
@@ -77,8 +77,8 @@ care when accessing other shared resources.
77
77
 
78
78
  The consume block accepts the usual subscriptions headers, as well as two
79
79
  additional headers `:dead_letter_queue` and `:max_redeliveries`. If either of
80
- the latter two is present, the honsumer will unreceive any messages for which
81
- the block returns `false`; after `:max\_redeliveries`, it will send the message
80
+ the latter two is present, the consumer will unreceive any messages for which
81
+ the block returns `false`; after `:max_redeliveries`, it will send the message
82
82
  to `:dead_letter_queue`. `consume` blocks without these headers will fail
83
83
  silently rather than unreceive.
84
84
 
@@ -97,3 +97,10 @@ Or install it yourself as:
97
97
 
98
98
  $ gem install stapfen
99
99
 
100
+ ## Running Specs
101
+
102
+ Download this from jar from Maven Central
103
+ * [activemq-all-5.8.0.jar](http://search.maven.org/#artifactdetails%7Corg.apache.activemq%7Cactivemq-all%7C5.8.0%7Cjar)
104
+ * Put it in gem root
105
+ * ```rake spec```
106
+
@@ -0,0 +1,76 @@
1
+ begin
2
+ require 'hermann'
3
+ require 'hermann/consumer'
4
+ rescue LoadError => e
5
+ if RUBY_PLATFORM == 'java'
6
+ raise
7
+ end
8
+ end
9
+
10
+ require 'stapfen/destination'
11
+
12
+ module Stapfen
13
+ module Client
14
+ class Kafka
15
+ attr_reader :connection, :producer
16
+
17
+ # Initialize a Kafka client object
18
+ #
19
+ # @params [Hash] configuration object
20
+ # @option configuration [String] :topic The kafka topic
21
+ # @option configuration [String] :groupId The kafka groupId
22
+ # @option configuration [String] :zookeepers List of zookeepers
23
+ #
24
+ # @raises [ConfigurationError] if required configs are not present
25
+ def initialize(configuration)
26
+ super()
27
+ @config = configuration
28
+ @topic = @config[:topic]
29
+ @groupId = @config[:groupId]
30
+ @zookeepers = @config[:zookeepers]
31
+ raise ConfigurationError unless @topic && @groupId && @zookeepers
32
+ @connection = Hermann::Consumer.new(@topic, @groupId, @zookeepers)
33
+ end
34
+
35
+ # This method is not implemenented
36
+ def connect(*args)
37
+ # No-op
38
+ end
39
+
40
+ # Cannot unreceive
41
+ def can_unreceive?
42
+ false
43
+ end
44
+
45
+ # Closes the consumer threads created by kafka.
46
+ #
47
+ # @return [Boolean] True/false depending on whether we actually closed
48
+ # the connection
49
+ def close
50
+ return false unless @connection
51
+ @connection.shutdown
52
+ @connection = nil
53
+ return true
54
+ end
55
+
56
+ # Subscribes to a destination (i.e. kafka topic) and consumes messages
57
+ #
58
+ # @params [Destination] source of messages to consume
59
+ #
60
+ # @params [Hash] Not used
61
+ #
62
+ # @params [block] block to yield consumed messages
63
+ def subscribe(destination, headers={}, &block)
64
+ destination = Stapfen::Destination.from_string(destination)
65
+ connection.consume(destination.as_kafka, &block)
66
+ end
67
+
68
+ def runloop
69
+ loop do
70
+ sleep 1
71
+ end
72
+ end
73
+
74
+ end
75
+ end
76
+ end
@@ -40,6 +40,10 @@ module Stapfen
40
40
  end
41
41
  end
42
42
 
43
+ def as_kafka
44
+ return name
45
+ end
46
+
43
47
  # Create a {Stapfen::Destination} from the given string
44
48
  #
45
49
  # @param [String] name
@@ -1,14 +1,13 @@
1
-
2
1
  module Stapfen
3
2
  class Message
4
3
  attr_reader :message_id, :body, :original, :destination
5
4
 
6
5
  def initialize(opts={})
7
6
  super()
8
- @body = opts[:body]
7
+ @body = opts[:body]
9
8
  @destination = opts[:destination]
10
- @message_id = opts[:message_id]
11
- @original = opts[:original]
9
+ @message_id = opts[:message_id]
10
+ @original = opts[:original]
12
11
  end
13
12
 
14
13
  # Create an instance of {Stapfen::Message} from the passed in
@@ -42,5 +41,18 @@ module Stapfen
42
41
  :message_id => message.jms_message_id,
43
42
  :original => message)
44
43
  end
44
+
45
+ # Create an instance of {Stapfen::Message} from the passed in
46
+ # +String+ which a Kafka consumer should receive
47
+ #
48
+ # @param [String] message
49
+ # @return [Stapfen::Message] A Stapfen wrapper object
50
+ def self.from_kafka(message)
51
+ unless message.kind_of? String
52
+ raise Stapfen::InvalidMessageError, message.inspect
53
+ end
54
+
55
+ return self.new(:body => message)
56
+ end
45
57
  end
46
58
  end
@@ -1,3 +1,3 @@
1
1
  module Stapfen
2
- VERSION = '2.1.1'
2
+ VERSION = '2.2.0'
3
3
  end
@@ -47,12 +47,12 @@ module Stapfen
47
47
  raise
48
48
  end
49
49
 
50
- @use_stomp = true
50
+ @protocol = 'stomp'
51
51
  return true
52
52
  end
53
53
 
54
54
  def self.stomp?
55
- @use_stomp.nil? || @use_stomp
55
+ @protocol.nil? || @protocol == 'stomp'
56
56
  end
57
57
 
58
58
  # Force the worker to use JMS as the messaging protocol.
@@ -73,12 +73,38 @@ module Stapfen
73
73
  raise
74
74
  end
75
75
 
76
- @use_stomp = false
76
+ @protocol = 'jms'
77
77
  return true
78
78
  end
79
79
 
80
80
  def self.jms?
81
- !(stomp?)
81
+ @protocol == 'jms'
82
+ end
83
+
84
+ # Force the worker to use Kafka as the messaging protocol.
85
+ #
86
+ # *Note:* Only works under JRuby
87
+ #
88
+ # @return [Boolean]
89
+ def self.use_kafka!
90
+ unless RUBY_PLATFORM == 'java'
91
+ raise Stapfen::ConfigurationError, "You cannot use Kafka unless you're running under JRuby!"
92
+ end
93
+
94
+ begin
95
+ require 'java'
96
+ require 'hermann'
97
+ rescue LoadError
98
+ puts "You need the `hermann` gem to be installed to use Kafka!"
99
+ raise
100
+ end
101
+
102
+ @protocol = 'kafka'
103
+ return true
104
+ end
105
+
106
+ def self.kafka?
107
+ @protocol == 'kafka'
82
108
  end
83
109
 
84
110
  # Optional method, should be passed a block which will yield a {{Logger}}
@@ -164,6 +190,9 @@ module Stapfen
164
190
  elsif self.class.jms?
165
191
  require 'stapfen/client/jms'
166
192
  @client = Stapfen::Client::JMS.new(self.class.configuration.call)
193
+ elsif self.class.kafka?
194
+ require 'stapfen/client/kafka'
195
+ @client = Stapfen::Client::Kafka.new(self.class.configuration.call)
167
196
  end
168
197
 
169
198
  debug("Running with #{@client} inside of Thread:#{Thread.current.inspect}")
@@ -192,6 +221,10 @@ module Stapfen
192
221
  message = Stapfen::Message.from_jms(m)
193
222
  end
194
223
 
224
+ if self.class.kafka?
225
+ message = Stapfen::Message.from_kafka(m)
226
+ end
227
+
195
228
  success = self.send(method_name, message)
196
229
 
197
230
  unless success
data/lib/stapfen.rb CHANGED
@@ -11,7 +11,6 @@ rescue LoadError
11
11
  # Can't process JMS
12
12
  end
13
13
 
14
-
15
14
  require 'stapfen/version'
16
15
  require 'stapfen/client'
17
16
  require 'stapfen/worker'
@@ -12,7 +12,7 @@ if RUBY_PLATFORM == 'java'
12
12
  describe '#can_unreceive?' do
13
13
  subject { client.can_unreceive? }
14
14
 
15
- it { should be_true }
15
+ it { should be true }
16
16
  end
17
17
 
18
18
  describe '#unreceive' do
@@ -158,11 +158,11 @@ if RUBY_PLATFORM == 'java'
158
158
  client.stub(:connection).and_return(double('JMS::Connection'))
159
159
  end
160
160
 
161
- it { should be_false }
161
+ it { should be false }
162
162
  end
163
163
 
164
164
  context 'without a connection' do
165
- it { should be_true }
165
+ it { should be true }
166
166
  end
167
167
  end
168
168
 
@@ -177,7 +177,7 @@ if RUBY_PLATFORM == 'java'
177
177
  context 'without an existing session' do
178
178
  it 'should close the client' do
179
179
  connection.should_receive(:close)
180
- expect(result).to be_true
180
+ expect(result).to be true
181
181
  end
182
182
  end
183
183
 
@@ -191,7 +191,7 @@ if RUBY_PLATFORM == 'java'
191
191
  it 'should close the client and session' do
192
192
  session.should_receive(:close)
193
193
  connection.should_receive(:close)
194
- expect(result).to be_true
194
+ expect(result).to be true
195
195
  end
196
196
  end
197
197
  end
@@ -0,0 +1,54 @@
1
+ require 'spec_helper'
2
+
3
+ require 'stapfen/client/kafka'
4
+
5
+ describe Stapfen::Client::Kafka, :java => true do
6
+ let(:config) { { :topic => 'test', :groupId => 'groupId', :zookeepers => 'foo' } }
7
+ let(:consumer) { double('Hermann::Consumer') }
8
+
9
+ subject(:client) { described_class.new(config) }
10
+
11
+ before do
12
+ allow(Hermann::Consumer).to receive(:new) { consumer }
13
+ end
14
+
15
+ it { should respond_to :connect }
16
+
17
+ describe '#can_unreceive?' do
18
+ subject { client.can_unreceive? }
19
+ it { should be false }
20
+ end
21
+
22
+ describe '#close' do
23
+ subject(:result) { client.close }
24
+
25
+ context 'with a connection' do
26
+ it 'should close the client' do
27
+ allow(consumer).to receive(:shutdown)
28
+ expect(result).to be true
29
+ end
30
+ end
31
+ context 'without a connection' do
32
+ it 'returns false' do
33
+ expect(Hermann::Consumer).to receive(:new) { nil }
34
+ expect(consumer).to_not receive(:shutdown)
35
+ expect(result).to be false
36
+ end
37
+ end
38
+ end
39
+
40
+ describe '#subscribe' do
41
+ let(:topic) { 'topic' }
42
+ let(:destination) { double('Destination') }
43
+ let(:msg) { 'foo' }
44
+ it 'yields to the block and passes in consumed message' do
45
+ allow(destination).to receive(:as_kafka) { topic }
46
+ allow(Stapfen::Destination).to receive(:from_string) { destination }
47
+ allow(consumer).to receive(:consume).with(topic).and_yield(msg)
48
+
49
+ expect{ |b|
50
+ client.subscribe(destination, nil, &b)
51
+ }.to yield_with_args(msg)
52
+ end
53
+ end
54
+ end
@@ -5,6 +5,19 @@ describe Stapfen::Destination do
5
5
  it { should respond_to :name }
6
6
  it { should respond_to :type }
7
7
 
8
+ describe '#as_kafka' do
9
+ let(:name) { 'topic' }
10
+ subject(:destination) do
11
+ d = described_class.new
12
+ d.type = :topic
13
+ d.name = name
14
+ d.as_kafka
15
+ end
16
+
17
+ it { should be_instance_of String }
18
+ it { should eql "topic" }
19
+ end
20
+
8
21
  describe '#as_jms' do
9
22
  let(:name) { 'rspec/dlq' }
10
23
  subject(:destination) do
data/spec/logger_spec.rb CHANGED
@@ -21,7 +21,7 @@ describe Stapfen::Logger do
21
21
  end
22
22
 
23
23
  it 'should discard info messages' do
24
- expect(logger.info('rspec')).to be_false
24
+ expect(logger.info('rspec')).to be false
25
25
  end
26
26
  end
27
27
 
@@ -34,8 +34,7 @@ describe Stapfen::Logger do
34
34
 
35
35
  it 'should pass info messages along' do
36
36
  plogger.should_receive(:info)
37
-
38
- expect(logger.info('rspec')).to be_true
37
+ expect(logger.info('rspec')).to be true
39
38
  end
40
39
  end
41
40
  end
data/spec/spec_helper.rb CHANGED
@@ -1,7 +1,7 @@
1
1
  $LOAD_PATH.unshift(File.expand_path(File.dirname(__FILE__) + '../lib'))
2
2
 
3
3
  require 'stapfen'
4
-
4
+ require 'rspec/its'
5
5
 
6
6
  is_java = (RUBY_PLATFORM == 'java')
7
7
 
@@ -12,6 +12,9 @@ end
12
12
 
13
13
 
14
14
  RSpec.configure do |c|
15
+ c.color = true
16
+ c.order = "random"
17
+
15
18
  unless is_java
16
19
  c.filter_run_excluding :java => true
17
20
  end
data/spec/worker_spec.rb CHANGED
@@ -17,7 +17,7 @@ describe Stapfen::Worker do
17
17
  subject(:result) { worker.use_stomp! }
18
18
 
19
19
  it 'should update the instance variable' do
20
- expect(result).to be_true
20
+ expect(result).to be true
21
21
  expect(worker).to be_stomp
22
22
  expect(worker).not_to be_jms
23
23
  end
@@ -32,7 +32,7 @@ describe Stapfen::Worker do
32
32
  end
33
33
 
34
34
  it 'should update the instance variable' do
35
- expect(result).to be_true
35
+ expect(result).to be true
36
36
  expect(worker).to be_jms
37
37
  expect(worker).not_to be_stomp
38
38
  end
@@ -55,6 +55,7 @@ describe Stapfen::Worker do
55
55
  end
56
56
 
57
57
  describe '#configure' do
58
+ let(:config) { {:valid => true} }
58
59
  it 'should error when not passed a block' do
59
60
  expect {
60
61
  worker.configure
@@ -62,21 +63,26 @@ describe Stapfen::Worker do
62
63
  end
63
64
 
64
65
  it 'should save the return value from the block' do
65
- config = {:valid => true}
66
-
67
66
  worker.configure do
68
67
  config
69
68
  end
70
-
71
69
  expect(worker.configuration.call).to eql(config)
72
70
  end
73
71
  end
74
72
 
75
- describe '#exit_cleanly' do
73
+ describe '#exit_cleanly', :java => true do
76
74
  subject(:result) { worker.exit_cleanly }
77
75
 
76
+ before do
77
+ allow(Java::JavaLang::System).to receive(:exit).with(0)
78
+ end
79
+
80
+ after do
81
+ worker.class_variable_set(:@@workers, [])
82
+ end
83
+
78
84
  context 'with no worker classes' do
79
- it { should be_false }
85
+ it { should be false }
80
86
  end
81
87
 
82
88
  context 'with a single worker class' do
@@ -88,12 +94,12 @@ describe Stapfen::Worker do
88
94
 
89
95
  it "should execute the worker's #exit_cleanly method" do
90
96
  w.should_receive(:exit_cleanly)
91
- expect(result).to be_true
97
+ expect(result).to be true
92
98
  end
93
99
 
94
100
  it "should return false if the worker's #exit_cleanly method" do
95
101
  w.should_receive(:exit_cleanly).and_raise(StandardError)
96
- expect(result).to be_false
102
+ expect(result).to be false
97
103
  end
98
104
  end
99
105
 
@@ -101,14 +107,14 @@ describe Stapfen::Worker do
101
107
  let(:w1) { double('Fake Worker 1') }
102
108
  let(:w2) { double('Fake Worker 2') }
103
109
 
104
- before :each do
110
+ before do
105
111
  worker.class_variable_set(:@@workers, [w1, w2])
106
112
  end
107
113
 
108
114
  it 'should invoke both #exit_cleanly methods' do
109
- w1.should_receive(:exit_cleanly)
110
- w2.should_receive(:exit_cleanly)
111
- expect(result).to be_true
115
+ expect(w1).to receive(:exit_cleanly)
116
+ expect(w2).to receive(:exit_cleanly)
117
+ expect(worker.exit_cleanly).to be true
112
118
  end
113
119
  end
114
120
  end
@@ -125,6 +131,10 @@ describe Stapfen::Worker do
125
131
  context 'with just a queue name' do
126
132
  let(:name) { 'jms.queue.lol' }
127
133
 
134
+ before do
135
+ worker.instance_variable_set(:@consumers, [])
136
+ end
137
+
128
138
  it 'should add an entry for the queue name' do
129
139
  worker.consume(name) do |msg|
130
140
  nil
@@ -163,6 +173,16 @@ describe Stapfen::Worker do
163
173
  client.stub(:subscribe) do |name, headers, &block|
164
174
  block.call(message)
165
175
  end
176
+
177
+ config = {:valid => true}
178
+
179
+ worker.configure do
180
+ config
181
+ end
182
+ end
183
+
184
+ after do
185
+ worker.class_variable_set(:@@workers, [])
166
186
  end
167
187
 
168
188
  context 'with just a queue name' do
@@ -189,6 +209,7 @@ describe Stapfen::Worker do
189
209
  { :dead_letter_queue => '/queue/foo',
190
210
  :max_redeliveries => 3 }
191
211
  end
212
+
192
213
  let(:raw_headers) { unrec_headers.merge(:other_header => 'foo!') }
193
214
  context 'on a failed message' do
194
215
  it 'should unreceive' do
data/stapfen.gemspec CHANGED
@@ -3,17 +3,22 @@ lib = File.expand_path('../lib', __FILE__)
3
3
  $LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
4
4
  require 'stapfen/version'
5
5
 
6
- Gem::Specification.new do |gem|
7
- gem.name = "stapfen"
8
- gem.version = Stapfen::VERSION
9
- gem.authors = ["R. Tyler Croy"]
10
- gem.email = ["rtyler.croy@lookout.com"]
11
- gem.description = "A simple gem for writing good basic STOMP workers"
12
- gem.summary = "A simple gem for writing good basic STOMP workers"
13
- gem.homepage = ""
6
+ Gem::Specification.new do |s|
7
+ s.name = "stapfen"
8
+ s.version = Stapfen::VERSION
9
+ s.authors = ["R. Tyler Croy"]
10
+ s.email = ["rtyler.croy@lookout.com"]
11
+ s.description = "A simple gem for writing good basic STOMP workers"
12
+ s.summary = "A simple gem for writing good basic STOMP workers"
13
+ s.homepage = ""
14
14
 
15
- gem.files = `git ls-files`.split($/)
16
- gem.executables = gem.files.grep(%r{^bin/}).map{ |f| File.basename(f) }
17
- gem.test_files = gem.files.grep(%r{^(test|spec|features)/})
18
- gem.require_paths = ["lib"]
15
+ s.files = `git ls-files`.split($/)
16
+ s.executables = s.files.grep(%r{^bin/}).map{ |f| File.basename(f) }
17
+ s.test_files = s.files.grep(%r{^(test|spec|features)/})
18
+ s.require_paths = ["lib"]
19
+
20
+ if RUBY_PLATFORM == "java"
21
+ s.add_dependency 'hermann', "~> 0.20.0"
22
+ s.platform = 'java'
23
+ end
19
24
  end
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: stapfen
3
3
  version: !ruby/object:Gem::Version
4
- version: 2.1.1
4
+ version: 2.2.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - R. Tyler Croy
@@ -9,7 +9,7 @@ autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
11
 
12
- date: 2014-01-28 00:00:00 Z
12
+ date: 2014-11-03 00:00:00 Z
13
13
  dependencies: []
14
14
 
15
15
  description: A simple gem for writing good basic STOMP workers
@@ -32,6 +32,7 @@ files:
32
32
  - lib/stapfen.rb
33
33
  - lib/stapfen/client.rb
34
34
  - lib/stapfen/client/jms.rb
35
+ - lib/stapfen/client/kafka.rb
35
36
  - lib/stapfen/client/stomp.rb
36
37
  - lib/stapfen/destination.rb
37
38
  - lib/stapfen/logger.rb
@@ -39,6 +40,7 @@ files:
39
40
  - lib/stapfen/version.rb
40
41
  - lib/stapfen/worker.rb
41
42
  - spec/client/jms_spec.rb
43
+ - spec/client/kafka_spec.rb
42
44
  - spec/client/stomp_spec.rb
43
45
  - spec/client_spec.rb
44
46
  - spec/destination_spec.rb
@@ -69,12 +71,13 @@ required_rubygems_version: !ruby/object:Gem::Requirement
69
71
  requirements: []
70
72
 
71
73
  rubyforge_project:
72
- rubygems_version: 2.2.1
74
+ rubygems_version: 2.4.1
73
75
  signing_key:
74
76
  specification_version: 4
75
77
  summary: A simple gem for writing good basic STOMP workers
76
78
  test_files:
77
79
  - spec/client/jms_spec.rb
80
+ - spec/client/kafka_spec.rb
78
81
  - spec/client/stomp_spec.rb
79
82
  - spec/client_spec.rb
80
83
  - spec/destination_spec.rb