hermes_messenger_of_the_gods 2.1.1 → 2.3.1

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
  SHA256:
3
- metadata.gz: c9fb8caf1a8299a378495d5f33f4be6e226725ceb3d9a2bfca2ee301ddfa74b2
4
- data.tar.gz: 20ae2dedfc73f959bbb8705c398a293bb105d4f3362e1b33c62a0bf00705c7e4
3
+ metadata.gz: 604daff161d76c0ebf41ab253989906c75c519aba9460282fc0644a3b3ed1cad
4
+ data.tar.gz: 201cda28475512177767a542e0c13f15780431dbc8cfd45f324425bccecc090c
5
5
  SHA512:
6
- metadata.gz: 82d1ef250df05d7630816d9c02fb1cc35024d101d82263b213762336110daaef10cc33d6b84ced72eb3a712981e75ffc1ad5aa0327081a8c46ebfc1cd60ffb86
7
- data.tar.gz: 0b618c1608e636d4afb210fe3cafa8bd0786a8e0c74da0f14b5ad10067c0b6293f2b495d283c9c016abcc2fb63b3dfbeb56d69d5b8fac28405e108eb30f3d66d
6
+ metadata.gz: 607884c3e2d370128952cd2a832686dbaeade734ae3580143a677715d388faf47dc620049252e07230c7f920e64db09a4b30b2c8ee08c85a4e5a2a667bd7595d
7
+ data.tar.gz: a627e353104644dce6b85e0fb8dee0e6fe821742c2b29c3662140241c968cf0335991fe146143fd777460bd22b086f03dc1852249cdf64836f2d5b0b8816b071
@@ -31,6 +31,7 @@ jobs:
31
31
  COVERALLS_NOISY=true bundle exec rspec --color --format documentation;"
32
32
 
33
33
  - name: Push Coveralls
34
+ continue-on-error: true
34
35
  env:
35
36
  TOKEN: ${{ secrets.COVERALLS_TOKEN }}
36
37
  working-directory: ${{ github.workspace }}/src/github.com/${{ github.repository }}
data/.gitignore CHANGED
@@ -10,3 +10,4 @@
10
10
  # rspec failure tracking
11
11
  .rspec_status
12
12
  .bundle
13
+ *.gem
@@ -61,7 +61,7 @@ module HermesMessengerOfTheGods
61
61
  endpoints.collect do |ep_name, endpoint|
62
62
  next if targeted_endpoints && !targeted_endpoints.include?(ep_name)
63
63
 
64
- Thread.new do
64
+ begin
65
65
  endpoint.dispatch!(self, endpoint_args) unless HermesMessengerOfTheGods.config.stub_dispatch
66
66
  register_success(ep_name, endpoint.result)
67
67
  rescue StandardError => e
@@ -70,7 +70,7 @@ module HermesMessengerOfTheGods
70
70
  ensure
71
71
  endpoint.teardown
72
72
  end
73
- end.compact.map(&:join)
73
+ end
74
74
 
75
75
  unless dispatch_errors.empty?
76
76
  klass = if successes.empty?
@@ -32,6 +32,9 @@ module HermesMessengerOfTheGods
32
32
  def work_off
33
33
  WorkerStatusServer.start!(worker: self) if health_check_enabled?
34
34
 
35
+ trap(:TERM) { endpoint.shutdown! }
36
+ trap(:INT) { endpoint.shutdown! }
37
+
35
38
  instrument(:starting)
36
39
  self.consecutive_failures = 0
37
40
  endpoint.work_off do |job, original_message|
@@ -10,21 +10,63 @@ module HermesMessengerOfTheGods
10
10
  VISIBILITY_EXTEND_DURATION = 120
11
11
  VISIBILITY_EXTEND_FREQUENCY = 60
12
12
 
13
+ def initialize(*args)
14
+ super
15
+ @message_mux = Monitor.new
16
+ end
17
+
13
18
  def poller
14
19
  @poller ||= Aws::SQS::QueuePoller.new(endpoint)
15
20
  end
16
21
 
