hanami-events-cloud_pubsub 2.9.0 → 3.0.0

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
  SHA256:
3
- metadata.gz: a5ffe95cabc82141bd06ee9514ad0af66aaba9c5ebc719190e7cc9efba855274
4
- data.tar.gz: 119b219d3294f50b37a13daa36a4a55edf0d85f5ac14e82676fee3cad62f135a
3
+ metadata.gz: fd0a13431ee107060d1d5df6dac57392e421053f13e58dc9d7144bb01008be12
4
+ data.tar.gz: d71e132eee40d004bf01827de7b5782ae1ca77b909fd884288bb0fc84f6d9a30
5
5
  SHA512:
6
- metadata.gz: a3475491db3dab17ab2fd423c056dca407977321223bd457903b3773bdbd7ef9080b2446e70305e8e64f136d6bd434c157b90ae72bd48f91bd388cb060005ee3
7
- data.tar.gz: 93bd30e26d6a85281f21dfd394f6aa7ea41a340459426f8b280f798e56b1fb3dc857390e6384e8d4605a286cbd313174eab2207e971e0c02374663cd91180744
6
+ metadata.gz: 5740b2f509eca29b70870b32adf7508bdc776a9d2efea0c41540fef600d26464eed902752b8095d5e3f028a04a08d5b13f7bc4b8ad313d24c008b96973542a8e
7
+ data.tar.gz: e75c53c924ab42ca5db76d02217e2e2f82ce83f1ae6e63e85640cfab894380282bca5bad9deeabb64970d88d2788ceaf5aec09999af4d8e8342ec5eac46180fe
@@ -2,9 +2,10 @@
2
2
  inherit_from: .rubocop_todo.yml
3
3
 
4
4
  AllCops:
5
+ NewCops: enable
5
6
  Exclude:
