action_subscriber 1.3.0.rc0-java → 1.4.0-java

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: b86e0cbcf0af1bdd5f25742161fbc643df6f1905
4
- data.tar.gz: 81b0ba3ff06133af583aaff1eed278d5e13e2e36
3
+ metadata.gz: 54f1bedbe81ed4f5f7be1e55396e635804caee90
4
+ data.tar.gz: 98653c65724ab0410128c74fa7d7423fea0d3353
5
5
  SHA512:
6
- metadata.gz: 65411ae99b60937735bd5c6c1a1ee8ecc79be77da3847ccc9bbcbd05d94e16bf6ae7df03eb26ebec507328de30cc424b5b9b633cbc66a5e9b28e15f649e77e4d
7
- data.tar.gz: 997cd52b905f8b8315b1608e5da33dd98c40442bc20f1d86e444d0350d13010d5e1fbd0d36ba021a4536baeb03ad9fc495fa2a5809b8a807ccd036c45f5ce864
6
+ metadata.gz: 34c87c741309e62954644936130e301c3ded6b007190c7ebf6ad9559f43b6bde2fafd3a02918308816ff6b35082442c1b5e1be145263328c2553511c9ac151bc
7
+ data.tar.gz: 294933dfbf85d177f2c14a7ba29c811c8ed8e17a955ce2e638804d8b5097ed983dfd4032d9eaa00cafcaab13889240d1aa39a640a16ff6d0c615786436580e89
@@ -36,6 +36,8 @@ module ActionSubscriber
36
36
  ::ActionSubscriber::Babou.auto_pop!
37
37
  when /subscribe/i then
38
38
  ::ActionSubscriber::Babou.start_subscribers
39
+ else
40
+ fail "ActionSubscriber.configuration.mode must be 'pop' or 'subscribe'. Currently set to '#{::ActionSubscriber.configuration.mode}'"
39
41
  end
40
42
  end
41
43
  end
@@ -14,6 +14,7 @@ require "action_subscriber/version"
14
14
  require "action_subscriber/default_routing"
15
15
  require "action_subscriber/dsl"
16
16
  require "action_subscriber/configuration"
17
+ require "action_subscriber/message_retry"
17
18
  require "action_subscriber/middleware"
18
19
  require "action_subscriber/rabbit_connection"
19
20
  require "action_subscriber/subscribable"
@@ -80,7 +80,8 @@ module ActionSubscriber
80
80
  yield
81
81
  acknowledge
82
82
  rescue => error
83
- reject
83
+ ::ActionSubscriber::MessageRetry.redeliver_message_with_backoff(env)
84
+ acknowledge
84
85
  raise error
85
86
  end
86
87
 
@@ -24,8 +24,10 @@ module ActionSubscriber
24
24
  :content_type => properties[:content_type],
25
25
  :delivery_tag => delivery_info.delivery_tag,
26
26
  :exchange => delivery_info.exchange,
27
+ :headers => properties.headers,
27
28
  :message_id => nil,
28
29
  :routing_key => delivery_info.routing_key,
30
+ :queue => queue.name,
29
31
  }
30
32
  env = ::ActionSubscriber::Middleware::Env.new(self, encoded_payload, properties)
31
33
  enqueue_env(env)
@@ -45,8 +47,10 @@ module ActionSubscriber
45
47
  :content_type => properties.content_type,
46
48
  :delivery_tag => delivery_info.delivery_tag,
47
49
  :exchange => delivery_info.exchange,
50
+ :headers => properties.headers,
48
51
  :message_id => properties.message_id,
49
52
  :routing_key => delivery_info.routing_key,
53
+ :queue => queue.name,
50
54
  }
51
55
  env = ::ActionSubscriber::Middleware::Env.new(self, encoded_payload, properties)
52
56
  enqueue_env(env)
@@ -12,16 +12,18 @@ module ActionSubscriber
12
12
  times_to_pop = [::ActionSubscriber::Threadpool.ready_size, ::ActionSubscriber.config.times_to_pop].min
13
13
  times_to_pop.times do
14
14
  queues.each do |queue|
15
- header, encoded_payload = queue.pop(queue_subscription_options)
15
+ metadata, encoded_payload = queue.pop(queue_subscription_options)
16
16
  next unless encoded_payload
17
17
  ::ActiveSupport::Notifications.instrument "popped_event.action_subscriber", :payload_size => encoded_payload.bytesize, :queue => queue.name