22
+ def inflight_messages
23
+ @message_mux.synchronize { @inflight_messages ||= [] }
24
+ end
25
+
26
+ def inflight_messages=(val)
27
+ @message_mux.synchronize { @inflight_messages = val }
28
+ end
29
+
30
+ def shutting_down?
31
+ @shutdown || false
32
+ end
33
+
34
+ # Basic Shutdown behavior:
35
+ # Allow in-progress message to finish working.
36
+ # Reset visbility timeout to all un-executed messages (from current message to end of array) to 0 so they move
37
+ # to other works
38
+ #
39
+ # Break from polling
40
+ def shutdown!
41
+ say Logger::INFO, 'Shutdown command received'
42
+ @shutdown = true
43
+ end
44
+
17
45
  def poll_options
18
46
  (options[:poll_options] || {}).merge(skip_delete: true)
19
47
  end
20
48
 
21
49
  def work_off(&blk)
22
- poller.poll(poll_options) do |messages, _stats|
23
- messages = Array.wrap(messages)
50
+ poller.before_request { |_stats| throw :stop_polling if shutting_down? }
24
51
 
25
- working_messages(messages) do
26
- completed = messages.select { |msg| work_message(msg, &blk) }
27
- poller.delete_messages(completed) unless completed.empty?
52
+ poller.poll(poll_options) do |messages, _stats|
53
+ self.inflight_messages = messages = Array.wrap(messages)
54
+
55
+ working_messages do
56
+ completion_results = messages.group_by do |msg|
57
+ # We return false if we are shutting down so the messages are not deleted.
58
+ # It is also possible that this process has already releases these SQS messages
59
+ # back in to the queue so they may be picked up by another process.
60
+ #
61
+ # Work message returns true if the messager should be considered successful
62
+ shutting_down? ? :shutdown : work_message(msg, &blk)
63
+ end
64
+
65
+ poller.delete_messages(completion_results[true]) unless completion_results.fetch(true, []).empty?
66
+ # Messages skipped due to shutdowns get their visibility set back to 0 so they restart
67
+ # normal failed jobs will be left in queue until their visibility timeout expires to indicate a backoff
68
+ set_message_visibility(completion_results[:shutdown], 0) unless completion_results.fetch(:shutdown,
69
+ []).empty?
28
70
  end
29
71
  end
30
72
  end
@@ -54,9 +96,9 @@ module HermesMessengerOfTheGods
54
96
  def has_pending_work?
55
97
  data = queue_data.attributes
56
98
 
57
- approximate_pending_messages = data["ApproximateNumberOfMessages"].to_i -
58
- data["ApproximateNumberOfMessagesNotVisible"].to_i -
59
- data["ApproximateNumberOfMessagesDelayed"].to_i
99
+ approximate_pending_messages = data['ApproximateNumberOfMessages'].to_i -
100
+ data['ApproximateNumberOfMessagesNotVisible'].to_i -
101
+ data['ApproximateNumberOfMessagesDelayed'].to_i
60
102
 
61
103
  # Just in case the math is off
62
104
  approximate_pending_messages > 0
@@ -77,38 +119,40 @@ module HermesMessengerOfTheGods
77
119
  message_body
78
120
  end
79
121
 
80
- def working_messages(messages)
81
- thread = start_visibility_update_thread(messages)
82
-
122
+ def working_messages
123
+ thread = start_visibility_update_thread
83
124
  yield
84
125
  ensure
85
126
  thread&.terminate
86
127
  end
87
128
 
88
- def start_visibility_update_thread(messages)
129
+ def start_visibility_update_thread
89
130
  start_work_time = Time.now
90
131
  Thread.new do
91
132
  loop do
92
133
  new_time = (Time.now - start_work_time) + VISIBILITY_EXTEND_DURATION
93
- queue.change_message_visibility_batch(
94
- entries: messages.collect do |message|
95
- {
96
- id: SecureRandom.uuid,
97
- receipt_handle: message.receipt_handle,
98
- visibility_timeout: new_time
99
- }
100
- end
101
- )
102
-
134
+ set_message_visibility(inflight_messages, new_time)
103
135
  sleep VISIBILITY_EXTEND_FREQUENCY
104
136
  rescue StandardError => e
105
- STDERR.puts 'Error received trying to extend visibility'
106
- STDERR.puts e.message
137
+ warn 'Error received trying to extend visibility'
138
+ warn e.message
107
139
 
108
140
  raise
109
141
  end
110
142
  end
111
143
  end
