emque-consuming 1.1.3 → 1.2.0

Sign up to get free protection for your applications and to get access to all the features.
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