18
18
  properties = {
19
19
  :channel => queue.channel,
20
- :content_type => header.content_type,
21
- :delivery_tag => header.delivery_tag,
22
- :exchange => header.exchange,
23
- :message_id => header.message_id,
24
- :routing_key => header.routing_key,
20
+ :content_type => metadata.content_type,
21
+ :delivery_tag => metadata.delivery_tag,
22
+ :exchange => metadata.exchange,
23
+ :headers => _normalized_headers(metadata),
24
+ :message_id => metadata.message_id,
25
+ :routing_key => metadata.routing_key,
26
+ :queue => queue.name,
25
27
  }
26
28
  env = ::ActionSubscriber::Middleware::Env.new(self, encoded_payload, properties)
27
29
  enqueue_env(env)
@@ -35,15 +37,17 @@ module ActionSubscriber
35
37
  def auto_subscribe!
36
38
  queues.each do |queue|
37
39
  queue.channel.prefetch = ::ActionSubscriber.config.prefetch if acknowledge_messages?
38
- consumer = queue.subscribe(queue_subscription_options) do |header, encoded_payload|
40
+ consumer = queue.subscribe(queue_subscription_options) do |metadata, encoded_payload|
39
41
  ::ActiveSupport::Notifications.instrument "received_event.action_subscriber", :payload_size => encoded_payload.bytesize, :queue => queue.name
40
42
  properties = {
41
43
  :channel => queue.channel,
42
- :content_type => header.content_type,
43
- :delivery_tag => header.delivery_tag,
44
- :exchange => header.exchange,
45
- :message_id => header.message_id,
46
- :routing_key => header.routing_key,
44
+ :content_type => metadata.content_type,
45
+ :delivery_tag => metadata.delivery_tag,
46
+ :exchange => metadata.exchange,
47
+ :headers => _normalized_headers(metadata),
48
+ :message_id => metadata.message_id,
49
+ :routing_key => metadata.routing_key,
50
+ :queue => queue.name,
47
51
  }
48
52
  env = ::ActionSubscriber::Middleware::Env.new(self, encoded_payload, properties)
49
53
  enqueue_env(env)
@@ -66,6 +70,13 @@ module ActionSubscriber
66
70
  end
67
71
  end
68
72
  end
73
+
74
+ def _normalized_headers(metadata)
75
+ return {} unless metadata.headers
76
+ metadata.headers.each_with_object({}) do |(header,value), hash|
77
+ hash[header] = value.to_s
78
+ end
79
+ end
69
80
  end
70
81
  end
71
82
  end
@@ -0,0 +1,60 @@
1
+ module ActionSubscriber
2
+ module MessageRetry
3
+ SCHEDULE = {
4
+ 2 => 100,
5
+ 3 => 500,
6
+ 4 => 2_500,
7
+ 5 => 12_500,
8
+ 6 => 62_500,
9
+ 7 => 312_500,
10
+ 8 => 1_562_500,
11
+ 9 => 7_812_500,
12
+ 10 => 39_062_500,
13
+ }.freeze
14
+
15
+ def self.redeliver_message_with_backoff(env)
16
+ next_attempt = get_last_attempt_number(env) + 1
17
+ ttl = SCHEDULE[next_attempt]
18
+ return unless ttl
19
+ with_exchange(env, ttl) do |exchange|
20
+ exchange.publish(env.encoded_payload, retry_options(env, next_attempt))
21
+ end
22
+ end
23
+
24
+ # Private Implementation
25
+ def self.get_last_attempt_number(env)
26
+ attempt_header = env.headers.fetch("as-attempt", "1")
27
+ attempt_header.to_i
28
+ end
29
+
30
+ def self.retry_headers(env, attempt)
31
+ env.headers.reject do |key, val|
32
+ key == "x-death"
33
+ end.merge({"as-attempt" => attempt.to_s})
34
+ end
35
+
36
+ def self.retry_options(env, attempt)
37
+ {
38
+ :content_type => env.content_type,
39
+ :routing_key => env.routing_key,
40
+ :headers => retry_headers(env, attempt),
41
+ }
42
+ end
43
+
44
+ def self.with_exchange(env, ttl)
45
+ exchange_retry_name = "#{env.exchange}_retry_#{ttl}"
46
+ queue_retry_name = "#{env.queue}_retry_#{ttl}"
47
+ channel = RabbitConnection.subscriber_connection.create_channel
48
+ begin
49
+ channel.confirm_select
50
+ exchange = channel.topic(exchange_retry_name)
51
+ queue = channel.queue(queue_retry_name, :arguments => {"x-dead-letter-exchange" => env.exchange, "x-message-ttl" => ttl})
52
+ queue.bind(exchange, :routing_key => env.routing_key)
53
+ yield(exchange)
54
+ channel.wait_for_confirms
55
+ ensure
56
+ channel.close rescue nil
57
+ end
58
+ end
59
+ end
60
+ end
@@ -6,8 +6,10 @@ module ActionSubscriber
6
6
  attr_reader :content_type,
