hermes_messenger_of_the_gods 2.4.2 → 3.0.0.rc1
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/README.md +16 -93
- data/lib/hermes_messenger_of_the_gods/concerns/message.rb +16 -87
- data/lib/hermes_messenger_of_the_gods/concerns/mono_message.rb +6 -4
- data/lib/hermes_messenger_of_the_gods/concerns/worker.rb +13 -28
- data/lib/hermes_messenger_of_the_gods/endpoint_builder.rb +4 -6
- data/lib/hermes_messenger_of_the_gods/endpoints/base.rb +11 -24
- data/lib/hermes_messenger_of_the_gods/endpoints/sqs.rb +0 -1
- data/lib/hermes_messenger_of_the_gods/exceptions.rb +0 -3
- data/lib/hermes_messenger_of_the_gods/testing/dispatch_matcher.rb +0 -1
- data/lib/hermes_messenger_of_the_gods/testing/rspec_helpers.rb +0 -8
- data/lib/hermes_messenger_of_the_gods/version.rb +1 -1
- data/lib/hermes_messenger_of_the_gods.rb +0 -27
- metadata +4 -6
- data/lib/hermes_messenger_of_the_gods/concerns/base.rb +0 -42
- data/lib/hermes_messenger_of_the_gods/output/basic.rb +0 -67
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 4c476e60bbfdcf74e23ae4c0678a170d0db9d74252f754f0597c2c9ffec3f087
|
4
|
+
data.tar.gz: 07a7a6be81771b775f975e67e4c068e6a63462e978b6dda90706714c0283f264
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 2e95976b36e7e11d10f083a6e7aab7786a6e8caa651c83907babf6b62d403d55256b0dd7156c571fffc585c4105475b95ea8a44b336ff277dc05ae329c45be74
|
7
|
+
data.tar.gz: 23e2e98b7b448148d4c9641526568c5806e8c6e98ea3aa06d33e16317f06aed6ee90188e610bdd5749f675e3c515a8daec4ee31c8e6a4a12a047e415eaaad916
|
data/README.md
CHANGED
@@ -105,51 +105,13 @@ class Foo
|
|
105
105
|
|
106
106
|
attr_accessor :name
|
107
107
|
validates :name, presence: true
|
108
|
-
self.endpoints =
|
109
|
-
default: sns_endpoint("sns:arn", jitter: false),
|
110
|
-
other: sns_endpoint('...')
|
111
|
-
}
|
108
|
+
self.endpoints = sns_endpoint("sns:arn", jitter: false)
|
112
109
|
end
|
113
110
|
|
114
111
|
Foo.new(name: 'omg').dispatch!
|
115
112
|
# => true
|
116
113
|
```
|
117
114
|
|
118
|
-
Dispatches to each endpoint is done in a thread to allow for better performance.
|
119
|
-
|
120
|
-
##### Targeting an endpoint
|
121
|
-
You may target only a specific endpoint by passing the `endpoints: ['']` option
|
122
|
-
during message creation. Using the message above:
|
123
|
-
`Foo.new(name: 'omg', endpoints: [:other]).dispatch!` would dispatch only to
|
124
|
-
the other endpoint.
|
125
|
-
|
126
|
-
|
127
|
-
#### Async message dispatch
|
128
|
-
All messages contain a `dispatch_async(!)` option in addition to typical deferral.
|
129
|
-
Using an async dispatch runs the dispatch in a thread. Since dispatches tend to
|
130
|
-
be I/O heavy this is an ideal option if you do not care about capturing the
|
131
|
-
return information or error status. You can check to determine how many messages
|
132
|
-
are in-flight using the helper method
|
133
|
-
`HermesMessengerOfTheGods.async_dispatches_in_progress` in the testing helpers
|
134
|
-
a method named `wait_for_async_dispatches` is avaialbe which will wait for up
|
135
|
-
to 5 seconds for all messages to be "delivered".
|
136
|
-
|
137
|
-
### Endpoint responses
|
138
|
-
When an endpoint reports successful transmission, the response is recorded in
|
139
|
-
the `message.successes` hash. This hash is keyed to correspond to the
|
140
|
-
configuration `endpoints` hash.
|
141
|
-
|
142
|
-
### Endpoint Failures
|
143
|
-
When an endpoint fails (raises an error) the final error raised will be stored
|
144
|
-
in the `message.dispatch_errors` hash. This hash is keyed to correspond to the
|
145
|
-
`endponts` configuration hash
|
146
|
-
|
147
|
-
Failure Exceptions:
|
148
|
-
* When all endpoints fail a `HermesMessengerOfTheGods::MessageDispatchTotalFailure` is raised
|
149
|
-
* When only some endpoints fail a `HermesMessengerOfTheGods::MessageDispatchPartialFailure` is raised
|
150
|
-
|
151
|
-
Both of these exepctions inherit from `HermesMessengerOfTheGods::MessageDispatchFailed`
|
152
|
-
|
153
115
|
## The Worker
|
154
116
|
The worker provides a generic class to provide access for reading from
|
155
117
|
endpoints. Only some endpoints actually provide the ability to read messages.
|
@@ -218,9 +180,7 @@ class MessageType
|
|
218
180
|
end
|
219
181
|
|
220
182
|
class AwesomeWorker < HermesMessengerOfTheGods::Worker
|
221
|
-
self.endpoint =
|
222
|
-
default: sns_endpoint("sns::arn", jitter: false)
|
223
|
-
}
|
183
|
+
self.endpoint = sns_endpoint("sns::arn", jitter: false)
|
224
184
|
self.deserialize_with = MessageType
|
225
185
|
self.deserialize_method = :omg_dude
|
226
186
|
end
|
@@ -247,7 +207,7 @@ and the message into a single class.
|
|
247
207
|
class MonoMessageWorker
|
248
208
|
include HermesMessengerOftheGods::Concerns::MonoMessage
|
249
209
|
|
250
|
-
self.
|
210
|
+
self.endpoint = sqs_endpoint("arn")
|
251
211
|
|
252
212
|
def perform
|
253
213
|
# Do magic Here
|
@@ -260,8 +220,8 @@ You may then start the message execution with:
|
|
260
220
|
`./bin/fly_hermes start --pool=MonoMessageWorker--1`
|
261
221
|
|
262
222
|
|
263
|
-
##
|
264
|
-
Hermes supports using
|
223
|
+
## rotocol Buffers
|
224
|
+
Hermes supports using rotoBuffers over the wire using the
|
265
225
|
`HermesMessengerOfTheGods::Concerns::GrpcProtobuf` mixin. Currently only JSON
|
266
226
|
encoding is allowed.
|
267
227
|
|
@@ -371,36 +331,6 @@ array.
|
|
371
331
|
* `:jsonify` - converts the trasnmitted data to json prior to transmission
|
372
332
|
* `:from_sns` - reads and converts from JSON the serialized Message key
|
373
333
|
|
374
|
-
## Instrumentation
|
375
|
-
HMOTG Uses `ActiveSupport::Notifications` to provide internal instrumentation
|
376
|
-
|
377
|
-
All messages emited include the emitter in their payload if possible:
|
378
|
-
* Messages prefixed with `hermes_messenger_of_the_gods.worker` include the
|
379
|
-
`worker` key.
|
380
|
-
* Messages prefixed with `hermes_messenger_of_the_gods.message` include the
|
381
|
-
`message` key.
|
382
|
-
* Messages prefixed with `hermes_messenger_of_the_gods.endpoint` include the
|
383
|
-
`endpoint` key.
|
384
|
-
|
385
|
-
**NOTE:** All messages are prefixed with `hermes_messenger_of_the_gods` but it
|
386
|
-
was omitted here for brevity.
|
387
|
-
|
388
|
-
| Message | Is Timed | Description | Payload Objects |
|
389
|
-
| ------ | -------- | ----------- | --------------- |
|
390
|
-
| `worker.starting` | | Called when the worker starts up | |
|
391
|
-
| `worker.starting_job` | | Called before work begins on a job | `job` - the deserialize job being run |
|
392
|
-
| `worker.run_job` | ✓ | Measured the execution of the message | `job` - the deserialize job being run |
|
393
|
-
| `worker.failure` | | Invoked when a message raises an error during execution | `job` - the deserialize job being run <br> `error` - the exception raised |
|
394
|
-
| `worker.fatal_error` | | Raised when an unhandled exception causes the worker to die | `exception` - The exceptoin that caused the worker to die |
|
395
|
-
| `worker.deserialization` | ✓ | Called during message deserialization off the endpoint | `job` - the raw job received from the endpoint |
|
396
|
-
| `message.dispatch` | ✓ | Called when a message complets the dispatch process | |
|
397
|
-
| `message.dispatch_failure` | | Called once for every failed enpoint | `exception` - the error raised <br> `endpoint_name` - the name of the failed endpoint |
|
398
|
-
| `endpoint.dispatch` | ✓ | Called around the actual dispatch for each endpoint | |
|
399
|
-
| `endpoint.dispatch_failure` | | Called each time the endpoint fails to dispatch | `try` - The number of times the endpoint has tried to dispatch so far. First call is 1. <br> `exception` - The error that was raised causing the failure |
|
400
|
-
| `endpoint.final_failure` | | Called on the last exception to before the endpoint gives up | `try` - The number of times the endpoint has tried to dispatch so far. At this point `try` equals the `:retries` config . <br> `exception` - The error that was raised causing the failure |
|
401
|
-
| `endpoint.read_failure` | | An inbound message could not be handled (Malformed JSON for example) | `exception` - The unhandled error |
|
402
|
-
|
403
|
-
|
404
334
|
## Global Configuration
|
405
335
|
When configuring HMOTG you can set global configuration opions like so:
|
406
336
|
|
@@ -433,24 +363,17 @@ parameter, or a block which is expected to return the message.
|
|
433
363
|
Additionally the `say` method is provided which takes the desired level contsant
|
434
364
|
as the first parameter. `say(Logger::ERROR, "foo")`
|
435
365
|
|
436
|
-
|
437
|
-
|
438
|
-
|
439
|
-
|
440
|
-
|
441
|
-
|
442
|
-
|
443
|
-
|
444
|
-
|
445
|
-
|
446
|
-
|
447
|
-
I, [date stamp] INFO -- Worker WorkerClass::0(pid: 8): Starting Job <MessageClass: {:instance_var_1 => 123, :instance_var_2=5678}>
|
448
|
-
I, [date stamp] INFO -- Worker WorkerClass::0(pid: 8): Finished Job <MessageClass: {:instance_var_1 => 123, :instance_var_2=5678}>
|
449
|
-
```
|
450
|
-
|
451
|
-
Don't want any output such as during a test suite, or want to write your own?
|
452
|
-
You can turn off the Basic outputter via
|
453
|
-
`HermesMessengerOfTheGods::Output::Basic.unsubscribe!`
|
366
|
+
## Upgrading
|
367
|
+
### V2 -> V3
|
368
|
+
Upgrading to V2 to V3 includes the following breaking changes:
|
369
|
+
|
370
|
+
1) The worker / message `endpoints` setting has been changed to just `endpoint` and takes a single endpoint definition.
|
371
|
+
2) Outputters are no longer used. You need to log anything you want or need.
|
372
|
+
3) There is no longer instrumentation outputted using ActiveSupport::Notifications
|
373
|
+
4) Async Dispatches are now removed (Test helper `wait_for_async_dispatches` also removed)
|
374
|
+
5) Partial and Total failure errors are no longer used, the superclass MessageDispatchFailed is used.
|
375
|
+
6) Dispatch Errors / Successes are no longer included
|
376
|
+
7) Callback system has been removed
|
454
377
|
|
455
378
|
## Development
|
456
379
|
|
@@ -4,23 +4,16 @@ require 'active_model'
|
|
4
4
|
require 'active_support'
|
5
5
|
require 'active_support/core_ext/hash'
|
6
6
|
|
7
|
-
require 'hermes_messenger_of_the_gods/concerns/base'
|
8
|
-
|
9
7
|
module HermesMessengerOfTheGods
|
10
8
|
module Concerns
|
11
9
|
module Message
|
12
10
|
extend ActiveSupport::Concern
|
13
11
|
|
14
12
|
include ActiveModel::Model
|
15
|
-
include
|
16
|
-
|
17
|
-
attr_accessor :targeted_endpoints, :original_message, :source_endpoint
|
13
|
+
include EndpointBuilder::Helpers
|
14
|
+
include LoggingHelpers
|
18
15
|
|
19
|
-
|
20
|
-
@monitor = Monitor.new
|
21
|
-
self.targeted_endpoints = options.delete(:endpoints)
|
22
|
-
super
|
23
|
-
end
|
16
|
+
attr_accessor :original_message, :source_endpoint
|
24
17
|
|
25
18
|
def validate!
|
26
19
|
raise HermesMessengerOfTheGods::ValidationError, self unless valid?
|
@@ -32,24 +25,6 @@ module HermesMessengerOfTheGods
|
|
32
25
|
false
|
33
26
|
end
|
34
27
|
|
35
|
-
def dispatch_async
|
36
|
-
HermesMessengerOfTheGods.increment_async_dispatches_in_progress
|
37
|
-
Thread.new do
|
38
|
-
dispatch
|
39
|
-
ensure
|
40
|
-
HermesMessengerOfTheGods.decrement_async_dispatches_in_progress
|
41
|
-
end
|
42
|
-
end
|
43
|
-
|
44
|
-
def dispatch_async!
|
45
|
-
HermesMessengerOfTheGods.increment_async_dispatches_in_progress
|
46
|
-
Thread.new do
|
47
|
-
dispatch!
|
48
|
-
ensure
|
49
|
-
HermesMessengerOfTheGods.decrement_async_dispatches_in_progress
|
50
|
-
end
|
51
|
-
end
|
52
|
-
|
53
28
|
def retry_at(future_time_or_seconds_in_future)
|
54
29
|
raise 'unable to set visiblity' if source_endpoint.nil? || original_message.nil?
|
55
30
|
raise "endpoint type doesn't support setting execution time" unless source_endpoint.respond_to?(:set_reexecution_time)
|
@@ -58,60 +33,20 @@ module HermesMessengerOfTheGods
|
|
58
33
|
end
|
59
34
|
|
60
35
|
def dispatch!(endpoint_args: {})
|
61
|
-
|
62
|
-
validate!
|
63
|
-
|
64
|
-
endpoints.collect do |ep_name, endpoint|
|
65
|
-
next if targeted_endpoints && !targeted_endpoints.include?(ep_name)
|
66
|
-
|
67
|
-
begin
|
68
|
-
endpoint.dispatch!(self, endpoint_args) unless HermesMessengerOfTheGods.config.stub_dispatch
|
69
|
-
register_success(ep_name, endpoint.result)
|
70
|
-
rescue StandardError => e
|
71
|
-
say_error(e)
|
72
|
-
register_failure(ep_name, e)
|
73
|
-
ensure
|
74
|
-
endpoint.teardown
|
75
|
-
end
|
76
|
-
end
|
77
|
-
|
78
|
-
unless dispatch_errors.empty?
|
79
|
-
klass = if successes.empty?
|
80
|
-
HermesMessengerOfTheGods::MessageDispatchTotalFailure
|
81
|
-
else
|
82
|
-
HermesMessengerOfTheGods::MessageDispatchPartialFailure
|
83
|
-
end
|
36
|
+
validate!
|
84
37
|
|
85
|
-
|
86
|
-
|
87
|
-
|
88
|
-
|
38
|
+
begin
|
39
|
+
endpoint.dispatch!(self, endpoint_args) unless HermesMessengerOfTheGods.config.stub_dispatch
|
40
|
+
rescue StandardError => e
|
41
|
+
say_error(e)
|
42
|
+
raise HermesMessengerOfTheGods::MessageDispatchFailed, e.message
|
43
|
+
ensure
|
44
|
+
endpoint.teardown
|
89
45
|
end
|
90
46
|
|
91
47
|
true
|
92
48
|
end
|
93
49
|
|
94
|
-
def register_failure(ep_name, error)
|
95
|
-
@monitor.synchronize do
|
96
|
-
instrument(:dispatch_failure, endpoint_name: ep_name, exception: error)
|
97
|
-
dispatch_errors[ep_name] = error
|
98
|
-
end
|
99
|
-
end
|
100
|
-
|
101
|
-
def register_success(ep_name, return_value)
|
102
|
-
@monitor.synchronize do
|
103
|
-
successes[ep_name] = return_value
|
104
|
-
end
|
105
|
-
end
|
106
|
-
|
107
|
-
def dispatch_errors
|
108
|
-
@dispatch_errors ||= {}
|
109
|
-
end
|
110
|
-
|
111
|
-
def successes
|
112
|
-
@successes ||= {}
|
113
|
-
end
|
114
|
-
|
115
50
|
def _build_for_transmission
|
116
51
|
to_message
|
117
52
|
end
|
@@ -131,11 +66,7 @@ module HermesMessengerOfTheGods
|
|
131
66
|
end
|
132
67
|
|
133
68
|
included do
|
134
|
-
class_attribute :_defined_attributes, :
|
135
|
-
|
136
|
-
define_model_callbacks :dispatch
|
137
|
-
|
138
|
-
around_dispatch { |_, blk| instrument(:dispatch, &blk) }
|
69
|
+
class_attribute :_defined_attributes, :_endpoint, :_circuit_breaker_errors, :_max_consecutive_failures
|
139
70
|
end
|
140
71
|
|
141
72
|
class_methods do
|
@@ -150,8 +81,8 @@ module HermesMessengerOfTheGods
|
|
150
81
|
super
|
151
82
|
end
|
152
83
|
|
153
|
-
def
|
154
|
-
|
84
|
+
def endpoint
|
85
|
+
_endpoint
|
155
86
|
end
|
156
87
|
|
157
88
|
def circuit_breaker_errors
|
@@ -185,10 +116,8 @@ module HermesMessengerOfTheGods
|
|
185
116
|
self._circuit_breaker_errors = val
|
186
117
|
end
|
187
118
|
|
188
|
-
def
|
189
|
-
|
190
|
-
|
191
|
-
self._endpoints = val
|
119
|
+
def endpoint=(val)
|
120
|
+
self._endpoint = val
|
192
121
|
end
|
193
122
|
end
|
194
123
|
end
|
@@ -10,12 +10,14 @@ module HermesMessengerOfTheGods
|
|
10
10
|
module MonoMessage
|
11
11
|
extend ActiveSupport::Concern
|
12
12
|
|
13
|
-
|
13
|
+
def self.included(other)
|
14
|
+
other.include HermesMessengerOfTheGods::Concerns::Message
|
15
|
+
end
|
14
16
|
|
15
17
|
class_methods do
|
16
|
-
def
|
18
|
+
def endpoint=(*args)
|
17
19
|
super
|
18
|
-
worker_klass.
|
20
|
+
worker_klass.endpoint = endpoint
|
19
21
|
end
|
20
22
|
|
21
23
|
def circuit_breaker_errors=(*args)
|
@@ -40,7 +42,7 @@ module HermesMessengerOfTheGods
|
|
40
42
|
me = self
|
41
43
|
@worker_klass ||= Class.new do
|
42
44
|
include HermesMessengerOfTheGods::Concerns::Worker
|
43
|
-
self.
|
45
|
+
self.endpoint = me.endpoint
|
44
46
|
self.circuit_breaker_errors = me.circuit_breaker_errors
|
45
47
|
self.max_consecutive_failures = me.max_consecutive_failures
|
46
48
|
self.deserialize_with = me
|
@@ -2,7 +2,6 @@
|
|
2
2
|
|
3
3
|
require 'active_support'
|
4
4
|
|
5
|
-
require_relative './base'
|
6
5
|
require_relative '../status_server'
|
7
6
|
|
8
7
|
module HermesMessengerOfTheGods
|
@@ -10,7 +9,8 @@ module HermesMessengerOfTheGods
|
|
10
9
|
module Worker
|
11
10
|
extend ActiveSupport::Concern
|
12
11
|
|
13
|
-
include
|
12
|
+
include EndpointBuilder::Helpers
|
13
|
+
include LoggingHelpers
|
14
14
|
|
15
15
|
included do
|
16
16
|
attr_writer :name
|
@@ -37,7 +37,6 @@ module HermesMessengerOfTheGods
|
|
37
37
|
trap(:TERM) { endpoint.shutdown! }
|
38
38
|
trap(:INT) { endpoint.shutdown! }
|
39
39
|
|
40
|
-
instrument(:starting)
|
41
40
|
self.consecutive_failures = 0
|
42
41
|
endpoint.work_off do |job, original_message|
|
43
42
|
self.last_task_performed = Time.now
|
@@ -45,7 +44,6 @@ module HermesMessengerOfTheGods
|
|
45
44
|
built_job = deserialize(job)
|
46
45
|
built_job.original_message = original_message
|
47
46
|
built_job.source_endpoint = endpoint
|
48
|
-
instrument(:starting_job, job: built_job)
|
49
47
|
built_job.validate! if built_job.respond_to?(:validate!)
|
50
48
|
run_job(built_job)
|
51
49
|
handle_success(built_job, job)
|
@@ -55,7 +53,6 @@ module HermesMessengerOfTheGods
|
|
55
53
|
max_consecutive_failures = self.class.max_consecutive_failures
|
56
54
|
|
57
55
|
if max_consecutive_failures.is_a?(Integer) && HermesMessengerOfTheGods.config.kill_on_consecutive_failures && consecutive_failures >= max_consecutive_failures
|
58
|
-
instrument(:consecutive_failure_shutdown)
|
59
56
|
return Process.kill('TERM', Process.getpgid(Process.ppid))
|
60
57
|
end
|
61
58
|
|
@@ -72,46 +69,35 @@ module HermesMessengerOfTheGods
|
|
72
69
|
throw(:skip_delete, true)
|
73
70
|
end
|
74
71
|
rescue StandardError => e
|
75
|
-
instrument(:fatal_error, exception: e)
|
76
72
|
raise
|
77
73
|
ensure
|
78
74
|
endpoint.teardown
|
79
75
|
end
|
80
76
|
|
81
77
|
def run_job(job)
|
82
|
-
|
83
|
-
|
84
|
-
|
85
|
-
|
86
|
-
|
87
|
-
|
88
|
-
raise 'You need to define a run_job method in the worker, or a perform method on the message'
|
89
|
-
end
|
78
|
+
if respond_to?(:perform)
|
79
|
+
perform(job)
|
80
|
+
elsif job.respond_to?(:perform)
|
81
|
+
job.perform
|
82
|
+
else
|
83
|
+
raise 'You need to define a run_job method in the worker, or a perform method on the message'
|
90
84
|
end
|
91
85
|
end
|
92
86
|
|
93
87
|
def handle_success(built_job, raw_job)
|
94
|
-
instrument(:success, job: built_job)
|
95
88
|
endpoint.handle_success(raw_job)
|
96
89
|
self.consecutive_failures = 0
|
97
90
|
end
|
98
91
|
|
99
92
|
def handle_failure(job, e)
|
100
|
-
instrument(:failure, job: job, error: e)
|
101
93
|
endpoint.handle_failure(job, e)
|
102
94
|
self.consecutive_failures ||= 0
|
103
95
|
self.consecutive_failures += 1
|
104
96
|
end
|
105
97
|
|
106
98
|
def deserialize(raw_job)
|
107
|
-
|
108
|
-
|
109
|
-
self.class.deserialize_with.send(deserialize_method, raw_job)
|
110
|
-
end
|
111
|
-
end
|
112
|
-
|
113
|
-
def endpoint
|
114
|
-
@endpoint ||= endpoints.values.first
|
99
|
+
deserialize_method = self.class.deserialize_method || :from_message
|
100
|
+
self.class.deserialize_with.send(deserialize_method, raw_job)
|
115
101
|
end
|
116
102
|
|
117
103
|
def log_message_prefix
|
@@ -124,7 +110,7 @@ module HermesMessengerOfTheGods
|
|
124
110
|
end
|
125
111
|
|
126
112
|
class_methods do
|
127
|
-
attr_reader :
|
113
|
+
attr_reader :endpoint
|
128
114
|
attr_accessor :deserialize_with, :deserialize_method
|
129
115
|
|
130
116
|
def build_worker
|
@@ -166,11 +152,10 @@ module HermesMessengerOfTheGods
|
|
166
152
|
@circuit_breaker_errors = val
|
167
153
|
end
|
168
154
|
|
169
|
-
def
|
155
|
+
def endpoint=(val)
|
170
156
|
raise 'Expected an endpoint' unless val.is_a?(Hash)
|
171
|
-
raise 'Workers can only have one defined endpoint' unless val.length == 1
|
172
157
|
|
173
|
-
@
|
158
|
+
@endpoint = val
|
174
159
|
end
|
175
160
|
end
|
176
161
|
end
|
@@ -12,8 +12,8 @@ module HermesMessengerOfTheGods
|
|
12
12
|
extend ActiveSupport::Concern
|
13
13
|
|
14
14
|
included do
|
15
|
-
def
|
16
|
-
@
|
15
|
+
def endpoint
|
16
|
+
@endpoint ||= self.class.build_endpoint
|
17
17
|
end
|
18
18
|
end
|
19
19
|
|
@@ -36,10 +36,8 @@ module HermesMessengerOfTheGods
|
|
36
36
|
end
|
37
37
|
end
|
38
38
|
|
39
|
-
def
|
40
|
-
|
41
|
-
hsh[k] = EndpointBuilder.build(k, v[:klass], *v[:args])
|
42
|
-
end
|
39
|
+
def build_endpoint
|
40
|
+
EndpointBuilder.build('default', endpoint[:klass], *endpoint[:args])
|
43
41
|
end
|
44
42
|
end
|
45
43
|
end
|
@@ -1,13 +1,8 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
2
|
|
3
|
-
require_relative '../concerns/base'
|
4
|
-
|
5
3
|
module HermesMessengerOfTheGods
|
6
4
|
module Endpoints
|
7
5
|
class Base
|
8
|
-
extend ActiveModel::Callbacks
|
9
|
-
|
10
|
-
include HermesMessengerOfTheGods::Concerns::Base
|
11
6
|
|
12
7
|
DEFAULT_OPTIONS = { retries: 3, jitter: true, backoff: :linear, jsonify: true }.freeze
|
13
8
|
DEFAULT_RETRYS = {
|
@@ -17,10 +12,6 @@ module HermesMessengerOfTheGods
|
|
17
12
|
|
18
13
|
attr_accessor :options, :endpoint, :errors, :result, :name
|
19
14
|
|
20
|
-
define_model_callbacks :dispatch
|
21
|
-
|
22
|
-
around_dispatch { |_, blk| instrument(:dispatch, &blk) }
|
23
|
-
|
24
15
|
def initialize(name, endpoint, options = {})
|
25
16
|
self.name = name
|
26
17
|
self.options = self.class::DEFAULT_OPTIONS.merge(options)
|
@@ -35,21 +26,17 @@ module HermesMessengerOfTheGods
|
|
35
26
|
end
|
36
27
|
|
37
28
|
def dispatch!(message, options = {})
|
38
|
-
|
39
|
-
|
40
|
-
|
41
|
-
|
42
|
-
|
43
|
-
|
44
|
-
|
45
|
-
|
46
|
-
|
47
|
-
|
48
|
-
|
49
|
-
else
|
50
|
-
instrument(:final_failure, try: retry_number, exception: e)
|
51
|
-
raise
|
52
|
-
end
|
29
|
+
retry_number = 0
|
30
|
+
begin
|
31
|
+
self.result = transmit(transform_message(message), message, options)
|
32
|
+
rescue StandardError => e
|
33
|
+
errors << e
|
34
|
+
retry_number += 1
|
35
|
+
if retry_number < max_retries && retry_from(e)
|
36
|
+
backoff(retry_number)
|
37
|
+
retry
|
38
|
+
else
|
39
|
+
raise
|
53
40
|
end
|
54
41
|
end
|
55
42
|
|
@@ -19,9 +19,6 @@ module HermesMessengerOfTheGods
|
|
19
19
|
attr_accessor :exceptions
|
20
20
|
end
|
21
21
|
|
22
|
-
class MessageDispatchTotalFailure < MessageDispatchFailed; end
|
23
|
-
class MessageDispatchPartialFailure < MessageDispatchFailed; end
|
24
|
-
|
25
22
|
module Endpoints
|
26
23
|
class FatalError < RuntimeError; end
|
27
24
|
end
|
@@ -45,14 +45,6 @@ module HermesMessengerOfTheGods
|
|
45
45
|
build_fake_endpoint(klass, endpoint, *args)
|
46
46
|
end
|
47
47
|
end
|
48
|
-
|
49
|
-
def wait_for_async_dispatches
|
50
|
-
return if HermesMessengerOfTheGods.async_dispatches_in_progress.zero?
|
51
|
-
|
52
|
-
Timeout.timeout(5) do
|
53
|
-
sleep 0.01 until HermesMessengerOfTheGods.async_dispatches_in_progress.zero?
|
54
|
-
end
|
55
|
-
end
|
56
48
|
end
|
57
49
|
end
|
58
50
|
end
|
@@ -8,7 +8,6 @@ require 'hermes_messenger_of_the_gods/configuration'
|
|
8
8
|
require 'hermes_messenger_of_the_gods/logging_helpers'
|
9
9
|
require 'hermes_messenger_of_the_gods/endpoint_builder'
|
10
10
|
|
11
|
-
require 'hermes_messenger_of_the_gods/concerns/base'
|
12
11
|
require 'hermes_messenger_of_the_gods/concerns/message'
|
13
12
|
require 'hermes_messenger_of_the_gods/concerns/worker'
|
14
13
|
require 'hermes_messenger_of_the_gods/concerns/mono_message'
|
@@ -16,8 +15,6 @@ require 'hermes_messenger_of_the_gods/concerns/grpc_protobuf'
|
|
16
15
|
|
17
16
|
require 'hermes_messenger_of_the_gods/endpoints'
|
18
17
|
|
19
|
-
require 'hermes_messenger_of_the_gods/output/basic'
|
20
|
-
|
21
18
|
module HermesMessengerOfTheGods
|
22
19
|
class << self
|
23
20
|
def configuration
|
@@ -29,29 +26,5 @@ module HermesMessengerOfTheGods
|
|
29
26
|
configuration
|
30
27
|
end
|
31
28
|
alias config configure
|
32
|
-
|
33
|
-
def async_dispatches_in_progress
|
34
|
-
@async_dispatches_in_progress ||= 0
|
35
|
-
end
|
36
|
-
|
37
|
-
def increment_async_dispatches_in_progress
|
38
|
-
monitor.synchronize do
|
39
|
-
self.async_dispatches_in_progress += 1
|
40
|
-
end
|
41
|
-
end
|
42
|
-
|
43
|
-
def decrement_async_dispatches_in_progress
|
44
|
-
monitor.synchronize do
|
45
|
-
self.async_dispatches_in_progress -= 1
|
46
|
-
end
|
47
|
-
end
|
48
|
-
|
49
|
-
private
|
50
|
-
|
51
|
-
attr_writer :async_dispatches_in_progress
|
52
|
-
|
53
|
-
def monitor
|
54
|
-
@monitor ||= Monitor.new
|
55
|
-
end
|
56
29
|
end
|
57
30
|
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:
|
4
|
+
version: 3.0.0.rc1
|
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: 2023-
|
12
|
+
date: 2023-10-06 00:00:00.000000000 Z
|
13
13
|
dependencies:
|
14
14
|
- !ruby/object:Gem::Dependency
|
15
15
|
name: activemodel
|
@@ -217,7 +217,6 @@ files:
|
|
217
217
|
- exe/fly_hermes
|
218
218
|
- hermes_messenger_of_the_gods.gemspec
|
219
219
|
- lib/hermes_messenger_of_the_gods.rb
|
220
|
-
- lib/hermes_messenger_of_the_gods/concerns/base.rb
|
221
220
|
- lib/hermes_messenger_of_the_gods/concerns/grpc_protobuf.rb
|
222
221
|
- lib/hermes_messenger_of_the_gods/concerns/message.rb
|
223
222
|
- lib/hermes_messenger_of_the_gods/concerns/mono_message.rb
|
@@ -230,7 +229,6 @@ files:
|
|
230
229
|
- lib/hermes_messenger_of_the_gods/endpoints/sqs.rb
|
231
230
|
- lib/hermes_messenger_of_the_gods/exceptions.rb
|
232
231
|
- lib/hermes_messenger_of_the_gods/logging_helpers.rb
|
233
|
-
- lib/hermes_messenger_of_the_gods/output/basic.rb
|
234
232
|
- lib/hermes_messenger_of_the_gods/status_server.rb
|
235
233
|
- lib/hermes_messenger_of_the_gods/testing/array_endpoint.rb
|
236
234
|
- lib/hermes_messenger_of_the_gods/testing/dispatch_matcher.rb
|
@@ -252,9 +250,9 @@ required_ruby_version: !ruby/object:Gem::Requirement
|
|
252
250
|
version: '0'
|
253
251
|
required_rubygems_version: !ruby/object:Gem::Requirement
|
254
252
|
requirements:
|
255
|
-
- - "
|
253
|
+
- - ">"
|
256
254
|
- !ruby/object:Gem::Version
|
257
|
-
version:
|
255
|
+
version: 1.3.1
|
258
256
|
requirements: []
|
259
257
|
rubygems_version: 3.2.22
|
260
258
|
signing_key:
|
@@ -1,42 +0,0 @@
|
|
1
|
-
# frozen_string_literal: true
|
2
|
-
|
3
|
-
require 'active_support'
|
4
|
-
require 'active_support/core_ext/object/blank'
|
5
|
-
|
6
|
-
module HermesMessengerOfTheGods
|
7
|
-
module Concerns
|
8
|
-
module Base
|
9
|
-
extend ActiveSupport::Concern
|
10
|
-
|
11
|
-
include EndpointBuilder::Helpers
|
12
|
-
include LoggingHelpers
|
13
|
-
|
14
|
-
included do
|
15
|
-
def instrument(name, payload = {}, &blk)
|
16
|
-
name = [
|
17
|
-
'hermes_messenger_of_the_gods',
|
18
|
-
notification_prefix,
|
19
|
-
name,
|
20
|
-
].reject(&:blank?).join('.')
|
21
|
-
|
22
|
-
payload[_instrument_key] ||= self if _instrument_key
|
23
|
-
ActiveSupport::Notifications.instrument(name, payload, &blk)
|
24
|
-
end
|
25
|
-
|
26
|
-
def notification_prefix
|
27
|
-
_instrument_key
|
28
|
-
end
|
29
|
-
|
30
|
-
def _instrument_key
|
31
|
-
if is_a?(HermesMessengerOfTheGods::Concerns::Worker)
|
32
|
-
:worker
|
33
|
-
elsif is_a?(HermesMessengerOfTheGods::Concerns::Message)
|
34
|
-
:message
|
35
|
-
elsif is_a?(HermesMessengerOfTheGods::Endpoints::Base)
|
36
|
-
:endpoint
|
37
|
-
end
|
38
|
-
end
|
39
|
-
end
|
40
|
-
end
|
41
|
-
end
|
42
|
-
end
|
@@ -1,67 +0,0 @@
|
|
1
|
-
# frozen_string_literal: true
|
2
|
-
|
3
|
-
# Worker Output
|
4
|
-
module HermesMessengerOfTheGods
|
5
|
-
module Output
|
6
|
-
module Basic
|
7
|
-
@subscriptions = []
|
8
|
-
|
9
|
-
def self.unsubscribe!
|
10
|
-
@subscriptions.map { |s| ActiveSupport::Notifications.unsubscribe(s) }
|
11
|
-
end
|
12
|
-
|
13
|
-
def self.subscribe!
|
14
|
-
unsubscribe!
|
15
|
-
|
16
|
-
@subscriptions = [
|
17
|
-
ActiveSupport::Notifications.subscribe('hermes_messenger_of_the_gods.worker.starting') do |*_, payload|
|
18
|
-
payload[:worker].say_info { 'Starting Worker' }
|
19
|
-
end,
|
20
|
-
ActiveSupport::Notifications.subscribe('hermes_messenger_of_the_gods.worker.run_job') do |_, start, finish, _, payload|
|
21
|
-
payload[:worker].say_debug { "Completed #{to_log_s(payload[:job])} in #{finish - start}s" }
|
22
|
-
end,
|
23
|
-
ActiveSupport::Notifications.subscribe('hermes_messenger_of_the_gods.worker.starting_job') do |*_, payload|
|
24
|
-
payload[:worker].say_info { "Starting Job #{to_log_s(payload[:job])}" }
|
25
|
-
end,
|
26
|
-
ActiveSupport::Notifications.subscribe('hermes_messenger_of_the_gods.worker.success') do |*_, payload|
|
27
|
-
payload[:worker].say_info { "Finished Job #{to_log_s(payload[:job])}" }
|
28
|
-
end,
|
29
|
-
ActiveSupport::Notifications.subscribe('hermes_messenger_of_the_gods.worker.failure') do |*_, payload|
|
30
|
-
payload[:worker].say_error { "Error in #{to_log_s(payload[:job])}: #{payload[:error].message}" }
|
31
|
-
payload[:worker].say_debug { "backtrace: #{payload[:error].backtrace}" }
|
32
|
-
end,
|
33
|
-
ActiveSupport::Notifications.subscribe('hermes_messenger_of_the_gods.worker.fatal_error') do |*_, payload|
|
34
|
-
payload[:worker].say_error { "Fatal Error: #{to_log_s(payload[:job])}: #{payload[:exception].message}" }
|
35
|
-
payload[:worker].say_debug { "backtrace: #{payload[:exception].backtrace}" }
|
36
|
-
end,
|
37
|
-
# Message Output
|
38
|
-
ActiveSupport::Notifications.subscribe('hermes_messenger_of_the_gods.message.dispatch') do |_, _start, _finish, _, payload|
|
39
|
-
payload[:message].say_debug { "Dispatch complete in #{to_log_s(payload[:job])}s" }
|
40
|
-
end,
|
41
|
-
ActiveSupport::Notifications.subscribe('hermes_messenger_of_the_gods.message.dispatch_failure') do |*_, payload|
|
42
|
-
payload[:message].say_error { "Dispatch failure to #{to_log_s(payload[:job])}: #{payload[:exception].inspect}" }
|
43
|
-
end,
|
44
|
-
# Endpoint Output
|
45
|
-
ActiveSupport::Notifications.subscribe('hermes_messenger_of_the_gods.endpoint.dispatch') do |_, start, finish, _, payload|
|
46
|
-
payload[:endpoint].say_debug { "Dispatch complete in #{finish - start}s #{' FAILED' if payload.key?(:exception)}" }
|
47
|
-
end,
|
48
|
-
ActiveSupport::Notifications.subscribe(/hermes_messenger_of_the_gods.endpoint.(dispatch|final)_failure/) do |name, *_, payload|
|
49
|
-
payload[:endpoint].say_error { "Dispatch #{'final ' if name.include?('final_')} failure ##{payload[:try]} to #{payload[:endpoint_name]}: #{payload[:exception].inspect}" }
|
50
|
-
end,
|
51
|
-
ActiveSupport::Notifications.subscribe(/hermes_messenger_of_the_gods.endpoint.read_failure/) do |_name, *_, payload|
|
52
|
-
payload[:endpoint].say_error { "A message was received that could not be decoded: #{payload[:exception].message}" }
|
53
|
-
end,
|
54
|
-
]
|
55
|
-
end
|
56
|
-
subscribe!
|
57
|
-
|
58
|
-
def self.to_log_s(item)
|
59
|
-
if item.respond_to?(:to_log_s)
|
60
|
-
item.to_log_s
|
61
|
-
else
|
62
|
-
item.inspect
|
63
|
-
end
|
64
|
-
end
|
65
|
-
end
|
66
|
-
end
|
67
|
-
end
|