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.
Files changed (136) hide show
  1. checksums.yaml +7 -0
  2. data/.drone.yml +9 -0
  3. data/.gitignore +12 -0
  4. data/.rspec +3 -0
  5. data/.ruby-version +1 -0
  6. data/.travis.yml +5 -0
  7. data/Gemfile +13 -0
  8. data/README.md +464 -0
  9. data/Rakefile +6 -0
  10. data/bin/console +14 -0
  11. data/bin/setup +8 -0
  12. data/exe/fly_hermes +57 -0
  13. data/hermes_messenger_of_the_gods.gemspec +38 -0
  14. data/lib/hermes_messenger_of_the_gods.rb +57 -0
  15. data/lib/hermes_messenger_of_the_gods/concerns/base.rb +42 -0
  16. data/lib/hermes_messenger_of_the_gods/concerns/grpc_protobuf.rb +62 -0
  17. data/lib/hermes_messenger_of_the_gods/concerns/message.rb +194 -0
  18. data/lib/hermes_messenger_of_the_gods/concerns/mono_message.rb +52 -0
  19. data/lib/hermes_messenger_of_the_gods/concerns/worker.rb +173 -0
  20. data/lib/hermes_messenger_of_the_gods/configuration.rb +29 -0
  21. data/lib/hermes_messenger_of_the_gods/endpoint_builder.rb +41 -0
  22. data/lib/hermes_messenger_of_the_gods/endpoints.rb +3 -0
  23. data/lib/hermes_messenger_of_the_gods/endpoints/base.rb +113 -0
  24. data/lib/hermes_messenger_of_the_gods/endpoints/sns.rb +21 -0
  25. data/lib/hermes_messenger_of_the_gods/endpoints/sqs.rb +114 -0
  26. data/lib/hermes_messenger_of_the_gods/exceptions.rb +27 -0
  27. data/lib/hermes_messenger_of_the_gods/logging_helpers.rb +30 -0
  28. data/lib/hermes_messenger_of_the_gods/output/basic.rb +63 -0
  29. data/lib/hermes_messenger_of_the_gods/status_server.rb +48 -0
  30. data/lib/hermes_messenger_of_the_gods/testing/array_endpoint.rb +46 -0
  31. data/lib/hermes_messenger_of_the_gods/testing/dispatch_matcher.rb +52 -0
  32. data/lib/hermes_messenger_of_the_gods/testing/rspec_helpers.rb +64 -0
  33. data/lib/hermes_messenger_of_the_gods/version.rb +3 -0
  34. data/packageGems.sh +13 -0
  35. data/vendor/cache/Protobuf3Fixer-5f9f1a2d2da9/.bundlecache +0 -0
  36. data/vendor/cache/Protobuf3Fixer-5f9f1a2d2da9/.circleci/config.yml +32 -0
  37. data/vendor/cache/Protobuf3Fixer-5f9f1a2d2da9/.gitignore +11 -0
  38. data/vendor/cache/Protobuf3Fixer-5f9f1a2d2da9/.rspec +3 -0
  39. data/vendor/cache/Protobuf3Fixer-5f9f1a2d2da9/.rubocop.yml +42 -0
  40. data/vendor/cache/Protobuf3Fixer-5f9f1a2d2da9/.ruby-version +1 -0
  41. data/vendor/cache/Protobuf3Fixer-5f9f1a2d2da9/.travis.yml +5 -0
  42. data/vendor/cache/Protobuf3Fixer-5f9f1a2d2da9/Gemfile +6 -0
  43. data/vendor/cache/Protobuf3Fixer-5f9f1a2d2da9/Gemfile.lock +75 -0
  44. data/vendor/cache/Protobuf3Fixer-5f9f1a2d2da9/Makefile +1 -0
  45. data/vendor/cache/Protobuf3Fixer-5f9f1a2d2da9/README.md +78 -0
  46. data/vendor/cache/Protobuf3Fixer-5f9f1a2d2da9/Rakefile +6 -0
  47. data/vendor/cache/Protobuf3Fixer-5f9f1a2d2da9/bin/bundle +105 -0
  48. data/vendor/cache/Protobuf3Fixer-5f9f1a2d2da9/bin/coderay +29 -0
  49. data/vendor/cache/Protobuf3Fixer-5f9f1a2d2da9/bin/console +14 -0
  50. data/vendor/cache/Protobuf3Fixer-5f9f1a2d2da9/bin/grpc_tools_ruby_protoc +29 -0
  51. data/vendor/cache/Protobuf3Fixer-5f9f1a2d2da9/bin/grpc_tools_ruby_protoc_plugin +29 -0
  52. data/vendor/cache/Protobuf3Fixer-5f9f1a2d2da9/bin/htmldiff +29 -0
  53. data/vendor/cache/Protobuf3Fixer-5f9f1a2d2da9/bin/ldiff +29 -0
  54. data/vendor/cache/Protobuf3Fixer-5f9f1a2d2da9/bin/pry +29 -0
  55. data/vendor/cache/Protobuf3Fixer-5f9f1a2d2da9/bin/rake +29 -0
  56. data/vendor/cache/Protobuf3Fixer-5f9f1a2d2da9/bin/rspec +29 -0
  57. data/vendor/cache/Protobuf3Fixer-5f9f1a2d2da9/bin/rubocop +29 -0
  58. data/vendor/cache/Protobuf3Fixer-5f9f1a2d2da9/bin/ruby-parse +29 -0
  59. data/vendor/cache/Protobuf3Fixer-5f9f1a2d2da9/bin/ruby-rewrite +29 -0
  60. data/vendor/cache/Protobuf3Fixer-5f9f1a2d2da9/bin/setup +8 -0
  61. data/vendor/cache/Protobuf3Fixer-5f9f1a2d2da9/lib/protobuf3_fixer.rb +123 -0
  62. data/vendor/cache/Protobuf3Fixer-5f9f1a2d2da9/lib/protobuf3_fixer/encoder.rb +63 -0
  63. data/vendor/cache/Protobuf3Fixer-5f9f1a2d2da9/lib/protobuf3_fixer/generation_helpers.rb +23 -0
  64. data/vendor/cache/Protobuf3Fixer-5f9f1a2d2da9/lib/protobuf3_fixer/reflector.rb +66 -0
  65. data/vendor/cache/Protobuf3Fixer-5f9f1a2d2da9/lib/protobuf3_fixer/version.rb +3 -0
  66. data/vendor/cache/Protobuf3Fixer-5f9f1a2d2da9/protobuf3_fixer.gemspec +54 -0
  67. data/vendor/cache/Protobuf3Fixer-5f9f1a2d2da9/rubocop/bundle +105 -0
  68. data/vendor/cache/Protobuf3Fixer-5f9f1a2d2da9/rubocop/coderay +29 -0
  69. data/vendor/cache/Protobuf3Fixer-5f9f1a2d2da9/rubocop/grpc_tools_ruby_protoc +29 -0
  70. data/vendor/cache/Protobuf3Fixer-5f9f1a2d2da9/rubocop/grpc_tools_ruby_protoc_plugin +29 -0
  71. data/vendor/cache/Protobuf3Fixer-5f9f1a2d2da9/rubocop/htmldiff +29 -0
  72. data/vendor/cache/Protobuf3Fixer-5f9f1a2d2da9/rubocop/ldiff +29 -0
  73. data/vendor/cache/Protobuf3Fixer-5f9f1a2d2da9/rubocop/pry +29 -0
  74. data/vendor/cache/Protobuf3Fixer-5f9f1a2d2da9/rubocop/rake +29 -0
  75. data/vendor/cache/Protobuf3Fixer-5f9f1a2d2da9/rubocop/rspec +29 -0
  76. data/vendor/cache/Protobuf3Fixer-5f9f1a2d2da9/rubocop/rubocop +29 -0
  77. data/vendor/cache/Protobuf3Fixer-5f9f1a2d2da9/rubocop/ruby-parse +29 -0
  78. data/vendor/cache/Protobuf3Fixer-5f9f1a2d2da9/rubocop/ruby-rewrite +29 -0
  79. data/vendor/cache/Protobuf3Fixer-5f9f1a2d2da9/spec/build_from_hash_spec.rb +20 -0
  80. data/vendor/cache/Protobuf3Fixer-5f9f1a2d2da9/spec/encoding/encoding_options_spec.rb +23 -0
  81. data/vendor/cache/Protobuf3Fixer-5f9f1a2d2da9/spec/extra_fields/json_decode_of_superset_spec.rb +54 -0
  82. data/vendor/cache/Protobuf3Fixer-5f9f1a2d2da9/spec/generation_helpers_spec.rb +37 -0
  83. data/vendor/cache/Protobuf3Fixer-5f9f1a2d2da9/spec/protobuf3_fixer_spec.rb +5 -0
  84. data/vendor/cache/Protobuf3Fixer-5f9f1a2d2da9/spec/spec_helper.rb +17 -0
  85. data/vendor/cache/Protobuf3Fixer-5f9f1a2d2da9/spec/support/compiled_protobuffs/source/superset_pb.rb +44 -0
  86. data/vendor/cache/Protobuf3Fixer-5f9f1a2d2da9/spec/support/compiled_protobuffs/source/timestamp_pb.rb +27 -0
  87. data/vendor/cache/Protobuf3Fixer-5f9f1a2d2da9/spec/support/protobuffs/source/superset.proto +40 -0
  88. data/vendor/cache/Protobuf3Fixer-5f9f1a2d2da9/spec/support/protobuffs/source/timestamp.proto +18 -0
  89. data/vendor/cache/Protobuf3Fixer-5f9f1a2d2da9/spec/well_known_type_fixes/timestamp_spec.rb +79 -0
  90. data/vendor/cache/activemodel-6.0.3.1.gem +0 -0
  91. data/vendor/cache/activesupport-6.0.3.1.gem +0 -0
  92. data/vendor/cache/addressable-2.6.0.gem +0 -0
  93. data/vendor/cache/aws-eventstream-1.1.0.gem +0 -0
  94. data/vendor/cache/aws-partitions-1.329.0.gem +0 -0
  95. data/vendor/cache/aws-sdk-core-3.99.2.gem +0 -0
  96. data/vendor/cache/aws-sdk-sns-1.25.1.gem +0 -0
  97. data/vendor/cache/aws-sdk-sqs-1.27.1.gem +0 -0
  98. data/vendor/cache/aws-sigv4-1.1.4.gem +0 -0
  99. data/vendor/cache/codeclimate-test-reporter-1.0.9.gem +0 -0
  100. data/vendor/cache/coderay-1.1.2.gem +0 -0
  101. data/vendor/cache/concurrent-ruby-1.1.6.gem +0 -0
  102. data/vendor/cache/crack-0.4.3.gem +0 -0
  103. data/vendor/cache/diff-lcs-1.3.gem +0 -0
  104. data/vendor/cache/docile-1.1.5.gem +0 -0
  105. data/vendor/cache/google-protobuf-3.12.2-universal-darwin.gem +0 -0
  106. data/vendor/cache/google-protobuf-3.12.2-x86_64-linux.gem +0 -0
  107. data/vendor/cache/google-protobuf-3.12.2.gem +0 -0
  108. data/vendor/cache/googleapis-common-protos-types-1.0.2.gem +0 -0
  109. data/vendor/cache/grpc-1.18.0-universal-darwin.gem +0 -0
  110. data/vendor/cache/grpc-1.18.0-x86_64-linux.gem +0 -0
  111. data/vendor/cache/grpc-1.18.0.gem +0 -0
  112. data/vendor/cache/hashdiff-0.3.8.gem +0 -0
  113. data/vendor/cache/i18n-1.8.3.gem +0 -0
  114. data/vendor/cache/jmespath-1.4.0.gem +0 -0
  115. data/vendor/cache/json-2.1.0.gem +0 -0
  116. data/vendor/cache/memory_profiler-0.9.12.gem +0 -0
  117. data/vendor/cache/method_source-0.9.2.gem +0 -0
  118. data/vendor/cache/minitest-5.14.1.gem +0 -0
  119. data/vendor/cache/pry-0.12.2.gem +0 -0
  120. data/vendor/cache/public_suffix-3.0.3.gem +0 -0
  121. data/vendor/cache/rake-10.5.0.gem +0 -0
  122. data/vendor/cache/rspec-3.8.0.gem +0 -0
  123. data/vendor/cache/rspec-core-3.8.0.gem +0 -0
  124. data/vendor/cache/rspec-expectations-3.8.2.gem +0 -0
  125. data/vendor/cache/rspec-mocks-3.8.0.gem +0 -0
  126. data/vendor/cache/rspec-support-3.8.0.gem +0 -0
  127. data/vendor/cache/safe_yaml-1.0.4.gem +0 -0
  128. data/vendor/cache/simplecov-0.13.0.gem +0 -0
  129. data/vendor/cache/simplecov-html-0.10.2.gem +0 -0
  130. data/vendor/cache/thor-1.0.1.gem +0 -0
  131. data/vendor/cache/thread_safe-0.3.6.gem +0 -0
  132. data/vendor/cache/timecop-0.9.1.gem +0 -0
  133. data/vendor/cache/tzinfo-1.2.7.gem +0 -0
  134. data/vendor/cache/webmock-3.5.1.gem +0 -0
  135. data/vendor/cache/zeitwerk-2.3.0.gem +0 -0
  136. metadata +362 -0
@@ -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
@@ -0,0 +1,9 @@
1
+
2
+ pipeline:
3
+ test:
4
+ image: getterminus/ruby-ci-image:2.6-je-20190205
5
+ group: test
6
+ secrets: [ CODECOV_TOKEN ]
7
+ commands:
8
+ - bundle --local
9
+ - bundle exec rspec
@@ -0,0 +1,12 @@
1
+ /.yardoc
2
+ /Gemfile.lock
3
+ /_yardoc/
4
+ /coverage/
5
+ /doc/
6
+ /pkg/
7
+ /spec/reports/
8
+ /tmp/
9
+
10
+ # rspec failure tracking
11
+ .rspec_status
12
+ .bundle
data/.rspec ADDED
@@ -0,0 +1,3 @@
1
+ --order rand
2
+ --format documentation
3
+ --color
@@ -0,0 +1 @@
1
+ 2.6.1
@@ -0,0 +1,5 @@
1
+ sudo: false
2
+ language: ruby
3
+ rvm:
4
+ - 2.1.7
5
+ before_install: gem install bundler -v 1.14.6
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
@@ -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
+