6
7
  - bin/*
7
- TargetRubyVersion: 2.4
8
+ TargetRubyVersion: 2.5
8
9
 
9
10
  Metrics/BlockLength:
10
11
  Exclude:
@@ -1,13 +1,24 @@
1
1
  # This configuration was generated by
2
2
  # `rubocop --auto-gen-config`
3
- # on 2019-10-30 15:26:46 -0400 using RuboCop version 0.72.0.
3
+ # on 2020-09-25 19:54:44 UTC using RuboCop version 0.89.0.
4
4
  # The point is for the user to remove these configuration records
5
5
  # one by one as the offenses are removed from the code base.
6
6
  # Note that changes in the inspected code, or installation of new
7
7
  # versions of RuboCop, may require this file to be generated again.
8
8
 
9
- # Offense count: 1
10
- # Configuration parameters: CountComments, ExcludedMethods.
9
+ # Offense count: 2
10
+ # Cop supports --auto-correct.
11
+ Lint/RedundantCopDisableDirective:
12
+ Exclude:
13
+ - 'lib/hanami/events/adapter/cloud_pubsub.rb'
14
+
15
+ # Offense count: 3
16
+ # Configuration parameters: IgnoredMethods.
17
+ Metrics/AbcSize:
18
+ Max: 21
19
+
20
+ # Offense count: 4
21
+ # Configuration parameters: CountComments, CountAsOne, ExcludedMethods.
11
22
  Metrics/MethodLength:
12
23
  Max: 14
13
24
 
@@ -16,10 +27,3 @@ Metrics/MethodLength:
16
27
  Style/GlobalVars:
17
28
  Exclude:
18
29
  - 'examples/server.rb'
19
-
20
- # Offense count: 35
21
- # Cop supports --auto-correct.
22
- # Configuration parameters: AutoCorrect, AllowHeredoc, AllowURI, URISchemes, IgnoreCopDirectives, IgnoredPatterns.
23
- # URISchemes: http, https
24
- Metrics/LineLength:
25
- Max: 96
@@ -8,9 +8,10 @@ GIT
8
8
  PATH
9
9
  remote: .
10
10
  specs:
11
- hanami-events-cloud_pubsub (2.9.0)
11
+ hanami-events-cloud_pubsub (3.0.0)
12
12
  dry-configurable (>= 0.8)
13
- google-cloud-pubsub (>= 0.38.1, < 1.7)
13
+ gapic-common (>= 0.3.4)
14
+ google-cloud-pubsub (>= 0.38.1, < 2.1)
14
15
  hanami-cli (~> 0.2)
15
16
  hanami-events (~> 0.2.0)
16
17
  rack
@@ -37,26 +38,27 @@ GEM
37
38
  dry-equalizer (0.3.0)
38
39
  faraday (1.0.1)
39
40
  multipart-post (>= 1.2, < 3)
41
+ gapic-common (0.3.4)
42
+ google-protobuf (~> 3.12, >= 3.12.2)
43
+ googleapis-common-protos (>= 1.3.9, < 2.0)
44
+ googleapis-common-protos-types (>= 1.0.4, < 2.0)
45
+ googleauth (~> 0.9)
46
+ grpc (~> 1.25)
40
47
  google-cloud-core (1.5.0)
41
48
  google-cloud-env (~> 1.0)
42
49
  google-cloud-errors (~> 1.0)
43
50
  google-cloud-env (1.3.3)
44
51
  faraday (>= 0.17.3, < 2.0)
45
52
  google-cloud-errors (1.0.1)
46
- google-cloud-pubsub (1.6.1)
53
+ google-cloud-pubsub (2.0.0)
47
54
  concurrent-ruby (~> 1.1)
48
- google-cloud-core (~> 1.2)
49
- google-gax (~> 1.8)
50
- googleapis-common-protos (>= 1.3.9, < 2.0)
51
- googleapis-common-protos-types (>= 1.0.4, < 2.0)
52
- grpc-google-iam-v1 (~> 0.6.9)
53
- google-gax (1.8.1)
54
- google-protobuf (~> 3.9)
55
- googleapis-common-protos (>= 1.3.9, < 2.0)
56
- googleauth (~> 0.9)
57
- grpc (~> 1.24)
58
- rly (~> 0.2.3)
59
- google-protobuf (3.12.4)
55
+ google-cloud-core (~> 1.5)
56
+ google-cloud-pubsub-v1 (~> 0.0)
57
+ google-cloud-pubsub-v1 (0.1.2)
58
+ gapic-common (~> 0.3)
59
+ google-cloud-errors (~> 1.0)
60
+ grpc-google-iam-v1 (>= 0.6.10, < 2.0)
61
+ google-protobuf (3.13.0)
60
62
  googleapis-common-protos (1.3.10)
61
63
  google-protobuf (~> 3.11)
62
64
  googleapis-common-protos-types (>= 1.0.5, < 2.0)
@@ -70,8 +72,8 @@ GEM
70
72
  multi_json (~> 1.11)
71
73
  os (>= 0.9, < 2.0)
72
74
  signet (~> 0.14)
73
- grpc (1.30.2)
74
- google-protobuf (~> 3.12)
75
+ grpc (1.32.0)
76
+ google-protobuf (~> 3.13)
75
77
  googleapis-common-protos-types (~> 1.0)
76
78
  grpc-google-iam-v1 (0.6.10)
77
79
  google-protobuf (~> 3.11)
@@ -83,7 +85,7 @@ GEM
83
85
  hanami-utils (1.3.6)
84
86
  concurrent-ruby (~> 1.0)
85
87
  transproc (~> 1.0)
86
- jwt (2.2.1)
88
+ jwt (2.2.2)
87
89
  memoist (0.16.2)
88
90
  method_source (1.0.0)
89
91
  multi_json (1.15.0)
@@ -96,14 +98,13 @@ GEM
96
98
  pry (0.13.1)
97
99
  coderay (~> 1.1)
98
100
  method_source (~> 1.0)
99
- public_suffix (4.0.5)
101
+ public_suffix (4.0.6)
100
102
  rack (2.2.3)
101
103
  rainbow (3.0.0)
102
104
  rake (13.0.1)
103
105
  regexp_parser (1.7.1)
104
106
  request_id (0.4.3)
105
107
  rexml (3.2.4)
106
- rly (0.2.3)
107
108
  rspec (3.9.0)
108
109
  rspec-core (~> 3.9.0)
109
110
  rspec-expectations (~> 3.9.0)
@@ -12,7 +12,7 @@ Hanami::Events::CloudPubsub.setup
12
12
 
13
13
  pubsub = Google::Cloud::Pubsub.new project_id: 'emulator'
14
14
 
15
- events = Hanami::Events.initialize(:cloud_pubsub, pubsub: pubsub, logger: Logger.new(STDOUT))
15
+ events = Hanami::Events.initialize(:cloud_pubsub, pubsub: pubsub, logger: Logger.new($stdout))
16
16
 
17
17
  3.times do
18
18
  events.broadcast('user.deleted', user_id: 1)
@@ -4,6 +4,8 @@ Hanami::Events::CloudPubsub.configure do |config|
4
4
  config.subscriber.streams = 2
5
5
  config.subscriber.threads.push = 2
6
6
  config.subscriber.threads.callback = 2
7
+ config.auto_retry.enabled = true
8
+ config.auto_retry.dead_letter_topic_name = 'my-dead-letter-topic-name'
7
9
 
8
10
  config.subscriptions_loader = -> do
9
11
  $events.subscribe('user.deleted', id: 'testing-2') do |payload|
@@ -15,6 +15,8 @@ Gem::Specification.new do |spec|
15
15
  spec.homepage = 'https://github.com/adHawk/hanami-events-cloud_pubsub'
16
16
  spec.license = 'MIT'
17
17
 
18
+ spec.required_ruby_version = '>= 2.5.0'
19
+
18
20
  spec.files = `git ls-files -z`.split("\x0").reject do |f|
19
21
  f.match(%r{^(test|spec|features)/})
20
22
  end
@@ -23,7 +25,8 @@ Gem::Specification.new do |spec|
23
25
  spec.require_paths = ['lib']
24
26
 
25
27
  spec.add_dependency 'dry-configurable', '>= 0.8'
26
- spec.add_dependency 'google-cloud-pubsub', '>= 0.38.1', '< 1.7'
28
+ spec.add_dependency 'gapic-common', '>= 0.3.4'
29
+ spec.add_dependency 'google-cloud-pubsub', '>= 0.38.1', '< 2.1'
27
30
  spec.add_dependency 'hanami-cli', '~> 0.2'
28
31
  spec.add_dependency 'hanami-events', '~> 0.2.0'
29
32
  spec.add_dependency 'rack'
@@ -15,7 +15,7 @@ module Hanami
15
15
 
16
16
  def initialize(params)
17
17
  @pubsub = params[:pubsub]
18
- @logger = params[:logger] || Logger.new(STDOUT)
18
+ @logger = params[:logger] || Logger.new($stdout)
19
19
  @listen = params[:listen] || false
20
20
  @subscribers = Concurrent::Array.new
21
21
  @listeners = Concurrent::Array.new
@@ -29,15 +29,21 @@ module Hanami
29
29
  #
30
30
  # @param event [Symbol, String] the event name
31
31
  # @param payload [Hash] the event data
32
- def broadcast(name, payload, **message_opts)
32
+ def broadcast(name, input_payload, **message_opts)
33
33
  event_name = namespaced(name)
34
34
  topic = topic_for event_name
35
- payload = serializer.serialize(payload)
36
- attributes = { id: SecureRandom.uuid, event_name: event_name }
37
-
38
- middleware.invoke(payload, **attributes, **message_opts) do |*args|
39
- topic.publish_async(*args) do |result|
40
- logger.info "Published event #{result.inspect}"
35
+ serialized_payload = serializer.serialize(input_payload)
36
+ attrs = { id: SecureRandom.uuid, event_name: event_name }
37
+
38
+ middleware.invoke(serialized_payload, **attrs, **message_opts) do |payload, **opts|
39
+ topic.publish_async(payload, **opts) do |result|
40
+ msg = result.message.grpc.to_h
41
+
42
+ if result.succeeded?
43
+ logger.info "Published #{name.inspect} published", **msg
44
+ else
45
+ logger.warn "Failed to broadcast #{name.inspect} event", error: result.error, **msg # rubocop:disable Layout/LineLength
46
+ end
41
47
  end
42
48
  end
43
49
  end
@@ -77,7 +83,8 @@ module Hanami
77
83
  handler: method(:call_subscribers),
78
84
  logger: logger,
79
85
  topic: topic,
80
- subscriber_opts: subscriber_opts
86
+ subscriber_opts: subscriber_opts,
87
+ dead_letter_topic: dead_letter_topic
81
88
  )
82
89
 
83
90
  @listeners << listener
@@ -98,7 +105,7 @@ module Hanami
98
105
  @serializer ||= Hanami::Events::Serializer[@serializer_type].new
99
106
  end
100
107
 
101
- # rubocop:disable Metrics/LineLength
108
+ # rubocop:disable Layout/LineLength
102
109
  def topic_for(name)
103
110
  return @topic_registry[name.to_s] if @topic_registry[name.to_s]
104
111
 
@@ -110,7 +117,15 @@ module Hanami
110
117
 
111
118
  @topic_registry[name.to_s] = topic
112
119
  end
113
- # rubocop:enable Metrics/LineLength
120
+ # rubocop:enable Layout/LineLength
121
+
122
+ def dead_letter_topic
123
+ conf = Hanami::Events::CloudPubsub.config.auto_retry
124
+
125
+ return unless conf.enabled
126
+
127
+ topic_for namespaced(conf.dead_letter_topic_name)
128
+ end
114
129
 
115
130
  def namespaced(val, sep: '.')
116
131
  [Hanami::Events::CloudPubsub.namespace, val].compact.join(sep)
@@ -5,7 +5,6 @@ require 'hanami/events'
5
5
  require 'hanami/events/cloud_pubsub/version'
6
6
  require 'hanami/events/cloud_pubsub/middleware/stack'
7
7
  require 'hanami/events/cloud_pubsub/middleware/logging'
8
- require 'hanami/events/cloud_pubsub/middleware/auto_retry'
9
8
  require 'hanami/events/cloud_pubsub/runner'
10
9
  require 'hanami/events/cloud_pubsub/errors'
11
10
  require 'google/cloud/pubsub'
@@ -32,7 +31,7 @@ module Hanami
32
31
  setting :project_id, reader: true
33
32
  setting :auto_create_subscriptions, false, reader: true
34
33
  setting :auto_create_topics, false, reader: true
35
- setting :logger, Logger.new(STDOUT), reader: true
34
+ setting :logger, Logger.new($stdout), reader: true
36
35
  setting :subscriptions_loader, proc {
37
36
  abort <<~MSG
38
37
  ┌────────────────────────────────────────────────────────────────────────────────┐
@@ -58,8 +57,7 @@ module Hanami
58
57
  ], reader: true
59
58
 
60
59
  middleware_stack = Middleware::Stack.new(
61
- Middleware::Logging.new,
62
- Middleware::AutoRetry.new
60
+ Middleware::Logging.new
63
61
  )
64
62
 
65
63
  begin
@@ -89,6 +87,14 @@ module Hanami
89
87
 
90
88
  setting :on_shutdown_handlers, [], reader: true
91
89
 
90
+ setting :auto_retry do
91
+ setting :enabled, false
92
+ setting :max_attempts, 1200
93
+ setting :dead_letter_topic_name
94
+ setting :minimum_backoff, 30
95
+ setting :maximum_backoff, 600
96
+ end
97
+
92
98
  def self.finalize_settings!
93
99
  conf_hash = config.pubsub
94
100
  conf_hash.each { |key, val| Google::Cloud::Pubsub.configure[key] = val }
@@ -102,8 +102,8 @@ module Hanami
102
102
  end
103
103
 
104
104
  def shutdown
105
- STDOUT.flush
106
- STDERR.flush
105
+ $stdout.flush
106
+ $stderr.flush
107
107
  runner.gracefully_shutdown
108
108
  ensure
109
109
  @finished_shutting_down = true
@@ -5,6 +5,7 @@ require 'hanami/events/cloud_pubsub/safe_error_handler'
5
5
  module Hanami
6
6
  module Events
7
7
  module CloudPubsub
8
+ # rubocop:disable Metrics/ClassLength:
8
9
  # @api private
9
10
  class Listener
10
11
  attr_reader :topic,
@@ -13,8 +14,10 @@ module Hanami
13
14
  :logger,
14
15
  :handler,
15
16
  :event_name,
16
- :subscriber_opts,
17
- :middleware
17
+ :input_subscriber_opts,
18
+ :middleware,
19
+ :dead_letter_topic
20
+
18
21
  # rubocop:disable Metrics/ParameterLists
19
22
  def initialize(topic:,
20
23
  logger:,
@@ -22,25 +25,24 @@ module Hanami
22
25
  event_name:,
23
26
  subscriber_id:,
24
27
  subscriber_opts: {},
25
- middleware: CloudPubsub.config.middleware)
28
+ middleware: CloudPubsub.config.middleware,
29
+ dead_letter_topic: nil)
26
30
  @topic = topic
27
31
  @logger = logger
28
32
  @handler = handler
29
33
  @event_name = event_name
30
34
  @subscriber_id = subscriber_id
31
- @subscriber_opts = CloudPubsub.config.subscriber.to_h.merge(subscriber_opts)
35
+ @input_subscriber_opts = subscriber_opts
32
36
  @middleware = middleware
37
+ @dead_letter_topic = dead_letter_topic
33
38
  end
34
39
  # rubocop:enable Metrics/ParameterLists
35
40
 
36
41
  def register
37
42
  subscription = subscription_for(subscriber_id)
38
-
39
- listener = subscription.listen(**subscriber_opts) do |message|
40
- handle_message(message)
41
- end
42
-
43
- logger.debug("Registered listener for #{subscriber_id} with opts #{subscriber_opts}")
43
+ apply_retry_options(subscription)
44
+ listener = subscription.listen(**subscriber_options) { |m| handle_message(m) }
45
+ logger.debug("Registered listener for #{subscriber_id} with: #{subscriber_options}")
44
46
 
45
47
  @subscriber = listener
46
48
 
@@ -86,6 +88,8 @@ module Hanami
86
88
  rescue StandardError => e
87
89
  run_error_handlers(e, message)
88
90
  raise
91
+ ensure
92
+ message.nack! if CloudPubsub.config.auto_retry.enabled
89
93
  end
90
94
 
91
95
  def subscription_for(name)
@@ -120,7 +124,28 @@ module Hanami
120
124
  "a subscription already exists for #{sub_name} " \
121
125
  "but its name #{found_subscription.topic.name} does not match #{@event_name}"
122
126
  end
127
+
128
+ def subscriber_options
129
+ @subscriber_options ||= {
130
+ **CloudPubsub.config.subscriber.to_h,
131
+ **input_subscriber_opts
132
+ }
133
+ end
134
+
135
+ def apply_retry_options(sub)
136
+ return {} unless CloudPubsub.config.auto_retry.enabled
137
+
138
+ sub.retry_policy = Google::Cloud::PubSub::RetryPolicy.new(
139
+ minimum_backoff: CloudPubsub.config.auto_retry.minimum_backoff,
140
+ maximum_backoff: CloudPubsub.config.auto_retry.maximum_backoff
141
+ )
142
+ sub.dead_letter_topic = dead_letter_topic
143
+ sub.dead_letter_max_delivery_attempts = CloudPubsub.config.auto_retry.max_attempts
144
+
145
+ sub
146
+ end
123
147
  end
148
+ # rubocop:enable Metrics/ClassLength:
124
149
  end
125
150
  end
126
151
  end
@@ -40,14 +40,14 @@ module Hanami
40
40
  @entries.shift
41
41
  end
42
42
 
43
- def invoke(*args)
43
+ def invoke(*args, **kwargs)
44
44
  stack = entries.dup
45
45
 
46
46
  traverse_stack = proc do |**opts|
47
47
  if stack.empty?
48
- yield(*args)
48
+ yield(*args, **kwargs, **opts)
49
49
  else
50
- stack.shift.call(*args, **opts, &traverse_stack)
50
+ stack.shift.call(*args, **kwargs, **opts, &traverse_stack)
51
51
  end
52
52
  end
53
53
 
@@ -86,13 +86,12 @@ module Hanami
86
86
  # some reason.
87
87
  #
88
88
  # See: https://github.com/mperham/sidekiq/blob/e447dae961ebc894f12848d9f33446a07ffc67dc/bin/sidekiqload#L74
89
- # rubocop:disable Metrics/AbcSize
90
89
  def debug_info
91
90
  <<~MSG
92
91
  ╔══════ BACKTRACES
93
92
  #{Thread.list.flat_map { |thr| ThreadInspector.new(thr).to_s }.join("\n")}
94
93
  ╠══════ LISTENERS
95
- #{adapter.listeners.map { |lis| '' + lis.format }.join("\n")}
94
+ #{adapter.listeners.map { |lis| "#{lis.format}" }.join("\n")}
96
95
 
97
96
  ╠══════ GENERAL
98
97
  ║ ready?: #{ready?}
@@ -102,7 +101,6 @@ module Hanami
102
101
  ╚══════
103
102
  MSG
104
103
  end
105
- # rubocop:enable Metrics/AbcSize
106
104
 
107
105
  def sleep_for_a_bit
108
106
  sleep @sleep_time
@@ -114,11 +112,9 @@ module Hanami
114
112
  logger.info('Calling custom on_shutdown handler')
115
113
 
116
114
  CloudPubsub.on_shutdown_handlers.each do |handler|
117
- begin
118
- handler.call(adapter)
119
- rescue StandardError => e
120
- logger.warn("Shutdown handler failed (#{e.message})")
121
- end
115
+ handler.call(adapter)
116
+ rescue StandardError => e
117
+ logger.warn("Shutdown handler failed (#{e.message})")
122
118
  end
123
119
  end
124
120
  end
@@ -48,7 +48,7 @@ module Hanami
48
48
  end
49
49
 
50
50
  def join_backtrace(pretty_backtrace)
51
- pretty_backtrace.map! { |line| "║\t" + line }
51
+ pretty_backtrace.map! { |line| "║\t#{line}" }
52
52
  pretty_backtrace << '║'
53
53
  pretty_backtrace.join("\n")
54
54
  end
@@ -3,7 +3,7 @@
3
3
  module Hanami
4
4
  module Events
5
5
  module CloudPubsub
6
- VERSION = '2.9.0'
6
+ VERSION = '3.0.0'
7
7
  end
8
8
  end
9
9
  end
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: hanami-events-cloud_pubsub
3
3
  version: !ruby/object:Gem::Version
4
- version: 2.9.0
4
+ version: 3.0.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Ian Ker-Seymer
8
- autorequire:
8
+ autorequire:
9
9
  bindir: exe
10
10
  cert_chain: []
11
- date: 2020-08-06 00:00:00.000000000 Z
11
+ date: 2020-09-25 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: dry-configurable
@@ -24,6 +24,20 @@ dependencies:
24
24
  - - ">="
25
25
  - !ruby/object:Gem::Version
26
26
  version: '0.8'
27
+ - !ruby/object:Gem::Dependency
28
+ name: gapic-common
29
+ requirement: !ruby/object:Gem::Requirement
30
+ requirements:
31
+ - - ">="
32
+ - !ruby/object:Gem::Version
33
+ version: 0.3.4
34
+ type: :runtime
35
+ prerelease: false
36
+ version_requirements: !ruby/object:Gem::Requirement
37
+ requirements:
38
+ - - ">="
39
+ - !ruby/object:Gem::Version
40
+ version: 0.3.4
27
41
  - !ruby/object:Gem::Dependency
28
42
  name: google-cloud-pubsub
29
43
  requirement: !ruby/object:Gem::Requirement
@@ -33,7 +47,7 @@ dependencies:
33
47
  version: 0.38.1
34
48
  - - "<"
35
49
  - !ruby/object:Gem::Version
36
- version: '1.7'
50
+ version: '2.1'
37
51
  type: :runtime
38
52
  prerelease: false
39
53
  version_requirements: !ruby/object:Gem::Requirement
@@ -43,7 +57,7 @@ dependencies:
43
57
  version: 0.38.1
44
58
  - - "<"
45
59
  - !ruby/object:Gem::Version
46
- version: '1.7'
60
+ version: '2.1'
47
61
  - !ruby/object:Gem::Dependency
48
62
  name: hanami-cli
49
63
  requirement: !ruby/object:Gem::Requirement
@@ -178,7 +192,6 @@ files:
178
192
  - lib/hanami/events/cloud_pubsub/health_check_server.rb
179
193
  - lib/hanami/events/cloud_pubsub/integration.rb
180
194
  - lib/hanami/events/cloud_pubsub/listener.rb
181
- - lib/hanami/events/cloud_pubsub/middleware/auto_retry.rb
182
195
  - lib/hanami/events/cloud_pubsub/middleware/client/request_id.rb
183
196
  - lib/hanami/events/cloud_pubsub/middleware/logging.rb
184
197
  - lib/hanami/events/cloud_pubsub/middleware/prometheus.rb
@@ -195,7 +208,7 @@ homepage: https://github.com/adHawk/hanami-events-cloud_pubsub
195
208
  licenses:
196
209
  - MIT
197
210
  metadata: {}
198
- post_install_message:
211
+ post_install_message:
199
212
  rdoc_options: []
200
213
  require_paths:
201
214
  - lib
@@ -203,7 +216,7 @@ required_ruby_version: !ruby/object:Gem::Requirement
203
216
  requirements:
204
217
  - - ">="
205
218
  - !ruby/object:Gem::Version
206
- version: '0'
219
+ version: 2.5.0
207
220
  required_rubygems_version: !ruby/object:Gem::Requirement
208
221
  requirements:
209
222
  - - ">="
@@ -211,7 +224,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
211
224
  version: '0'
212
225
  requirements: []
213
226
  rubygems_version: 3.1.2
214
- signing_key:
227
+ signing_key:
215
228
  specification_version: 4
216
229
  summary: Google Cloud Pub/Sub adapter for the hanami-events gem
217
230
  test_files: []
@@ -1,93 +0,0 @@
1
- # frozen_string_literal: true
2
-
3
- module Hanami
4
- module Events
5
- module CloudPubsub
6
- # Middleware
7
- module Middleware
8
- # Middleware used for automatically acknowledging messages
9
- class AutoRetry
10
- attr_reader :max_attempts
11
-
12
- def initialize(logger: nil, max_attempts: 1200)
13
- @logger = logger
14
- @max_attempts = max_attempts
15
- end
16
-
17
- def call(message, **args)
18
- succeeded = false
19
- failed = false
20
- yield(**args)
21
- succeeded = true
22
- rescue StandardError => e
23
- failed = true
24
- raise e
25
- ensure
26
- ack_or_reject(message, succeeded, failed, args)
27
- end
28
-
29
- private
30
-
31
- def ack_or_reject(message, succeeded, failed, args)
32
- if succeeded
33
- handle_success(message, args)
34
- elsif failed && max_attempts_reached?(args)
35
- handle_max_attempts_reached(message, args)
36
- elsif failed
37
- handle_failure(message, args)
38
- else
39
- handle_unfinished(message, args)
40
- end
41
- end
42
-
43
- def handle_success(message, _args)
44
- message.acknowledge!
45
- logger.debug "Message(#{message.message_id}) was acknowledged"
46
- end
47
-
48
- def max_attempts_reached?(args)
49
- args.key?(:attempts) && args[:attempts] >= max_attempts
50
- end
51
-
52
- def handle_max_attempts_reached(message, _args)
53
- id = message.message_id
54
- msg = 'number of attempts exceeded max attempts ' \
55
- "of #{max_attempts}, acknowledging message"
56
- logger.debug "Message(#{id}) failed, #{msg}"
57
- message.acknowledge!
58
- end
59
-
60
- def handle_failure(message, args)
61
- id = message.message_id
62
- seconds = calculate_backoff_seconds(message, args)
63
- success = message.modify_ack_deadline!(seconds)
64
- msg = "added #{success ? seconds : 0} seconds of delay to ack deadline"
65
- logger.debug "Message(#{id}) failed, #{msg}" if success
66
- end
67
-
68
- def handle_unfinished(message, _args)
69
- id = message.message_id
70
- message.reject!
71
- logger.warn "Message(#{id}) was terminated from outside, rescheduling"
72
- end
73
-
74
- def logger
75
- @logger || CloudPubsub.logger
76
- end
77
-
78
- def calculate_backoff_seconds(_message, args)
79
- amt = if args.key?(:attempts)
80
- count = args[:attempts]
81
- # min + exponential + random smear
82
- 15 + count**4 + (rand(30) * (count + 1))
83
- else
84
- 60
85
- end
86
-
87
- amt > 600 ? 600 : amt
88
- end
89
- end
90
- end
91
- end
92
- end
93
- end