7
7
  :encoded_payload,
8
8
  :exchange,
9
+ :headers,
9
10
  :message_id,
10
11
  :routing_key,
12
+ :queue,
11
13
  :subscriber
12
14
 
13
15
  ##
@@ -18,16 +20,18 @@ module ActionSubscriber
18
20
  # :content_type => String
19
21
  # :delivery_tag => String (the message identifier to send back to rabbitmq for acknowledgement)
20
22
  # :exchange => String
23
+ # :headers => Hash[ String => String ]
21
24
  # :message_id => String
22
25
  # :routing_key => String
23
-
24
26
  def initialize(subscriber, encoded_payload, properties)
25
27
  @channel = properties.fetch(:channel)
26
28
  @content_type = properties.fetch(:content_type)
27
29
  @delivery_tag = properties.fetch(:delivery_tag)
28
30
  @encoded_payload = encoded_payload
29
31
  @exchange = properties.fetch(:exchange)
32
+ @headers = properties.fetch(:headers) || {}
30
33
  @message_id = properties.fetch(:message_id)
34
+ @queue = properties.fetch(:queue)
31
35
  @routing_key = properties.fetch(:routing_key)
32
36
  @subscriber = subscriber
33
37
  end
@@ -25,10 +25,12 @@ module ActionSubscriber
25
25
  end
26
26
  end
27
27
 
28
- def self.publishing_options(route, options = {})
29
- options[:mandatory] = false unless options.key(:mandatory)
30
- options[:persistent] = false unless options.key(:persistent)
31
- options[:routing_key] = route
28
+ def self.publishing_options(route, in_options = {})
29
+ options = {
30
+ :mandatory => false,
31
+ :persistent => false,
32
+ :routing_key => route,
33
+ }.merge(in_options)
32
34
 
33
35
  if ::RUBY_PLATFORM == "java"
34
36
  java_options = {}
@@ -17,8 +17,10 @@ module ActionSubscriber
17
17
  :content_type => "text/plain",
18
18
  :delivery_tag => "XYZ",
19
19
  :exchange => "events",
20
+ :headers => {},
20
21
  :message_id => "MSG-123",
21
22
  :routing_key => "amigo.user.created",
23
+ :queue => "test.amigo.user.created",
22
24
  }.freeze
23
25
 
24
26
  # Create a new subscriber instance. Available options are:
@@ -73,8 +75,10 @@ end
73
75
  :content_type => "text/plain",
74
76
  :delivery_tag => "XYZ",
75
77
  :exchange => "events",
78
+ :headers => {},
76
79
  :message_id => "MSG-123",
77
80
  :routing_key => "amigo.user.created",
81
+ :queue => "test.amigo.user.created",
78
82
  }}
79
83
  end
80
84
 
@@ -1,3 +1,3 @@
1
1
  module ActionSubscriber
2
- VERSION = "1.3.0.rc0"
2
+ VERSION = "1.4.0"
3
3
  end
@@ -17,7 +17,7 @@ describe "at_least_once! mode", :integration => true do
17
17
  exchange = channel.topic("events")
18
18
  exchange.publish("GrumpFace", :routing_key => "gorby_puff.grumpy")
19
19
 
20
- verify_expectation_within(1.0) do
20
+ verify_expectation_within(2.0) do
21
21
  expect($messages).to eq Set.new(["GrumpFace::0","GrumpFace::1","GrumpFace::2"])
22
22
  end
23
23
  end
