hermes_messenger_of_the_gods 2.0.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +7 -0
- data/.drone.yml +9 -0
- data/.gitignore +12 -0
- data/.rspec +3 -0
- data/.ruby-version +1 -0
- data/.travis.yml +5 -0
- data/Gemfile +13 -0
- data/README.md +464 -0
- data/Rakefile +6 -0
- data/bin/console +14 -0
- data/bin/setup +8 -0
- data/exe/fly_hermes +57 -0
- data/hermes_messenger_of_the_gods.gemspec +38 -0
- data/lib/hermes_messenger_of_the_gods.rb +57 -0
- data/lib/hermes_messenger_of_the_gods/concerns/base.rb +42 -0
- data/lib/hermes_messenger_of_the_gods/concerns/grpc_protobuf.rb +62 -0
- data/lib/hermes_messenger_of_the_gods/concerns/message.rb +194 -0
- data/lib/hermes_messenger_of_the_gods/concerns/mono_message.rb +52 -0
- data/lib/hermes_messenger_of_the_gods/concerns/worker.rb +173 -0
- data/lib/hermes_messenger_of_the_gods/configuration.rb +29 -0
- data/lib/hermes_messenger_of_the_gods/endpoint_builder.rb +41 -0
- data/lib/hermes_messenger_of_the_gods/endpoints.rb +3 -0
- data/lib/hermes_messenger_of_the_gods/endpoints/base.rb +113 -0
- data/lib/hermes_messenger_of_the_gods/endpoints/sns.rb +21 -0
- data/lib/hermes_messenger_of_the_gods/endpoints/sqs.rb +114 -0
- data/lib/hermes_messenger_of_the_gods/exceptions.rb +27 -0
- data/lib/hermes_messenger_of_the_gods/logging_helpers.rb +30 -0
- data/lib/hermes_messenger_of_the_gods/output/basic.rb +63 -0
- data/lib/hermes_messenger_of_the_gods/status_server.rb +48 -0
- data/lib/hermes_messenger_of_the_gods/testing/array_endpoint.rb +46 -0
- data/lib/hermes_messenger_of_the_gods/testing/dispatch_matcher.rb +52 -0
- data/lib/hermes_messenger_of_the_gods/testing/rspec_helpers.rb +64 -0
- data/lib/hermes_messenger_of_the_gods/version.rb +3 -0
- data/packageGems.sh +13 -0
- data/vendor/cache/Protobuf3Fixer-5f9f1a2d2da9/.bundlecache +0 -0
- data/vendor/cache/Protobuf3Fixer-5f9f1a2d2da9/.circleci/config.yml +32 -0
- data/vendor/cache/Protobuf3Fixer-5f9f1a2d2da9/.gitignore +11 -0
- data/vendor/cache/Protobuf3Fixer-5f9f1a2d2da9/.rspec +3 -0
- data/vendor/cache/Protobuf3Fixer-5f9f1a2d2da9/.rubocop.yml +42 -0
- data/vendor/cache/Protobuf3Fixer-5f9f1a2d2da9/.ruby-version +1 -0
- data/vendor/cache/Protobuf3Fixer-5f9f1a2d2da9/.travis.yml +5 -0
- data/vendor/cache/Protobuf3Fixer-5f9f1a2d2da9/Gemfile +6 -0
- data/vendor/cache/Protobuf3Fixer-5f9f1a2d2da9/Gemfile.lock +75 -0
- data/vendor/cache/Protobuf3Fixer-5f9f1a2d2da9/Makefile +1 -0
- data/vendor/cache/Protobuf3Fixer-5f9f1a2d2da9/README.md +78 -0
- data/vendor/cache/Protobuf3Fixer-5f9f1a2d2da9/Rakefile +6 -0
- data/vendor/cache/Protobuf3Fixer-5f9f1a2d2da9/bin/bundle +105 -0
- data/vendor/cache/Protobuf3Fixer-5f9f1a2d2da9/bin/coderay +29 -0
- data/vendor/cache/Protobuf3Fixer-5f9f1a2d2da9/bin/console +14 -0
- data/vendor/cache/Protobuf3Fixer-5f9f1a2d2da9/bin/grpc_tools_ruby_protoc +29 -0
- data/vendor/cache/Protobuf3Fixer-5f9f1a2d2da9/bin/grpc_tools_ruby_protoc_plugin +29 -0
- data/vendor/cache/Protobuf3Fixer-5f9f1a2d2da9/bin/htmldiff +29 -0
- data/vendor/cache/Protobuf3Fixer-5f9f1a2d2da9/bin/ldiff +29 -0
- data/vendor/cache/Protobuf3Fixer-5f9f1a2d2da9/bin/pry +29 -0
- data/vendor/cache/Protobuf3Fixer-5f9f1a2d2da9/bin/rake +29 -0
- data/vendor/cache/Protobuf3Fixer-5f9f1a2d2da9/bin/rspec +29 -0
- data/vendor/cache/Protobuf3Fixer-5f9f1a2d2da9/bin/rubocop +29 -0
- data/vendor/cache/Protobuf3Fixer-5f9f1a2d2da9/bin/ruby-parse +29 -0
- data/vendor/cache/Protobuf3Fixer-5f9f1a2d2da9/bin/ruby-rewrite +29 -0
- data/vendor/cache/Protobuf3Fixer-5f9f1a2d2da9/bin/setup +8 -0
- data/vendor/cache/Protobuf3Fixer-5f9f1a2d2da9/lib/protobuf3_fixer.rb +123 -0
- data/vendor/cache/Protobuf3Fixer-5f9f1a2d2da9/lib/protobuf3_fixer/encoder.rb +63 -0
- data/vendor/cache/Protobuf3Fixer-5f9f1a2d2da9/lib/protobuf3_fixer/generation_helpers.rb +23 -0
- data/vendor/cache/Protobuf3Fixer-5f9f1a2d2da9/lib/protobuf3_fixer/reflector.rb +66 -0
- data/vendor/cache/Protobuf3Fixer-5f9f1a2d2da9/lib/protobuf3_fixer/version.rb +3 -0
- data/vendor/cache/Protobuf3Fixer-5f9f1a2d2da9/protobuf3_fixer.gemspec +54 -0
- data/vendor/cache/Protobuf3Fixer-5f9f1a2d2da9/rubocop/bundle +105 -0
- data/vendor/cache/Protobuf3Fixer-5f9f1a2d2da9/rubocop/coderay +29 -0
- data/vendor/cache/Protobuf3Fixer-5f9f1a2d2da9/rubocop/grpc_tools_ruby_protoc +29 -0
- data/vendor/cache/Protobuf3Fixer-5f9f1a2d2da9/rubocop/grpc_tools_ruby_protoc_plugin +29 -0
- data/vendor/cache/Protobuf3Fixer-5f9f1a2d2da9/rubocop/htmldiff +29 -0
- data/vendor/cache/Protobuf3Fixer-5f9f1a2d2da9/rubocop/ldiff +29 -0
- data/vendor/cache/Protobuf3Fixer-5f9f1a2d2da9/rubocop/pry +29 -0
- data/vendor/cache/Protobuf3Fixer-5f9f1a2d2da9/rubocop/rake +29 -0
- data/vendor/cache/Protobuf3Fixer-5f9f1a2d2da9/rubocop/rspec +29 -0
- data/vendor/cache/Protobuf3Fixer-5f9f1a2d2da9/rubocop/rubocop +29 -0
- data/vendor/cache/Protobuf3Fixer-5f9f1a2d2da9/rubocop/ruby-parse +29 -0
- data/vendor/cache/Protobuf3Fixer-5f9f1a2d2da9/rubocop/ruby-rewrite +29 -0
- data/vendor/cache/Protobuf3Fixer-5f9f1a2d2da9/spec/build_from_hash_spec.rb +20 -0
- data/vendor/cache/Protobuf3Fixer-5f9f1a2d2da9/spec/encoding/encoding_options_spec.rb +23 -0
- data/vendor/cache/Protobuf3Fixer-5f9f1a2d2da9/spec/extra_fields/json_decode_of_superset_spec.rb +54 -0
- data/vendor/cache/Protobuf3Fixer-5f9f1a2d2da9/spec/generation_helpers_spec.rb +37 -0
- data/vendor/cache/Protobuf3Fixer-5f9f1a2d2da9/spec/protobuf3_fixer_spec.rb +5 -0
- data/vendor/cache/Protobuf3Fixer-5f9f1a2d2da9/spec/spec_helper.rb +17 -0
- data/vendor/cache/Protobuf3Fixer-5f9f1a2d2da9/spec/support/compiled_protobuffs/source/superset_pb.rb +44 -0
- data/vendor/cache/Protobuf3Fixer-5f9f1a2d2da9/spec/support/compiled_protobuffs/source/timestamp_pb.rb +27 -0
- data/vendor/cache/Protobuf3Fixer-5f9f1a2d2da9/spec/support/protobuffs/source/superset.proto +40 -0
- data/vendor/cache/Protobuf3Fixer-5f9f1a2d2da9/spec/support/protobuffs/source/timestamp.proto +18 -0
- data/vendor/cache/Protobuf3Fixer-5f9f1a2d2da9/spec/well_known_type_fixes/timestamp_spec.rb +79 -0
- data/vendor/cache/activemodel-6.0.3.1.gem +0 -0
- data/vendor/cache/activesupport-6.0.3.1.gem +0 -0
- data/vendor/cache/addressable-2.6.0.gem +0 -0
- data/vendor/cache/aws-eventstream-1.1.0.gem +0 -0
- data/vendor/cache/aws-partitions-1.329.0.gem +0 -0
- data/vendor/cache/aws-sdk-core-3.99.2.gem +0 -0
- data/vendor/cache/aws-sdk-sns-1.25.1.gem +0 -0
- data/vendor/cache/aws-sdk-sqs-1.27.1.gem +0 -0
- data/vendor/cache/aws-sigv4-1.1.4.gem +0 -0
- data/vendor/cache/codeclimate-test-reporter-1.0.9.gem +0 -0
- data/vendor/cache/coderay-1.1.2.gem +0 -0
- data/vendor/cache/concurrent-ruby-1.1.6.gem +0 -0
- data/vendor/cache/crack-0.4.3.gem +0 -0
- data/vendor/cache/diff-lcs-1.3.gem +0 -0
- data/vendor/cache/docile-1.1.5.gem +0 -0
- data/vendor/cache/google-protobuf-3.12.2-universal-darwin.gem +0 -0
- data/vendor/cache/google-protobuf-3.12.2-x86_64-linux.gem +0 -0
- data/vendor/cache/google-protobuf-3.12.2.gem +0 -0
- data/vendor/cache/googleapis-common-protos-types-1.0.2.gem +0 -0
- data/vendor/cache/grpc-1.18.0-universal-darwin.gem +0 -0
- data/vendor/cache/grpc-1.18.0-x86_64-linux.gem +0 -0
- data/vendor/cache/grpc-1.18.0.gem +0 -0
- data/vendor/cache/hashdiff-0.3.8.gem +0 -0
- data/vendor/cache/i18n-1.8.3.gem +0 -0
- data/vendor/cache/jmespath-1.4.0.gem +0 -0
- data/vendor/cache/json-2.1.0.gem +0 -0
- data/vendor/cache/memory_profiler-0.9.12.gem +0 -0
- data/vendor/cache/method_source-0.9.2.gem +0 -0
- data/vendor/cache/minitest-5.14.1.gem +0 -0
- data/vendor/cache/pry-0.12.2.gem +0 -0
- data/vendor/cache/public_suffix-3.0.3.gem +0 -0
- data/vendor/cache/rake-10.5.0.gem +0 -0
- data/vendor/cache/rspec-3.8.0.gem +0 -0
- data/vendor/cache/rspec-core-3.8.0.gem +0 -0
- data/vendor/cache/rspec-expectations-3.8.2.gem +0 -0
- data/vendor/cache/rspec-mocks-3.8.0.gem +0 -0
- data/vendor/cache/rspec-support-3.8.0.gem +0 -0
- data/vendor/cache/safe_yaml-1.0.4.gem +0 -0
- data/vendor/cache/simplecov-0.13.0.gem +0 -0
- data/vendor/cache/simplecov-html-0.10.2.gem +0 -0
- data/vendor/cache/thor-1.0.1.gem +0 -0
- data/vendor/cache/thread_safe-0.3.6.gem +0 -0
- data/vendor/cache/timecop-0.9.1.gem +0 -0
- data/vendor/cache/tzinfo-1.2.7.gem +0 -0
- data/vendor/cache/webmock-3.5.1.gem +0 -0
- data/vendor/cache/zeitwerk-2.3.0.gem +0 -0
- metadata +362 -0
checksums.yaml
ADDED
@@ -0,0 +1,7 @@
|
|
1
|
+
---
|
2
|
+
SHA256:
|
3
|
+
metadata.gz: ea4406994cf204a6e1f4d75e4f5214bce1551091beba8980d36bdf717da6c158
|
4
|
+
data.tar.gz: 724c1dd921922d02056144fe4c5c452901be2105bdfc0c62ecbbe8c8bda40e8c
|
5
|
+
SHA512:
|
6
|
+
metadata.gz: 530736b7cd4f48e51a28771221ffe0d1e87bebd6ccf74c8c8e8671e0f41bd68a5e480150d0d9c5a768bbd01c78da78251b296e819f20e0bf1089b8b5b06e9cc8
|
7
|
+
data.tar.gz: e48f7e6eeee775133b6467a99a88d5971f4c6547f6dc3208866e1aa85cea639bbab1ced3bb9ff2203d7c6cff841bb99d607c4175ac41aec6b78bd1d3bc3ec26d
|
data/.drone.yml
ADDED
data/.gitignore
ADDED
data/.rspec
ADDED
data/.ruby-version
ADDED
@@ -0,0 +1 @@
|
|
1
|
+
2.6.1
|
data/.travis.yml
ADDED
data/Gemfile
ADDED
@@ -0,0 +1,13 @@
|
|
1
|
+
source 'https://rubygems.org'
|
2
|
+
|
3
|
+
# Specify your gem's dependencies in hermes-messenger-of-the-gods.gemspec
|
4
|
+
gemspec
|
5
|
+
|
6
|
+
gem 'protobuf3_fixer', git: 'https://github.com/GetTerminus/Protobuf3Fixer.git'
|
7
|
+
gem 'grpc'
|
8
|
+
|
9
|
+
group :test do
|
10
|
+
gem "simplecov"
|
11
|
+
gem "webmock"
|
12
|
+
gem "codeclimate-test-reporter", "~> 1.0.0"
|
13
|
+
end
|
data/README.md
ADDED
@@ -0,0 +1,464 @@
|
|
1
|
+
# HermesMessengerOfTheGods
|
2
|
+
[![CircleCI](https://circleci.com/gh/GetTerminus/hermes_messenger_of_the_gods.svg?style=svg&circle-token=9f757798d1f2d06b93ee2f560c0689cc71f1f96a)](https://circleci.com/gh/GetTerminus/hermes_messenger_of_the_gods)
|
3
|
+
[![Code Climate](https://codeclimate.com/repos/58d16440cf31c32d1000041c/badges/bf27bdcafb886574909d/gpa.svg)](https://codeclimate.com/repos/58d16440cf31c32d1000041c/feed)
|
4
|
+
[![Test Coverage](https://codeclimate.com/repos/58d16440cf31c32d1000041c/badges/bf27bdcafb886574909d/coverage.svg)](https://codeclimate.com/repos/58d16440cf31c32d1000041c/coverage)
|
5
|
+
[![Issue Count](https://codeclimate.com/repos/58d16440cf31c32d1000041c/badges/bf27bdcafb886574909d/issue_count.svg)](https://codeclimate.com/repos/58d16440cf31c32d1000041c/feed)
|
6
|
+
|
7
|
+
## Installation
|
8
|
+
|
9
|
+
Add this line to your application's Gemfile:
|
10
|
+
|
11
|
+
```ruby
|
12
|
+
gem 'hermes_messenger_of_the_gods', git: 'url_of_repo'
|
13
|
+
```
|
14
|
+
|
15
|
+
And then execute:
|
16
|
+
|
17
|
+
$ bundle
|
18
|
+
|
19
|
+
Or install it yourself as:
|
20
|
+
|
21
|
+
$ gem install hermes_messenger_of_the_gods
|
22
|
+
|
23
|
+
## Usage
|
24
|
+
|
25
|
+
### The Message
|
26
|
+
|
27
|
+
A HMOTG Message includes ActiveModel::Base, so ou get alot of the joys related to that. Initialization can be setup with:
|
28
|
+
|
29
|
+
#### Creating a Message
|
30
|
+
When creating a message the most common parameters passed are the attributes
|
31
|
+
which represent the content of the message.
|
32
|
+
|
33
|
+
```ruby
|
34
|
+
class Foo
|
35
|
+
include HermesMessengerOfTheGods::Concerns::Message
|
36
|
+
attr_accessor :name
|
37
|
+
end
|
38
|
+
|
39
|
+
Foo.new(name: 'Dude').name
|
40
|
+
# => Dude
|
41
|
+
```
|
42
|
+
|
43
|
+
#### Validations
|
44
|
+
HMOTG Supports the validation syntax provided by ActiveModel::Validations.
|
45
|
+
|
46
|
+
```ruby
|
47
|
+
class Foo
|
48
|
+
include HermesMessengerOfTheGods::Concerns::Message
|
49
|
+
attr_accessor :name
|
50
|
+
validates :name, presence: true
|
51
|
+
end
|
52
|
+
|
53
|
+
instance = Foo.new(name: '')
|
54
|
+
instance.valid?
|
55
|
+
# => false
|
56
|
+
instance.errors
|
57
|
+
# => {name: ["can't be blank"]}
|
58
|
+
```
|
59
|
+
|
60
|
+
### Configuring a Endpoint
|
61
|
+
Endpoints are the recepients of message, and are typically configured per
|
62
|
+
message. The [Endpoints](https://github.com/GetTerminus/hermes_messenger_of_the_gods#endpoints)
|
63
|
+
section provides configuration details for each endpoint type.
|
64
|
+
|
65
|
+
#### Setting Endpoints
|
66
|
+
You may set a single endpoint for a mesage by assigning it to a class attribute
|
67
|
+
endpoitns
|
68
|
+
```ruby
|
69
|
+
class Foo
|
70
|
+
include HermesMessengerOfTheGods::Concerns::Message
|
71
|
+
|
72
|
+
attr_accessor :name
|
73
|
+
validates :name, presence: true
|
74
|
+
self.endpoints = {default: sns_endpoint("sns:arn", jitter: false) }
|
75
|
+
end
|
76
|
+
```
|
77
|
+
|
78
|
+
Alternatively you can set multiple endpoints using a hash syntax:
|
79
|
+
|
80
|
+
```ruby
|
81
|
+
class Foo
|
82
|
+
include HermesMessengerOfTheGods::Concerns::Message
|
83
|
+
|
84
|
+
attr_accessor :name
|
85
|
+
validates :name, presence: true
|
86
|
+
self.endpoints = {
|
87
|
+
receiver1: sns_endpoint("sns:arn", jitter: false),
|
88
|
+
receiver2: sns_endpoint("sns:arn", jitter: true),
|
89
|
+
}
|
90
|
+
end
|
91
|
+
```
|
92
|
+
|
93
|
+
**Important:** When using multiple endpoints, if one endpoint of many fails,
|
94
|
+
the entire message transmission is considered to have failed. Since we can't
|
95
|
+
take a message back from an endpoint we can't do too much about it.
|
96
|
+
|
97
|
+
#### Sending the message
|
98
|
+
Messages can be dispatched to the respective endpoints using the `dispatch` or
|
99
|
+
the error raising `dispatch!` method. By default the Message also includes a
|
100
|
+
`to_message` method which returns a hash of the object's attributes.
|
101
|
+
|
102
|
+
```ruby
|
103
|
+
class Foo
|
104
|
+
include HermesMessengerOfTheGods::Concerns::Message
|
105
|
+
|
106
|
+
attr_accessor :name
|
107
|
+
validates :name, presence: true
|
108
|
+
self.endpoints = {
|
109
|
+
default: sns_endpoint("sns:arn", jitter: false),
|
110
|
+
other: sns_endpoint('...')
|
111
|
+
}
|
112
|
+
end
|
113
|
+
|
114
|
+
Foo.new(name: 'omg').dispatch!
|
115
|
+
# => true
|
116
|
+
```
|
117
|
+
|
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
|
+
## The Worker
|
154
|
+
The worker provides a generic class to provide access for reading from
|
155
|
+
endpoints. Only some endpoints actually provide the ability to read messages.
|
156
|
+
|
157
|
+
### Configuration
|
158
|
+
Workers can be configured with a single endpoint and a single MessageClass for
|
159
|
+
deserialization.
|
160
|
+
|
161
|
+
```ruby
|
162
|
+
class MyWorker
|
163
|
+
include HermesMessengerOfTheGods::Concerns::Worker
|
164
|
+
|
165
|
+
self.endpoint = sns_endpoint("sns::arn", jitter: false)
|
166
|
+
self.deserialize_with = MessageType
|
167
|
+
end
|
168
|
+
```
|
169
|
+
|
170
|
+
### Getting the work done
|
171
|
+
When working off a messages coming from an endpoint, there are a few possible
|
172
|
+
paths the message can take.
|
173
|
+
|
174
|
+
1. You may define a `perform` method on the worker which takes the message
|
175
|
+
instance as the only argument.
|
176
|
+
2. If a `perform` method is not defined on the worker, a `perform` method is
|
177
|
+
expected to be defined on the message itself. This method is called with no
|
178
|
+
arguments.
|
179
|
+
3. If no `perform` method is found on the Worker or the Message an error is
|
180
|
+
raised.
|
181
|
+
|
182
|
+
**Note:** A `perform` method on the worker is perfered to a perform method on
|
183
|
+
the message.
|
184
|
+
|
185
|
+
### Error Handling
|
186
|
+
When a messsage fails to run, the `handle_failure` on the worker is invoked.
|
187
|
+
This method is called with two arguments:
|
188
|
+
|
189
|
+
1. The message itself
|
190
|
+
2. The exception itself.
|
191
|
+
|
192
|
+
By default this method simply passes the job and exception to the endpoint so
|
193
|
+
it can be handled as appropiate. If you overload this method you probably want
|
194
|
+
to ensure you call `super`.
|
195
|
+
|
196
|
+
### Message Deserialization
|
197
|
+
Messages coming off the endpoints need to be deserialized into the domain
|
198
|
+
message. By default we expect you are deserializing into a
|
199
|
+
HermesMessengerOfTheGods::Concerns::Message, but it can be anything really.
|
200
|
+
|
201
|
+
In order to turn the received message into the Object we expect a class method
|
202
|
+
`.from_message` to be defined. The HermesMessengerOfTheGods::Message superclass
|
203
|
+
defines a basic one that expects all attributes present in the message to be
|
204
|
+
`attr_accessor`s on the message object.
|
205
|
+
|
206
|
+
The method used to create the message object can be overloaded by setting
|
207
|
+
`deserialize_method` class variable of the worker.
|
208
|
+
|
209
|
+
```ruby
|
210
|
+
class MessageType
|
211
|
+
include HermesMessengerOfTheGods::Concerns::Message
|
212
|
+
|
213
|
+
attr_accessor :dude, :hrm
|
214
|
+
|
215
|
+
delf self.omg_dude(msg)
|
216
|
+
new(dude: msg["old_dude"], hrm: nil)
|
217
|
+
end
|
218
|
+
end
|
219
|
+
|
220
|
+
class AwesomeWorker < HermesMessengerOfTheGods::Worker
|
221
|
+
self.endpoint = {
|
222
|
+
default: sns_endpoint("sns::arn", jitter: false)
|
223
|
+
}
|
224
|
+
self.deserialize_with = MessageType
|
225
|
+
self.deserialize_method = :omg_dude
|
226
|
+
end
|
227
|
+
```
|
228
|
+
|
229
|
+
If the endpoint emits a hash with only the keys `:dude` and `:hrm` you can get
|
230
|
+
away without defining any `deserialize_with` setting. However if you need to do
|
231
|
+
some translations, you can define the custom builder function such as `omg_dude`
|
232
|
+
above.
|
233
|
+
|
234
|
+
### Execution
|
235
|
+
For a single queue `./bin/fly_hermes start --worker={worker job}`
|
236
|
+
For pooled operation `./bin/fly_hermes start --pool {worker job}--{count} {worker2 job}--{count} {worker3 job}--{count}
|
237
|
+
|
238
|
+
## Message & Worker in one class
|
239
|
+
When your message meets a few constraints you can combine the logic of the worker
|
240
|
+
and the message into a single class.
|
241
|
+
|
242
|
+
* You may only use one endpoint (due to limitation on the worker)
|
243
|
+
* The endpoint must be both readable and writable (No SNS for example)
|
244
|
+
* You do not need to customize callbacks much
|
245
|
+
|
246
|
+
```ruby
|
247
|
+
class MonoMessageWorker
|
248
|
+
include HermesMessengerOftheGods::Concerns::MonoMessage
|
249
|
+
|
250
|
+
self.endpoints = { default: sqs_endpoint("arn") } # Only 1 endpoint, options are supported
|
251
|
+
|
252
|
+
def perform
|
253
|
+
# Do magic Here
|
254
|
+
end
|
255
|
+
end
|
256
|
+
```
|
257
|
+
|
258
|
+
You may then start the message execution with:
|
259
|
+
|
260
|
+
`./bin/fly_hermes start --pool=MonoMessageWorker--1`
|
261
|
+
|
262
|
+
|
263
|
+
## Protocol Buffers
|
264
|
+
Hermes supports using ProtoBuffers over the wire using the
|
265
|
+
`HermesMessengerOfTheGods::Concerns::GrpcProtobuf` mixin. Currently only JSON
|
266
|
+
encoding is allowed.
|
267
|
+
|
268
|
+
Example:
|
269
|
+
|
270
|
+
```ruby
|
271
|
+
class MessageA
|
272
|
+
include HermesMessengerOfTheGods::Concerns::Message
|
273
|
+
include HermesMessengerOfTheGods::Concerns::GrpcProtobuf
|
274
|
+
self.protobuf_class = Helloworld::HelloRequest
|
275
|
+
end
|
276
|
+
|
277
|
+
# Or
|
278
|
+
|
279
|
+
class MessageB
|
280
|
+
include HermesMessengerOftheGods::Concerns::MonoMessage
|
281
|
+
include HermesMessengerOfTheGods::Concerns::GrpcProtobuf
|
282
|
+
self.protobuf_class = Helloworld::HelloRequest
|
283
|
+
end
|
284
|
+
```
|
285
|
+
|
286
|
+
This will use the Protobuf encoder and decoder for transmission on the wire.
|
287
|
+
|
288
|
+
### Notes:
|
289
|
+
|
290
|
+
1) Message initialization now requires the first parameter be an instance
|
291
|
+
of the provided protobuf.
|
292
|
+
2) If you are are using Dispatch helpers, you probably need to define a
|
293
|
+
specific builder.
|
294
|
+
3) If you are lazy, you can use `.from_message` and pass a hash.
|
295
|
+
|
296
|
+
## Health Check HTTP Server
|
297
|
+
Hermes comes with a built in HTTP Health check server that may be optionally enabled. The server responds with `200 OK`
|
298
|
+
when everything is going okay, and `500 Internal Server Error` when things seem out of wack.
|
299
|
+
|
300
|
+
The basic logic of the sever is as follows:
|
301
|
+
|
302
|
+
1) The server becomes unhealthy if no work has been performed in 60 seconds (customizable with the environment
|
303
|
+
variable `HERMES_MINIMUM_WORK_FREQUENCY`) AND the endpoint reports there is work to do.
|
304
|
+
2) The server always reports healthy when there is no pending work to be done.
|
305
|
+
|
306
|
+
Pending work for an SQS queue is when there is at least one message visible in the queue.
|
307
|
+
|
308
|
+
In order to enable the HTTP Health Check server, you should set the environment variable `ENABLE_HERMES_HEALTH_CHECK` to
|
309
|
+
and value except `false`. The port the server listens on is configurable using `HERMES_WORKER_STATUS_PORT` defaulting to 4242.
|
310
|
+
|
311
|
+
|
312
|
+
## Endpoints
|
313
|
+
Endpoints provide the external communication layer to the outside world.
|
314
|
+
Generally speaking all endpoints should inherit from the base endpoint to
|
315
|
+
provide common behaviors.
|
316
|
+
|
317
|
+
Endpoint creation takes two parameters, the first is the "endpoint", the second
|
318
|
+
is a options hash. Endpoint is required, while options provide more fine
|
319
|
+
grained control of the endpoint behavior. The content of both parameters is
|
320
|
+
dependent on the backing endpoint.
|
321
|
+
|
322
|
+
### General Endpoint Behavior
|
323
|
+
Each end point needs to define a `transmit` method. Beyond that the basic
|
324
|
+
behavior common to all end points will be automatically added.
|
325
|
+
|
326
|
+
### Dispatching a message to an endpoint
|
327
|
+
Dispatching a message into a endpoint can be accomplished by calling `dispatch`
|
328
|
+
and passing the message in as the first parameter.
|
329
|
+
|
330
|
+
* `dispatch(message)` returns true or false to represent success or failure
|
331
|
+
* `dispatch!(message)` returns true on success, and raises the last error received on failure
|
332
|
+
|
333
|
+
### Message Transformations
|
334
|
+
The endpoint will request the content to deliver from the message object itself.
|
335
|
+
A heirachy of methods will be used to determine wich method to use.
|
336
|
+
|
337
|
+
1. You may provide an options during creation of the endpoint, `:transformer` and that will be used. This can be a proc, or a method name. The proc will be called with the object as the first parameter
|
338
|
+
2. `to_<endpoint_type>_message` - For any endpoint, the class name will be transformed into a dynamic method call. For example the SnsFoo endpoint will look for `to_sns_foo_message`.
|
339
|
+
3. `to_message` - Generic to_message handler for the class.
|
340
|
+
4. Finally the transmitted message itself. You probably don't want this since most message objects do not serialize well.
|
341
|
+
|
342
|
+
### Backoffs
|
343
|
+
By default a linear backoff is used of 1 second per number of tries. You can
|
344
|
+
configure this by passing the `:backoff` option with `:linear` or
|
345
|
+
`:exponential`. If you prefer to write your own backoff, you can also pass a
|
346
|
+
proc to the backoff method. A `:backoff` value of nil will disable any backoffs.
|
347
|
+
|
348
|
+
Jitter is added by default to the backoff time. This can be disabled by passing
|
349
|
+
`jitter: false` in with the options.
|
350
|
+
|
351
|
+
### Error Handling
|
352
|
+
By default all standard errors are caught and retried, with the exceptoin of
|
353
|
+
`HermesMessengerOfTheGods::Endpoints::FatalError`. If this error is raised
|
354
|
+
there will be no further retries.
|
355
|
+
|
356
|
+
All errors raised during execution will be stored in the `endpoint.errors`
|
357
|
+
array.
|
358
|
+
|
359
|
+
### SNS Endpoint
|
360
|
+
* `endpoint` - the ARN of the SNS endpoint to publish to.
|
361
|
+
* Avaialable options:
|
362
|
+
* `:client_options` - a hash of options to pass to the [SNS::Topic](http://docs.aws.amazon.com/sdkforruby/api/Aws/SNS/Topic.html) during creation. If your ENV is setup with all required AWS keys you won't need to set anything here.
|
363
|
+
* `:publish_options` - a hash of options to pass into the publish command for the [SNS::Topic](http://docs.aws.amazon.com/sdkforruby/api/Aws/SNS/Topic.html#publish-instance_method). The message key will always be overwritten. You can also provide a proc, which will be passed the message per transmission and is expected to return a hash with options. A proc can be used to set message_attributes that rely on variables from the message body.
|
364
|
+
|
365
|
+
### SQS Endpoint
|
366
|
+
* `endpoint` - the URL of the SQS queue to poll.
|
367
|
+
* Avaialable options:
|
368
|
+
* `:client_options` - a hash of options to pass to the [SNS::Queue](http://docs.aws.amazon.com/AWSRubySDK/latest/AWS/SQS/Queue.html) during creation. If your ENV is setup with all required AWS keys you won't need to set anything here.
|
369
|
+
* `:poll_options` - a hash of options to pass into the poll command for the [SQS::QueuePoller](http://docs.aws.amazon.com/sdkforruby/api/Aws/SQS/QueuePoller.html#poll-instance_method).
|
370
|
+
* `:send_options` - a hash of options to pass into the send_message command for the [SQS::Queue](http://docs.aws.amazon.com/AWSRubySDK/latest/AWS/SQS/Queue.html#send_message-instance_method). The message_body key will always be overwritten. You can also provide a proc, which will be passed the message per transmission and is expected to return a hash with options.
|
371
|
+
* `:jsonify` - converts the trasnmitted data to json prior to transmission
|
372
|
+
* `:from_sns` - reads and converts from JSON the serialized Message key
|
373
|
+
|
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
|
+
## Global Configuration
|
405
|
+
When configuring HMOTG you can set global configuration opions like so:
|
406
|
+
|
407
|
+
```ruby
|
408
|
+
HermesMessengerOfTheGods.config do |config|
|
409
|
+
config.config_options = wassup
|
410
|
+
end
|
411
|
+
```
|
412
|
+
|
413
|
+
Allowed configuration options:
|
414
|
+
|
415
|
+
| Configuration Option | Default | Allowed Values
|
416
|
+
| -------------------- | --------------------- | --------------
|
417
|
+
| logger | Ruby Logger to STDOUT | A single or array of logger like objects
|
418
|
+
| quiet | false | Set this to true and all logging will be disabled
|
419
|
+
| delay_strategy | :smart | This value can be a symbol representing the delay strategy, or a proc which will be expected to do the delaying
|
420
|
+
| delay_options | {} | A set of default options to use when delaying. The contents of this hash are dependent on the `delay_strategy` used
|
421
|
+
|
422
|
+
## Logging
|
423
|
+
`HermesMessengerOfTheGods::Message`, `HermesMessengerOfTheGods::Worker` have
|
424
|
+
access to a unified set of logging helpers which respect the global logging
|
425
|
+
configuration. These helpers correspond to the configured `Logger::Severity`
|
426
|
+
constant. `debug`, `info`, `warn`, `error`, and `fatal` are provided by default.
|
427
|
+
|
428
|
+
All methods which correspond to a severity level take a single message
|
429
|
+
parameter, or a block which is expected to return the message.
|
430
|
+
[With the same behavior as the default logger](http://ruby-doc.org/stdlib-1.9.3/libdoc/logger/rdoc/Logger.html#class-Logger-label-How+to+log+a+message).
|
431
|
+
|
432
|
+
|
433
|
+
Additionally the `say` method is provided which takes the desired level contsant
|
434
|
+
as the first parameter. `say(Logger::ERROR, "foo")`
|
435
|
+
|
436
|
+
### Outputters
|
437
|
+
Hermes ships and attaches a Basic logger for by default. The primary warning is
|
438
|
+
that the basic output will default to the `inspect` output of your message. If
|
439
|
+
your message contains a significant number of, or complex, instance variables
|
440
|
+
There may be more info logged then is necessary to identify the message.
|
441
|
+
|
442
|
+
As such you can overwrite the `inspect` method, or create the custom
|
443
|
+
`to_log_s` method which will be used instead.
|
444
|
+
|
445
|
+
Example regular output:
|
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!`
|
454
|
+
|
455
|
+
## Development
|
456
|
+
|
457
|
+
After checking out the repo, run `bin/setup` to install dependencies. Then, run `rake spec` to run the tests. You can also run `bin/console` for an interactive prompt that will allow you to experiment.
|
458
|
+
|
459
|
+
To install this gem onto your local machine, run `bundle exec rake install`. To release a new version, update the version number in `version.rb`, and then run `bundle exec rake release`, which will create a git tag for the version, push git commits and tags, and push the `.gem` file to [rubygems.org](https://rubygems.org).
|
460
|
+
|
461
|
+
## Contributing
|
462
|
+
|
463
|
+
Bug reports and pull requests are welcome on GitHub at https://github.com/[USERNAME]/hermes-messenger-of-the-gods.
|
464
|
+
|