144
+
145
+ def set_message_visibility(messages, new_time)
146
+ queue.change_message_visibility_batch(
147
+ entries: messages.collect do |message|
148
+ {
149
+ id: SecureRandom.uuid,
150
+ receipt_handle: message.receipt_handle,
151
+ visibility_timeout: new_time
152
+ }
153
+ end
154
+ )
155
+ end
112
156
  end
113
157
  end
114
158
  end
@@ -15,6 +15,8 @@ module HermesMessengerOfTheGods
15
15
  end
16
16
  end
17
17
 
18
+ attr_accessor :on_receive
19
+
18
20
  def received
19
21
  self.class.received[endpoint]
20
22
  end
@@ -29,7 +31,9 @@ module HermesMessengerOfTheGods
29
31
 
30
32
  def do_transmit(msg, opts, raw_message = {})
31
33
  pub_opts = fetch_option(:publish_options, raw_message) || {}
32
- received << { message: msg, options: opts.merge(pub_opts) }
34
+ new_msg = { message: msg, options: opts.merge(pub_opts) }
35
+ received << new_msg
36
+ on_receive.call(new_msg) if on_receive
33
37
  "Recorded msg ##{self.class.received[endpoint].length} for #{endpoint}"
34
38
  end
35
39
  end
@@ -1,3 +1,3 @@
1
1
  module HermesMessengerOfTheGods
2
- VERSION = '2.1.1'
2
+ VERSION = '2.3.1'
3
3
  end
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: hermes_messenger_of_the_gods
3
3
  version: !ruby/object:Gem::Version
4
- version: 2.1.1
4
+ version: 2.3.1
5
5
  platform: ruby
6
6
  authors:
7
7
  - Brian Malinconico
@@ -9,7 +9,7 @@ authors:
9
9
  autorequire:
10
10
  bindir: exe
11
11
  cert_chain: []
12
- date: 2021-09-21 00:00:00.000000000 Z
12
+ date: 2022-07-07 00:00:00.000000000 Z
13
13
  dependencies:
14
14
  - !ruby/object:Gem::Dependency
15
15
  name: activemodel
@@ -226,8 +226,8 @@ files:
226
226
  - vendor/cache/activesupport-6.1.4.1.gem
227
227
  - vendor/cache/addressable-2.8.0.gem
228
228
  - vendor/cache/aws-eventstream-1.2.0.gem
229
- - vendor/cache/aws-partitions-1.503.0.gem
230
- - vendor/cache/aws-sdk-core-3.121.0.gem
229
+ - vendor/cache/aws-partitions-1.509.0.gem
230
+ - vendor/cache/aws-sdk-core-3.121.1.gem
231
231
  - vendor/cache/aws-sdk-sns-1.45.0.gem
232
232
  - vendor/cache/aws-sdk-sqs-1.44.0.gem
233
233
  - vendor/cache/aws-sigv4-1.4.0.gem
@@ -238,9 +238,11 @@ files:
238
238
  - vendor/cache/crack-0.4.5.gem
239
239
  - vendor/cache/diff-lcs-1.4.4.gem
240
240
  - vendor/cache/docile-1.4.0.gem
241
- - vendor/cache/google-protobuf-3.17.3-x86_64-linux.gem
242
- - vendor/cache/googleapis-common-protos-types-1.1.0.gem
243
- - vendor/cache/grpc-1.38.0-x86_64-linux.gem
241
+ - vendor/cache/google-protobuf-3.18.0-universal-darwin.gem
242
+ - vendor/cache/google-protobuf-3.18.0-x86_64-linux.gem
243
+ - vendor/cache/googleapis-common-protos-types-1.2.0.gem
244
+ - vendor/cache/grpc-1.40.0-universal-darwin.gem
245
+ - vendor/cache/grpc-1.40.0-x86_64-linux.gem
244
246
  - vendor/cache/hashdiff-1.0.1.gem
245
247
  - vendor/cache/i18n-1.8.10.gem
246
248
  - vendor/cache/jmespath-1.4.0.gem
@@ -287,7 +289,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
287
289
  - !ruby/object:Gem::Version
288
290
  version: '0'
289
291
  requirements: []
290
- rubygems_version: 3.2.27
292
+ rubygems_version: 3.2.22
291
293
  signing_key:
292
294
  specification_version: 4
293
295
  summary: Create and receive messages like a god!
Binary file