@@ -0,0 +1,27 @@
1
+ class PrankSubscriber < ActionSubscriber::Base
2
+ publisher :pikitis
3
+
4
+ def pulled
5
+ $messages << env.headers
6
+ end
7
+ end
8
+
9
+ describe "Custom Headers Are Published and Received", :integration => true do
10
+ let(:headers) { { "Custom" => "content/header" } }
11
+
12
+ it "works for auto_pop!" do
13
+ ::ActionSubscriber::Publisher.publish("pikitis.prank.pulled", "Yo Knope!", "events", :headers => headers)
14
+ verify_expectation_within(2.0) do
15
+ ::ActionSubscriber.auto_pop!
16
+ expect($messages).to eq(Set.new([headers]))
17
+ end
18
+ end
19
+
20
+ it "works for auto_subscriber!" do
21
+ ::ActionSubscriber.auto_subscribe!
22
+ ::ActionSubscriber::Publisher.publish("pikitis.prank.pulled", "Yo Knope!", "events", :headers => headers)
23
+ verify_expectation_within(2.0) do
24
+ expect($messages).to eq(Set.new([headers]))
25
+ end
26
+ end
27
+ end
@@ -7,8 +7,10 @@ describe ActionSubscriber::Middleware::Env do
7
7
  :delivery_tag => "XYZ",
8
8
  :encoded_payload => encoded_payload,
9
9
  :exchange => "events",
10
+ :headers => {},
10
11
  :message_id => "MSG-1234",
11
12
  :routing_key => "amigo.user.created",
13
+ :queue => "test.amigo.user.created",
12
14
  } }
13
15
  let(:subscriber) { UserSubscriber }
14
16
 
@@ -17,8 +19,10 @@ describe ActionSubscriber::Middleware::Env do
17
19
  specify { expect(subject.action).to eq("created") }
18
20
  specify { expect(subject.content_type).to eq(properties[:content_type]) }
19
21
  specify { expect(subject.exchange).to eq(properties[:exchange]) }
22
+ specify { expect(subject.headers).to eq(properties[:headers]) }
20
23
  specify { expect(subject.message_id).to eq(properties[:message_id]) }
21
24
  specify { expect(subject.routing_key).to eq(properties[:routing_key]) }
25
+ specify { expect(subject.queue).to eq(properties[:queue]) }
22
26
 
23
27
  describe "#acknowledge" do
24
28
  it "sends an acknowledgement to rabbitmq" do
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: action_subscriber
3
3
  version: !ruby/object:Gem::Version
4
- version: 1.3.0.rc0
4
+ version: 1.4.0
5
5
  platform: java
6
6
  authors:
7
7
  - Brian Stien
@@ -12,7 +12,7 @@ authors:
12
12
  autorequire:
13
13
  bindir: bin
14
14
  cert_chain: []
15
- date: 2015-10-14 00:00:00.000000000 Z
15
+ date: 2015-10-28 00:00:00.000000000 Z
16
16
  dependencies:
17
17
  - !ruby/object:Gem::Dependency
18
18
  requirement: !ruby/object:Gem::Requirement
@@ -202,6 +202,7 @@ files:
202
202
  - lib/action_subscriber/default_routing.rb
203
203
  - lib/action_subscriber/dsl.rb
204
204
  - lib/action_subscriber/march_hare/subscriber.rb
205
+ - lib/action_subscriber/message_retry.rb
205
206
  - lib/action_subscriber/middleware.rb
206
207
  - lib/action_subscriber/middleware/active_record/connection_management.rb
207
208
  - lib/action_subscriber/middleware/active_record/query_cache.rb
@@ -222,6 +223,7 @@ files:
222
223
  - spec/integration/at_most_once_spec.rb
223
224
  - spec/integration/automatic_reconnect_spec.rb
224
225
  - spec/integration/basic_subscriber_spec.rb
226
+ - spec/integration/custom_headers_spec.rb
225
227
  - spec/integration/decoding_payloads_spec.rb
226
228
  - spec/integration/manual_acknowledgement_spec.rb
227
229
  - spec/lib/action_subscriber/base_spec.rb
@@ -254,9 +256,9 @@ required_ruby_version: !ruby/object:Gem::Requirement
254
256
  version: '0'
255
257
  required_rubygems_version: !ruby/object:Gem::Requirement
256
258
  requirements:
257
- - - ">"
259
+ - - ">="
258
260
  - !ruby/object:Gem::Version
259
- version: 1.3.1
261
+ version: '0'
260
262
  requirements: []
261
263
  rubyforge_project:
262
264
  rubygems_version: 2.4.8
@@ -269,6 +271,7 @@ test_files:
269
271
  - spec/integration/at_most_once_spec.rb
270
272
  - spec/integration/automatic_reconnect_spec.rb
271
273
  - spec/integration/basic_subscriber_spec.rb
274
+ - spec/integration/custom_headers_spec.rb
272
275
  - spec/integration/decoding_payloads_spec.rb
273
276
  - spec/integration/manual_acknowledgement_spec.rb
274
277
  - spec/lib/action_subscriber/base_spec.rb