emque-consuming 1.1.3 → 1.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.
data/CHANGELOG.md CHANGED
@@ -1,5 +1,6 @@
1
1
  # Emque Consuming CHANGELOG
2
2
 
3
+ - [Add in the ability to retry errors and back off with an exponential delay](https://github.com/emque/emque-consuming/pull/55) 1.2.0
3
4
  - [Add in a configuration option to disable auto shutdown on reaching the error limit](https://github.com/emque/emque-consuming/pull/58) 1.1.3
4
5
 
5
6
  ## 1.0.0.beta4
@@ -10,6 +11,6 @@ After starting up, messages will need to be manually moved
10
11
  from the old queue to the new one.
11
12
 
12
13
  ### Failed Message Routing
13
- Messages that are not acknolwedged due to a consumer error will now be routed
14
+ Messages that are not acknowledged due to a consumer error will now be routed
14
15
  into a `service_name.error` queue. These can then be inspected and be discarded,
15
16
  purged, or manually moved back to the primary queue for re-processing.
data/README.md CHANGED
@@ -59,6 +59,22 @@ emque <options> (start|stop|new|console|help) <name (new only)>
59
59
  # ...
60
60
  ```
61
61
 
62
+ ### Automatic Error Retries
63
+
64
+ In 1.2.0 the ability to automatically retry specific types of errors was introduced.
65
+ This depends on the [Delayed Message Exchange](https://github.com/rabbitmq/rabbitmq-delayed-message-exchange) plugin. After
66
+ [installing the plugin](https://github.com/rabbitmq/rabbitmq-delayed-message-exchange#installing),
67
+ you'll need to configure emque consuming to utilize the plugin:
68
+
69
+ ```
70
+ config.enable_delayed_message = true # turn on retryable errors, defaults to false
71
+ config.retryable_errors = ["ExampleError"] # a comma delimited array of strings matching the error, defaults to any empty array ([])
72
+ config.retryable_error_limit = 4 # the number of retries to use before dead lettering the message, defaults to 3
73
+ config.delayed_message_workers = 3 # the number of workers processing delayed messages, defaults to 1
74
+ ```
75
+
76
+ This will now allow you to retry known errors with an exponential backoff, which should help with transient errors!
77
+
62
78
  ### Custom
63
79
 
64
80
  Configure Emque::Consuming in your config/application.rb file. Here is an example:
@@ -0,0 +1,87 @@
1
+ require "bunny"
2
+
3
+ module Emque
4
+ module Consuming
5
+ module Adapters
6
+ module RabbitMq
7
+ class DelayedMessageWorker
8
+ include Emque::Consuming::Actor
9
+ include Emque::Consuming::RetryableErrors
10
+ trap_exit :actor_died
11
+
12
+ def actor_died(actor, reason)
13
+ unless shutdown
14
+ logger.error "#{log_prefix} actor_died - died: #{reason}"
15
+ end
16
+ end
17
+
18
+ def initialize(connection)
19
+ self.channel = connection.create_channel
20
+
21
+ self.delayed_message_exchange = channel.exchange(
22
+ "emque.#{config.app_name}.delayed_message",
23
+ {
24
+ :type => "x-delayed-message",
25
+ :durable => true,
26
+ :auto_delete => false,
27
+ :arguments => {
28
+ "x-delayed-type" => "direct",
29
+ }
30
+ }
31
+ )
32
+
33
+ self.queue = channel.queue(
34
+ "emque.#{config.app_name}.delayed_message",
35
+ :durable => config.adapter.options[:durable],
36
+ :auto_delete => config.adapter.options[:auto_delete],
37
+ :arguments => {
38
+ "x-dead-letter-exchange" => "#{config.app_name}.error"
39
+ }
40
+ ).bind(delayed_message_exchange)
41
+ end
42
+
43
+ def start
44
+ logger.info "#{log_prefix} starting..."
45
+ queue.subscribe(:manual_ack => true, &method(:process_message))
46
+ logger.debug "#{log_prefix} started"
47
+ end
48
+
49
+ def stop
50
+ logger.debug "#{log_prefix} stopping..."
51
+ super do
52
+ logger.debug "#{log_prefix} closing channel"
53
+ channel.close
54
+ end
55
+ logger.debug "#{log_prefix} stopped"
56
+ end
57
+
58
+ private
59
+
60
+ attr_accessor :channel, :delayed_message_exchange, :queue
61
+
62
+ def process_message(delivery_info, metadata, payload)
63
+ begin
64
+ logger.info "#{log_prefix} processing message #{metadata}"
65
+ logger.debug "#{log_prefix} payload #{payload}"
66
+ message = Emque::Consuming::Message.new(
67
+ :original => payload
68
+ )
69
+ ::Emque::Consuming::Consumer.new.consume(:process, message)
70
+ channel.ack(delivery_info.delivery_tag)
71
+ rescue StandardError => ex
72
+ if retryable_errors.any? { |error| ex.class.to_s =~ /#{error}/ }
73
+ retry_error(delivery_info, metadata, payload, ex)
74
+ else
75
+ channel.nack(delivery_info.delivery_tag)
76
+ end
77
+ end
78
+ end
79
+
80
+ def log_prefix
81
+ "RabbitMQ DelayedMessageWorker:"
82
+ end
83
+ end
84
+ end
85
+ end
86
+ end
87
+ end
@@ -4,7 +4,7 @@ module Emque
4
4
  module Consuming
5
5
  module Adapters
6
6
  module RabbitMq
7
- class RetryWorker
7
+ class ErrorWorker
8
8
  include Emque::Consuming::Helpers
9
9
 
10
10
  def initialize(connection)
@@ -43,7 +43,7 @@ module Emque
43
43
  end
44
44
 
45
45
  def log_prefix
46
- "RabbitMQ RetryWorker:"
46
+ "RabbitMQ ErrorWorker:"
47
47
  end
48
48
 
49
49
  def retry_message(delivery_info, metadata, payload)
@@ -10,7 +10,7 @@ module Emque
10
10
 
11
11
  def actor_died(actor, reason)
12
12
  unless shutdown
13
- logger.error "RabbitMQ Manager: actor_died - #{actor.inspect} "+
13
+ logger.error "RabbitMQ Manager: actor_died - #{actor.inspect} " +
14
14
  "died: #{reason}"
15
15
  end
16
16
  end
@@ -19,10 +19,16 @@ module Emque
19
19
  setup_connection
20
20
  initialize_error_queue
21
21
  initialize_workers
22
+ initialize_delayed_message_workers if enable_delayed_message
22
23
  logger.info "RabbitMQ Manager: starting #{worker_count} workers..."
23
24
  workers(:flatten => true).each do |worker|
24
25
  worker.async.start
25
26
  end
27
+ if enable_delayed_message
28
+ delayed_message_workers.each do |worker|
29
+ worker.async.start
30
+ end
31
+ end
26
32
  end
27
33
 
28
34
  def stop
@@ -33,6 +39,12 @@ module Emque
33
39
  logger.info "RabbitMQ Manager: stopping #{worker.topic} worker..."
34
40
  worker.stop
35
41
  end
42
+ if enable_delayed_message
43
+ delayed_message_workers.each_with_index do |worker, i|
44
+ logger.info "RabbitMQ Manager: stopping #{worker.class} #{i + 1} worker..."
45
+ worker.stop
46
+ end
47
+ end
36
48
  end
37
49
 
38
50
  @connection.stop
@@ -55,13 +67,17 @@ module Emque
55
67
  flatten ? @workers.values.flatten : @workers
56
68
  end
57
69
 
70
+ def delayed_message_workers
71
+ @delayed_message_workers
72
+ end
73
+
58
74
  def retry_errors
59
- RetryWorker.new(@connection).retry_errors
75
+ ErrorWorker.new(@connection).retry_errors
60
76
  end
61
77
 
62
78
  private
63
79
 
64
- attr_writer :workers
80
+ attr_writer :workers, :delayed_message_workers
65
81
 
66
82
  def initialize_workers
67
83
  self.workers = {}.tap { |workers|
@@ -74,6 +90,18 @@ module Emque
74
90
  }
75
91
  end
76
92
 
93
+ def initialize_delayed_message_workers
94
+ self.delayed_message_workers = [].tap { |workers|
95
+ config.delayed_message_workers.times do
96
+ workers << DelayedMessageWorker.new_link(@connection)
97
+ end
98
+ }
99
+ end
100
+
101
+ def enable_delayed_message
102
+ config.enable_delayed_message
103
+ end
104
+
77
105
  def initialize_error_queue
78
106
  channel = @connection.create_channel
79
107
  error_exchange = channel.fanout(
@@ -6,6 +6,7 @@ module Emque
6
6
  module RabbitMq
7
7
  class Worker
8
8
  include Emque::Consuming::Actor
9
+ include Emque::Consuming::RetryableErrors
9
10
  trap_exit :actor_died
10
11
 
11
12
  attr_accessor :topic
@@ -64,6 +65,10 @@ module Emque
64
65
 
65
66
  attr_accessor :name, :channel, :queue
66
67
 
68
+ def enable_delayed_message
69
+ config.enable_delayed_message
70
+ end
71
+
67
72
  def process_message(delivery_info, metadata, payload)
68
73
  begin
69
74
  logger.info "#{log_prefix} processing message #{metadata}"
@@ -73,11 +78,48 @@ module Emque
73
78
  )
74
79
  ::Emque::Consuming::Consumer.new.consume(:process, message)
75
80
  channel.ack(delivery_info.delivery_tag)
76
- rescue StandardError
77
- channel.nack(delivery_info.delivery_tag)
81
+ rescue StandardError => ex
82
+ if enable_delayed_message
83
+ publish_to_delayed_message(delivery_info, metadata, payload)
84
+ else
85
+ channel.nack(delivery_info.delivery_tag)
86
+ end
87
+ ensure
88
+ channel.ack(delivery_info.delivery_tag)
78
89
  end
79
90
  end
80
91
 
92
+ def publish_to_delayed_message(delivery_info, metadata, payload)
93
+ headers = metadata[:headers] || {}
94
+ headers["x-delay"] = 1000
95
+ delayed_message_exchange.publish(payload, { :headers => headers })
96
+ channel.ack(delivery_info.delivery_tag)
97
+ end
98
+
99
+ def delayed_message_exchange
100
+ delayed_message_exchange = channel.exchange(
101
+ "emque.#{config.app_name}.delayed_message",
102
+ {
103
+ :type => "x-delayed-message",
104
+ :durable => true,
105
+ :auto_delete => false,
106
+ :arguments => {
107
+ "x-delayed-type" => "direct",
108
+ }
109
+ }
110
+ )
111
+ channel.queue(
112
+ "emque.#{config.app_name}.delayed_message",
113
+ :durable => config.adapter.options[:durable],
114
+ :auto_delete => config.adapter.options[:auto_delete],
115
+ :arguments => {
116
+ "x-dead-letter-exchange" => "#{config.app_name}.error"
117
+ }
118
+ ).bind(delayed_message_exchange)
119
+
120
+ delayed_message_exchange
121
+ end
122
+
81
123
  def log_prefix
82
124
  "RabbitMQ Worker: #{object_id} #{name}"
83
125
  end
@@ -14,7 +14,8 @@ module Emque
14
14
  def self.load
15
15
  require_relative "rabbit_mq/manager"
16
16
  require_relative "rabbit_mq/worker"
17
- require_relative "rabbit_mq/retry_worker"
17
+ require_relative "rabbit_mq/error_worker"
18
+ require_relative "rabbit_mq/delayed_message_worker"
18
19
  end
19
20
 
20
21
  def self.manager
@@ -144,6 +144,14 @@ module Emque
144
144
  end
145
145
  end
146
146
 
147
+ o.on(
148
+ "--retry-error-limit N",
149
+ "Max number of times to retry a retryable error"
150
+ ) do |arg|
151
+ retry_limit = arg.to_i
152
+ options[:retryable_error_limit] = retry_limit if retry_limit > 0
153
+ end
154
+
147
155
  o.banner = "emque <options> (start|stop|new|console|help) <name (new only)>"
148
156
  }
149
157
  end
@@ -3,23 +3,29 @@ require "logger"
3
3
  module Emque
4
4
  module Consuming
5
5
  class Configuration
6
- attr_accessor :app_name, :auto_shutdown, :adapter, :error_handlers,
7
- :error_limit, :error_expiration, :status, :status_port, :status_host,
6
+ attr_accessor :app_name, :adapter, :auto_shutdown,
7
+ :delayed_message_workers, :enable_delayed_message, :error_handlers,
8
+ :error_limit, :error_expiration, :retryable_errors,
9
+ :retryable_error_limit, :status, :status_port, :status_host,
8
10
  :socket_path, :shutdown_handlers
9
11
  attr_writer :env, :log_level
10
12
 
11
13
  def initialize
12
- @app_name = ""
13
- @auto_shutdown = false
14
- @error_handlers = []
15
- @error_limit = 5
16
- @error_expiration = 3600 # 60 minutes
17
- @log_level = nil
18
- @status_port = 10000
19
- @status_host = "0.0.0.0"
20
- @status = :off # :on
21
- @socket_path = "tmp/emque.sock"
22
- @shutdown_handlers = []
14
+ @app_name = ""
15
+ @auto_shutdown = false
16
+ @delayed_message_workers = 1
17
+ @enable_delayed_message = false
18
+ @error_handlers = []
19
+ @error_limit = 5
20
+ @error_expiration = 3600 # 60 minutes
21
+ @log_level = nil
22
+ @retryable_errors = []
23
+ @retryable_error_limit = 3
24
+ @status_port = 10000
25
+ @status_host = "0.0.0.0"
26
+ @status = :off # :on
27
+ @socket_path = "tmp/emque.sock"
28
+ @shutdown_handlers = []
23
29
  end
24
30
 
25
31
  def env
@@ -42,13 +48,17 @@ module Emque
42
48
  {}.tap { |config|
43
49
  [
44
50
  :app_name,
45
- :auto_shutdown,
46
51
  :adapter,
52
+ :auto_shutdown,
53
+ :delayed_message_workers,
47
54
  :env,
55
+ :enable_delayed_message,
48
56
  :error_handlers,
49
57
  :error_limit,
50
58
  :error_expiration,
51
59
  :log_level,
60
+ :retryable_errors,
61
+ :retryable_error_limit,
52
62
  :status_port,
53
63
  :status_host,
54
64
  :status,
@@ -1,5 +1,6 @@
1
1
  require "oj"
2
2
  require_relative "consumer/common"
3
+ require_relative "retryable_errors"
3
4
 
4
5
  module Emque
5
6
  module Consuming
@@ -0,0 +1,37 @@
1
+ module Emque
2
+ module Consuming
3
+ module RetryableErrors
4
+ include Emque::Consuming::Helpers
5
+
6
+ def retryable_errors
7
+ config.retryable_errors
8
+ end
9
+
10
+ def retryable_error_limit
11
+ config.retryable_error_limit
12
+ end
13
+
14
+ def delay_ms_time(retry_count)
15
+ retry_count * 500 * ( 2 ** retry_count)
16
+ end
17
+
18
+ def retry_error(delivery_info, metadata, payload, ex)
19
+ headers = metadata[:headers] || {}
20
+ retry_count = headers.fetch("x-retry-count", 0)
21
+
22
+ if retry_count <= retryable_error_limit
23
+ logger.info("Retrying Retryable Error #{ex.class}, with count " +
24
+ "#{retry_count}")
25
+ headers["x-retry-count"] = retry_count + 1
26
+ headers["x-delay"] = delay_ms_time(retry_count)
27
+ channel.ack(delivery_info.delivery_tag)
28
+ delayed_message_exchange.publish(payload, { :headers => headers })
29
+ else
30
+ logger.info("Retryable Error: #{ex.class} ran out of retries at " +
31
+ "#{retry_count}")
32
+ channel.nack(delivery_info.delivery_tag)
33
+ end
34
+ end
35
+ end
36
+ end
37
+ end
@@ -1,5 +1,5 @@
1
1
  module Emque
2
2
  module Consuming
3
- VERSION = "1.1.3"
3
+ VERSION = "1.2.0"
4
4
  end
5
5
  end
@@ -14,6 +14,45 @@ describe Emque::Consuming::Configuration do
14
14
  end
15
15
  end
16
16
 
17
+ describe "delayed_message_workers" do
18
+ it "has a default" do
19
+ config = Emque::Consuming::Configuration.new
20
+ expect(config.delayed_message_workers).to eq(1)
21
+ end
22
+
23
+ it "prefers the assigned value" do
24
+ config = Emque::Consuming::Configuration.new
25
+ config.delayed_message_workers = 2
26
+ expect(config.delayed_message_workers).to eq(2)
27
+ end
28
+ end
29
+
30
+ describe "retryable_errors" do
31
+ it "has a default" do
32
+ config = Emque::Consuming::Configuration.new
33
+ expect(config.retryable_errors).to eq([])
34
+ end
35
+
36
+ it "prefers the assigned value" do
37
+ config = Emque::Consuming::Configuration.new
38
+ config.retryable_errors = ["TestError"]
39
+ expect(config.retryable_errors).to eq(["TestError"])
40
+ end
41
+ end
42
+
43
+ describe "retryable_error_limit" do
44
+ it "has a default" do
45
+ config = Emque::Consuming::Configuration.new
46
+ expect(config.retryable_error_limit).to eq(3)
47
+ end
48
+
49
+ it "prefers the assigned value" do
50
+ config = Emque::Consuming::Configuration.new
51
+ config.retryable_error_limit = 4
52
+ expect(config.retryable_error_limit).to eq(4)
53
+ end
54
+ end
55
+
17
56
  describe "#to_hsh" do
18
57
  it "returns a hash" do
19
58
  config = Emque::Consuming::Configuration.new
@@ -22,9 +61,11 @@ describe Emque::Consuming::Configuration do
22
61
 
23
62
  it "returns the value of all the accessors" do
24
63
  accessors = [
25
- :app_name, :auto_shutdown, :adapter, :env, :error_handlers,
26
- :error_limit, :error_expiration, :log_level, :status_port, :status_host,
27
- :status, :socket_path, :shutdown_handlers
64
+ :app_name, :adapter, :auto_shutdown, :delayed_message_workers,
65
+ :env, :enable_delayed_message, :error_handlers, :error_limit,
66
+ :error_expiration, :log_level, :retryable_errors,
67
+ :retryable_error_limit, :status_port, :status_host, :status,
68
+ :socket_path, :shutdown_handlers
28
69
  ]
29
70
  config = Emque::Consuming::Configuration.new
30
71
 
@@ -0,0 +1,18 @@
1
+ require "spec_helper"
2
+ require "emque/consuming/retryable_errors"
3
+
4
+ describe Emque::Consuming::RetryableErrors do
5
+ describe "retryable errors" do
6
+ it "exponentially backs off the delay time" do
7
+ test_class = Class.new { include Emque::Consuming::RetryableErrors }
8
+ test = test_class.new
9
+ retry1 = test.delay_ms_time(1)
10
+ retry2 = test.delay_ms_time(2)
11
+ retry3 = test.delay_ms_time(3)
12
+
13
+ expect(retry1).to eq(1000)
14
+ expect(retry2).to eq(4000)
15
+ expect(retry3).to eq(12000)
16
+ end
17
+ end
18
+ end
metadata CHANGED
@@ -1,7 +1,8 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: emque-consuming
3
3
  version: !ruby/object:Gem::Version
4
- version: 1.1.3
4
+ version: 1.2.0
5
+ prerelease:
5
6
  platform: ruby
6
7
  authors:
7
8
  - Ryan Williams
@@ -14,6 +15,7 @@ dependencies:
14
15
  - !ruby/object:Gem::Dependency
15
16
  name: celluloid
16
17
  requirement: !ruby/object:Gem::Requirement
18
+ none: false
17
19
  requirements:
18
20
  - - '='
19
21
  - !ruby/object:Gem::Version
@@ -21,6 +23,7 @@ dependencies:
21
23
  type: :runtime
22
24
  prerelease: false
23
25
  version_requirements: !ruby/object:Gem::Requirement
26
+ none: false
24
27
  requirements:
25
28
  - - '='
26
29
  - !ruby/object:Gem::Version
@@ -28,169 +31,193 @@ dependencies:
28
31
  - !ruby/object:Gem::Dependency
29
32
  name: dante
30
33
  requirement: !ruby/object:Gem::Requirement
34
+ none: false
31
35
  requirements:
32
- - - "~>"
36
+ - - ~>
33
37
  - !ruby/object:Gem::Version
34
38
  version: 0.2.0
35
39
  type: :runtime
36
40
  prerelease: false
37
41
  version_requirements: !ruby/object:Gem::Requirement
42
+ none: false
38
43
  requirements:
39
- - - "~>"
44
+ - - ~>
40
45
  - !ruby/object:Gem::Version
41
46
  version: 0.2.0
42
47
  - !ruby/object:Gem::Dependency
43
48
  name: oj
44
49
  requirement: !ruby/object:Gem::Requirement
50
+ none: false
45
51
  requirements:
46
- - - "~>"
52
+ - - ~>
47
53
  - !ruby/object:Gem::Version
48
54
  version: 2.11.4
49
55
  type: :runtime
50
56
  prerelease: false
51
57
  version_requirements: !ruby/object:Gem::Requirement
58
+ none: false
52
59
  requirements:
53
- - - "~>"
60
+ - - ~>
54
61
  - !ruby/object:Gem::Version
55
62
  version: 2.11.4
56
63
  - !ruby/object:Gem::Dependency
57
64
  name: virtus
58
65
  requirement: !ruby/object:Gem::Requirement
66
+ none: false
59
67
  requirements:
60
- - - "~>"
68
+ - - ~>
61
69
  - !ruby/object:Gem::Version
62
70
  version: '1.0'
63
71
  type: :runtime
64
72
  prerelease: false
65
73
  version_requirements: !ruby/object:Gem::Requirement
74
+ none: false
66
75
  requirements:
67
- - - "~>"
76
+ - - ~>
68
77
  - !ruby/object:Gem::Version
69
78
  version: '1.0'
70
79
  - !ruby/object:Gem::Dependency
71
80
  name: puma
72
81
  requirement: !ruby/object:Gem::Requirement
82
+ none: false
73
83
  requirements:
74
- - - "~>"
84
+ - - ~>
75
85
  - !ruby/object:Gem::Version
76
86
  version: 2.11.1
77
87
  type: :runtime
78
88
  prerelease: false
79
89
  version_requirements: !ruby/object:Gem::Requirement
90
+ none: false
80
91
  requirements:
81
- - - "~>"
92
+ - - ~>
82
93
  - !ruby/object:Gem::Version
83
94
  version: 2.11.1
84
95
  - !ruby/object:Gem::Dependency
85
96
  name: pipe-ruby
86
97
  requirement: !ruby/object:Gem::Requirement
98
+ none: false
87
99
  requirements:
88
- - - "~>"
100
+ - - ~>
89
101
  - !ruby/object:Gem::Version
90
102
  version: 0.2.0
91
103
  type: :runtime
92
104
  prerelease: false
93
105
  version_requirements: !ruby/object:Gem::Requirement
106
+ none: false
94
107
  requirements:
95
- - - "~>"
108
+ - - ~>
96
109
  - !ruby/object:Gem::Version
97
110
  version: 0.2.0
98
111
  - !ruby/object:Gem::Dependency
99
112
  name: inflecto
100
113
  requirement: !ruby/object:Gem::Requirement
114
+ none: false
101
115
  requirements:
102
- - - "~>"
116
+ - - ~>
103
117
  - !ruby/object:Gem::Version
104
118
  version: 0.0.2
105
119
  type: :runtime
106
120
  prerelease: false
107
121
  version_requirements: !ruby/object:Gem::Requirement
122
+ none: false
108
123
  requirements:
109
- - - "~>"
124
+ - - ~>
110
125
  - !ruby/object:Gem::Version
111
126
  version: 0.0.2
112
127
  - !ruby/object:Gem::Dependency
113
128
  name: bundler
114
129
  requirement: !ruby/object:Gem::Requirement
130
+ none: false
115
131
  requirements:
116
- - - "~>"
132
+ - - ~>
117
133
  - !ruby/object:Gem::Version
118
134
  version: '1.7'
119
135
  type: :development
120
136
  prerelease: false
121
137
  version_requirements: !ruby/object:Gem::Requirement
138
+ none: false
122
139
  requirements:
123
- - - "~>"
140
+ - - ~>
124
141
  - !ruby/object:Gem::Version
125
142
  version: '1.7'
126
143
  - !ruby/object:Gem::Dependency
127
144
  name: rake
128
145
  requirement: !ruby/object:Gem::Requirement
146
+ none: false
129
147
  requirements:
130
- - - "~>"
148
+ - - ~>
131
149
  - !ruby/object:Gem::Version
132
150
  version: 10.4.2
133
151
  type: :development
134
152
  prerelease: false
135
153
  version_requirements: !ruby/object:Gem::Requirement
154
+ none: false
136
155
  requirements:
137
- - - "~>"
156
+ - - ~>
138
157
  - !ruby/object:Gem::Version
139
158
  version: 10.4.2
140
159
  - !ruby/object:Gem::Dependency
141
160
  name: rspec
142
161
  requirement: !ruby/object:Gem::Requirement
162
+ none: false
143
163
  requirements:
144
- - - "~>"
164
+ - - ~>
145
165
  - !ruby/object:Gem::Version
146
166
  version: '3.3'
147
167
  type: :development
148
168
  prerelease: false
149
169
  version_requirements: !ruby/object:Gem::Requirement
170
+ none: false
150
171
  requirements:
151
- - - "~>"
172
+ - - ~>
152
173
  - !ruby/object:Gem::Version
153
174
  version: '3.3'
154
175
  - !ruby/object:Gem::Dependency
155
176
  name: bunny
156
177
  requirement: !ruby/object:Gem::Requirement
178
+ none: false
157
179
  requirements:
158
- - - "~>"
180
+ - - ~>
159
181
  - !ruby/object:Gem::Version
160
182
  version: '1.7'
161
183
  type: :development
162
184
  prerelease: false
163
185
  version_requirements: !ruby/object:Gem::Requirement
186
+ none: false
164
187
  requirements:
165
- - - "~>"
188
+ - - ~>
166
189
  - !ruby/object:Gem::Version
167
190
  version: '1.7'
168
191
  - !ruby/object:Gem::Dependency
169
192
  name: timecop
170
193
  requirement: !ruby/object:Gem::Requirement
194
+ none: false
171
195
  requirements:
172
- - - "~>"
196
+ - - ~>
173
197
  - !ruby/object:Gem::Version
174
198
  version: 0.7.1
175
199
  type: :development
176
200
  prerelease: false
177
201
  version_requirements: !ruby/object:Gem::Requirement
202
+ none: false
178
203
  requirements:
179
- - - "~>"
204
+ - - ~>
180
205
  - !ruby/object:Gem::Version
181
206
  version: 0.7.1
182
207
  - !ruby/object:Gem::Dependency
183
208
  name: daemon_controller
184
209
  requirement: !ruby/object:Gem::Requirement
210
+ none: false
185
211
  requirements:
186
- - - "~>"
212
+ - - ~>
187
213
  - !ruby/object:Gem::Version
188
214
  version: 1.2.0
189
215
  type: :development
190
216
  prerelease: false
191
217
  version_requirements: !ruby/object:Gem::Requirement
218
+ none: false
192
219
  requirements:
193
- - - "~>"
220
+ - - ~>
194
221
  - !ruby/object:Gem::Version
195
222
  version: 1.2.0
196
223
  description:
@@ -201,8 +228,8 @@ executables:
201
228
  extensions: []
202
229
  extra_rdoc_files: []
203
230
  files:
204
- - ".gitignore"
205
- - ".travis.yml"
231
+ - .gitignore
232
+ - .travis.yml
206
233
  - CHANGELOG.md
207
234
  - Gemfile
208
235
  - LICENSE.txt
@@ -215,8 +242,9 @@ files:
215
242
  - lib/emque/consuming/actor.rb
216
243
  - lib/emque/consuming/adapter.rb
217
244
  - lib/emque/consuming/adapters/rabbit_mq.rb
245
+ - lib/emque/consuming/adapters/rabbit_mq/delayed_message_worker.rb
246
+ - lib/emque/consuming/adapters/rabbit_mq/error_worker.rb
218
247
  - lib/emque/consuming/adapters/rabbit_mq/manager.rb
219
- - lib/emque/consuming/adapters/rabbit_mq/retry_worker.rb
220
248
  - lib/emque/consuming/adapters/rabbit_mq/worker.rb
221
249
  - lib/emque/consuming/application.rb
222
250
  - lib/emque/consuming/cli.rb
@@ -237,6 +265,7 @@ files:
237
265
  - lib/emque/consuming/logging.rb
238
266
  - lib/emque/consuming/message.rb
239
267
  - lib/emque/consuming/pidfile.rb
268
+ - lib/emque/consuming/retryable_errors.rb
240
269
  - lib/emque/consuming/router.rb
241
270
  - lib/emque/consuming/runner.rb
242
271
  - lib/emque/consuming/status.rb
@@ -264,32 +293,34 @@ files:
264
293
  - spec/dummy/config/routes.rb
265
294
  - spec/error_tracker_spec.rb
266
295
  - spec/pidfile_spec.rb
296
+ - spec/retryable_errors_spec.rb
267
297
  - spec/router_spec.rb
268
298
  - spec/runner_spec.rb
269
299
  - spec/spec_helper.rb
270
300
  homepage: https://github.com/teamsnap/emque-consuming
271
301
  licenses:
272
302
  - MIT
273
- metadata: {}
274
303
  post_install_message:
275
304
  rdoc_options: []
276
305
  require_paths:
277
306
  - lib
278
307
  required_ruby_version: !ruby/object:Gem::Requirement
308
+ none: false
279
309
  requirements:
280
- - - ">="
310
+ - - ! '>='
281
311
  - !ruby/object:Gem::Version
282
312
  version: '2.1'
283
313
  required_rubygems_version: !ruby/object:Gem::Requirement
314
+ none: false
284
315
  requirements:
285
- - - ">="
316
+ - - ! '>='
286
317
  - !ruby/object:Gem::Version
287
318
  version: '0'
288
319
  requirements: []
289
320
  rubyforge_project:
290
- rubygems_version: 2.2.2
321
+ rubygems_version: 1.8.23
291
322
  signing_key:
292
- specification_version: 4
323
+ specification_version: 3
293
324
  summary: Microservices framework for Ruby
294
325
  test_files:
295
326
  - spec/application_spec.rb
@@ -304,6 +335,7 @@ test_files:
304
335
  - spec/dummy/config/routes.rb
305
336
  - spec/error_tracker_spec.rb
306
337
  - spec/pidfile_spec.rb
338
+ - spec/retryable_errors_spec.rb
307
339
  - spec/router_spec.rb
308
340
  - spec/runner_spec.rb
309
341
  - spec/spec_helper.rb
checksums.yaml DELETED
@@ -1,7 +0,0 @@
1
- ---
2
- SHA1:
3
- metadata.gz: 12f58267d541cb53c2dcd731663e1c19da52c801
4
- data.tar.gz: c9555bff3fc2315e542cd637d4d2a4f387895169
5
- SHA512:
6
- metadata.gz: 9fce1adb82ccb832409b252e1ed3d2741fc80ae8e4706cac533bd594141915b10d98a3aacef168fc145e3f95170c3e9ef5675d402bad1a46b4651e069b4012fc
7
- data.tar.gz: d0d287ed1519c23dcccc52bf9cc1dd3641af322d0ba1f47382a4fcc529321eb1251c714394bf3a5cf575d545bfc45d78dfad59b309683ae87dc907eb2f22c661