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
data/Rakefile
ADDED
data/bin/console
ADDED
@@ -0,0 +1,14 @@
|
|
1
|
+
#!/usr/bin/env ruby
|
2
|
+
|
3
|
+
require "bundler/setup"
|
4
|
+
require "hermes_messenger_of_the_gods"
|
5
|
+
|
6
|
+
# You can add fixtures and/or initialization code here to make experimenting
|
7
|
+
# with your gem easier. You can also use a different console, if you like.
|
8
|
+
|
9
|
+
# (If you use this, don't forget to add pry to your Gemfile!)
|
10
|
+
# require "pry"
|
11
|
+
# Pry.start
|
12
|
+
|
13
|
+
require "irb"
|
14
|
+
IRB.start(__FILE__)
|
data/bin/setup
ADDED
data/exe/fly_hermes
ADDED
@@ -0,0 +1,57 @@
|
|
1
|
+
#!/usr/bin/env ruby
|
2
|
+
|
3
|
+
require 'thor'
|
4
|
+
require 'bundler/setup'
|
5
|
+
require 'hermes_messenger_of_the_gods'
|
6
|
+
|
7
|
+
class FlyHermes < Thor
|
8
|
+
desc 'start', 'Starts a worker'
|
9
|
+
method_option :worker, type: :string
|
10
|
+
method_option :pool, type: :array
|
11
|
+
method_option :require, type: :string
|
12
|
+
method_option :name, type: :string
|
13
|
+
|
14
|
+
def start
|
15
|
+
if options[:require]
|
16
|
+
require options[:require]
|
17
|
+
else
|
18
|
+
require File.expand_path('config/environment.rb')
|
19
|
+
end
|
20
|
+
|
21
|
+
pools = []
|
22
|
+
if options[:worker]
|
23
|
+
pools << [options[:worker].constantize, 1]
|
24
|
+
elsif options[:pool]
|
25
|
+
|
26
|
+
options[:pool].each do |pool|
|
27
|
+
pool_klass, pool_size = pool.split('--', 2)
|
28
|
+
pool_size = pool_size.to_i if pool_size
|
29
|
+
raise "Pool size must be > 0" if pool_size.nil? or pool_size < 1
|
30
|
+
|
31
|
+
pools << [
|
32
|
+
pool_klass.constantize,
|
33
|
+
pool_size
|
34
|
+
]
|
35
|
+
end
|
36
|
+
end
|
37
|
+
|
38
|
+
if pools.empty?
|
39
|
+
raise "No workers specified. --worker or --pool is required"
|
40
|
+
end
|
41
|
+
|
42
|
+
pools.each do |worker_klass, count|
|
43
|
+
count.times do |i|
|
44
|
+
fork do
|
45
|
+
worker = worker_klass.build_worker
|
46
|
+
worker.name = options[:name] if options[:name]
|
47
|
+
worker.name += "::#{i}"
|
48
|
+
worker.work_off
|
49
|
+
end
|
50
|
+
end
|
51
|
+
end
|
52
|
+
|
53
|
+
Process.waitall
|
54
|
+
end
|
55
|
+
end
|
56
|
+
|
57
|
+
FlyHermes.start(ARGV)
|
@@ -0,0 +1,38 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
lib = File.expand_path('lib', __dir__)
|
4
|
+
$LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
|
5
|
+
require 'hermes_messenger_of_the_gods/version'
|
6
|
+
|
7
|
+
Gem::Specification.new do |spec|
|
8
|
+
spec.name = 'hermes_messenger_of_the_gods'
|
9
|
+
spec.version = HermesMessengerOfTheGods::VERSION
|
10
|
+
spec.authors = ['Brian Malinconico', 'Stevie Vines']
|
11
|
+
spec.email = ['bmalinconico@terminus.com', 'stevievines@gmail.com']
|
12
|
+
spec.metadata['allowed_push_host'] = "https://www.rubygems.org"
|
13
|
+
|
14
|
+
spec.summary = 'Create and receive messages like a god!'
|
15
|
+
spec.description = 'Things'
|
16
|
+
|
17
|
+
spec.files = `git ls-files -z`.split("\x0").reject do |f|
|
18
|
+
f.match(%r{^(test|spec|features)/})
|
19
|
+
end
|
20
|
+
spec.bindir = 'exe'
|
21
|
+
spec.executables = spec.files.grep(%r{^exe/}) { |f| File.basename(f) }
|
22
|
+
spec.require_paths = ['lib']
|
23
|
+
|
24
|
+
spec.add_dependency 'activemodel', '> 4.2.3'
|
25
|
+
spec.add_dependency 'activesupport', '> 4.2.3'
|
26
|
+
spec.add_dependency 'aws-sdk-sns', '~> 1.0'
|
27
|
+
spec.add_dependency 'aws-sdk-sqs', '~> 1.0'
|
28
|
+
spec.add_dependency 'protobuf3_fixer'
|
29
|
+
spec.add_dependency 'thor'
|
30
|
+
|
31
|
+
spec.add_development_dependency 'bundler', '~> 2.0'
|
32
|
+
spec.add_development_dependency 'memory_profiler'
|
33
|
+
spec.add_development_dependency 'pry'
|
34
|
+
spec.add_development_dependency 'rake', '~> 10.0'
|
35
|
+
spec.add_development_dependency 'rspec', '~> 3.0'
|
36
|
+
spec.add_development_dependency 'simplecov', '~> 1.14'
|
37
|
+
spec.add_development_dependency 'timecop'
|
38
|
+
end
|
@@ -0,0 +1,57 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require 'hermes_messenger_of_the_gods/version'
|
4
|
+
|
5
|
+
require 'hermes_messenger_of_the_gods/exceptions'
|
6
|
+
require 'hermes_messenger_of_the_gods/configuration'
|
7
|
+
|
8
|
+
require 'hermes_messenger_of_the_gods/logging_helpers'
|
9
|
+
require 'hermes_messenger_of_the_gods/endpoint_builder'
|
10
|
+
|
11
|
+
require 'hermes_messenger_of_the_gods/concerns/base'
|
12
|
+
require 'hermes_messenger_of_the_gods/concerns/message'
|
13
|
+
require 'hermes_messenger_of_the_gods/concerns/worker'
|
14
|
+
require 'hermes_messenger_of_the_gods/concerns/mono_message'
|
15
|
+
require 'hermes_messenger_of_the_gods/concerns/grpc_protobuf'
|
16
|
+
|
17
|
+
require 'hermes_messenger_of_the_gods/endpoints'
|
18
|
+
|
19
|
+
require 'hermes_messenger_of_the_gods/output/basic'
|
20
|
+
|
21
|
+
module HermesMessengerOfTheGods
|
22
|
+
class << self
|
23
|
+
def configuration
|
24
|
+
@configuration ||= Configuration.new
|
25
|
+
end
|
26
|
+
|
27
|
+
def configure
|
28
|
+
yield(configuration) if block_given?
|
29
|
+
configuration
|
30
|
+
end
|
31
|
+
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
|
+
end
|
57
|
+
end
|
@@ -0,0 +1,42 @@
|
|
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
|
@@ -0,0 +1,62 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require 'protobuf3_fixer'
|
4
|
+
module HermesMessengerOfTheGods
|
5
|
+
module Concerns
|
6
|
+
module GrpcProtobuf
|
7
|
+
extend ActiveSupport::Concern
|
8
|
+
|
9
|
+
included do
|
10
|
+
class_attribute :_protobuf_class
|
11
|
+
|
12
|
+
alias_method :_pre_grpc_protobuff_init, :initialize
|
13
|
+
def initialize(protobuf, options = {})
|
14
|
+
unless protobuf.is_a?(self.class._protobuf_class)
|
15
|
+
raise "#{self.class} requires a Protobuf for initialization"
|
16
|
+
end
|
17
|
+
|
18
|
+
_pre_grpc_protobuff_init(protobuf.to_h.merge!(options))
|
19
|
+
end
|
20
|
+
|
21
|
+
def _build_for_transmission
|
22
|
+
# Hermes expects a hash
|
23
|
+
JSON.parse(serialize_with_defaults)
|
24
|
+
end
|
25
|
+
|
26
|
+
def serialize_with_defaults
|
27
|
+
# Use the protobuf class' encode_json to generate defaults for any missing keys
|
28
|
+
self.class._protobuf_class.encode_json(message_as_proto, emit_defaults: true)
|
29
|
+
end
|
30
|
+
|
31
|
+
def message_as_proto
|
32
|
+
# Build a proto with the incoming hash
|
33
|
+
self.class._protobuf_class.new(to_message)
|
34
|
+
end
|
35
|
+
|
36
|
+
end
|
37
|
+
|
38
|
+
class_methods do
|
39
|
+
def build(message)
|
40
|
+
new(protobuf_class.new(message))
|
41
|
+
end
|
42
|
+
|
43
|
+
def from_message(attrs = {}, &blk)
|
44
|
+
# Hermes provides a hash, but we want to leverage the protobuf's built in deserialization, so dump it to json
|
45
|
+
pb = _protobuf_class.decode_json(JSON.dump(attrs))
|
46
|
+
new(pb, &blk)
|
47
|
+
end
|
48
|
+
|
49
|
+
def protobuf_class
|
50
|
+
_protobuf_class
|
51
|
+
end
|
52
|
+
|
53
|
+
def protobuf_class=(klass)
|
54
|
+
self._protobuf_class = klass
|
55
|
+
klass.descriptor.each do |f|
|
56
|
+
attr_accessor f.name.to_sym
|
57
|
+
end
|
58
|
+
end
|
59
|
+
end
|
60
|
+
end
|
61
|
+
end
|
62
|
+
end
|
@@ -0,0 +1,194 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require 'active_model'
|
4
|
+
require 'active_support'
|
5
|
+
require 'active_support/core_ext/hash'
|
6
|
+
|
7
|
+
require 'hermes_messenger_of_the_gods/concerns/base'
|
8
|
+
|
9
|
+
module HermesMessengerOfTheGods
|
10
|
+
module Concerns
|
11
|
+
module Message
|
12
|
+
extend ActiveSupport::Concern
|
13
|
+
|
14
|
+
include ActiveModel::Model
|
15
|
+
include HermesMessengerOfTheGods::Concerns::Base
|
16
|
+
|
17
|
+
attr_accessor :targeted_endpoints
|
18
|
+
|
19
|
+
def original_message
|
20
|
+
@original_message
|
21
|
+
end
|
22
|
+
|
23
|
+
def initialize(options = {})
|
24
|
+
@monitor = Monitor.new
|
25
|
+
self.targeted_endpoints = options.delete(:endpoints)
|
26
|
+
super
|
27
|
+
end
|
28
|
+
|
29
|
+
def validate!
|
30
|
+
raise HermesMessengerOfTheGods::ValidationError, self unless valid?
|
31
|
+
end
|
32
|
+
|
33
|
+
def dispatch
|
34
|
+
dispatch!
|
35
|
+
rescue StandardError
|
36
|
+
false
|
37
|
+
end
|
38
|
+
|
39
|
+
def dispatch_async
|
40
|
+
HermesMessengerOfTheGods.increment_async_dispatches_in_progress
|
41
|
+
Thread.new do
|
42
|
+
dispatch
|
43
|
+
ensure
|
44
|
+
HermesMessengerOfTheGods.decrement_async_dispatches_in_progress
|
45
|
+
end
|
46
|
+
end
|
47
|
+
|
48
|
+
def dispatch_async!
|
49
|
+
HermesMessengerOfTheGods.increment_async_dispatches_in_progress
|
50
|
+
Thread.new do
|
51
|
+
dispatch!
|
52
|
+
ensure
|
53
|
+
HermesMessengerOfTheGods.decrement_async_dispatches_in_progress
|
54
|
+
end
|
55
|
+
end
|
56
|
+
|
57
|
+
def dispatch!(endpoint_args: {})
|
58
|
+
run_callbacks :dispatch do
|
59
|
+
validate!
|
60
|
+
|
61
|
+
endpoints.collect do |ep_name, endpoint|
|
62
|
+
next if targeted_endpoints && !targeted_endpoints.include?(ep_name)
|
63
|
+
|
64
|
+
Thread.new do
|
65
|
+
endpoint.dispatch!(self, endpoint_args) unless HermesMessengerOfTheGods.config.stub_dispatch
|
66
|
+
register_success(ep_name, endpoint.result)
|
67
|
+
rescue StandardError => e
|
68
|
+
register_failure(ep_name, e)
|
69
|
+
ensure
|
70
|
+
endpoint.teardown
|
71
|
+
end
|
72
|
+
end.compact.map(&:join)
|
73
|
+
|
74
|
+
unless dispatch_errors.empty?
|
75
|
+
klass = if successes.empty?
|
76
|
+
HermesMessengerOfTheGods::MessageDispatchTotalFailure
|
77
|
+
else
|
78
|
+
HermesMessengerOfTheGods::MessageDispatchPartialFailure
|
79
|
+
end
|
80
|
+
|
81
|
+
ex = klass.new
|
82
|
+
ex.exceptions = dispatch_errors
|
83
|
+
raise ex
|
84
|
+
end
|
85
|
+
end
|
86
|
+
|
87
|
+
true
|
88
|
+
end
|
89
|
+
|
90
|
+
def register_failure(ep_name, error)
|
91
|
+
@monitor.synchronize do
|
92
|
+
instrument(:dispatch_failure, endpoint_name: ep_name, exception: error)
|
93
|
+
dispatch_errors[ep_name] = error
|
94
|
+
end
|
95
|
+
end
|
96
|
+
|
97
|
+
def register_success(ep_name, return_value)
|
98
|
+
@monitor.synchronize do
|
99
|
+
successes[ep_name] = return_value
|
100
|
+
end
|
101
|
+
end
|
102
|
+
|
103
|
+
def dispatch_errors
|
104
|
+
@dispatch_errors ||= {}
|
105
|
+
end
|
106
|
+
|
107
|
+
def successes
|
108
|
+
@successes ||= {}
|
109
|
+
end
|
110
|
+
|
111
|
+
def _build_for_transmission
|
112
|
+
to_message
|
113
|
+
end
|
114
|
+
|
115
|
+
def to_message
|
116
|
+
attributes
|
117
|
+
end
|
118
|
+
|
119
|
+
def attributes
|
120
|
+
(self.class._defined_attributes || []).each.with_object({}) do |attr, hsh|
|
121
|
+
hsh[attr] = send(attr)
|
122
|
+
end
|
123
|
+
end
|
124
|
+
|
125
|
+
def inspect
|
126
|
+
"<#{self.class}: #{attributes}>"
|
127
|
+
end
|
128
|
+
|
129
|
+
included do
|
130
|
+
class_attribute :_defined_attributes, :_endpoints, :_circuit_breaker_errors, :_max_consecutive_failures
|
131
|
+
|
132
|
+
define_model_callbacks :dispatch
|
133
|
+
|
134
|
+
around_dispatch { |_, blk| instrument(:dispatch, &blk) }
|
135
|
+
end
|
136
|
+
|
137
|
+
class_methods do
|
138
|
+
def from_message(attrs = {}, &blk)
|
139
|
+
attrs = attrs.slice(*_defined_attributes.map(&:to_s))
|
140
|
+
new(attrs, &blk)
|
141
|
+
end
|
142
|
+
|
143
|
+
def attr_accessor(*args)
|
144
|
+
self._defined_attributes ||= []
|
145
|
+
self._defined_attributes += args
|
146
|
+
super
|
147
|
+
end
|
148
|
+
|
149
|
+
def endpoints
|
150
|
+
_endpoints
|
151
|
+
end
|
152
|
+
|
153
|
+
def circuit_breaker_errors
|
154
|
+
_circuit_breaker_errors
|
155
|
+
end
|
156
|
+
|
157
|
+
|
158
|
+
def max_consecutive_failures
|
159
|
+
_max_consecutive_failures
|
160
|
+
end
|
161
|
+
|
162
|
+
def max_consecutive_failures=(val)
|
163
|
+
raise 'Expected an Integer' unless val.is_a?(Integer) || val.is_a?(NilClass)
|
164
|
+
self._max_consecutive_failures = val
|
165
|
+
end
|
166
|
+
|
167
|
+
def circuit_breaker_errors=(val)
|
168
|
+
val ||= {}
|
169
|
+
raise 'Expected a hash' unless val.is_a?(Hash)
|
170
|
+
|
171
|
+
val.each do |err, actions|
|
172
|
+
val[err][:sleep] ||= 0
|
173
|
+
val[err][:fatal] ||= false
|
174
|
+
end
|
175
|
+
|
176
|
+
val.each do |err, actions|
|
177
|
+
raise ':sleep must be a number' unless actions[:sleep].is_a?(Numeric)
|
178
|
+
raise ':fatal must be a boolean' unless [true, false].include?(actions[:fatal])
|
179
|
+
end
|
180
|
+
|
181
|
+
self._circuit_breaker_errors = val
|
182
|
+
end
|
183
|
+
|
184
|
+
def endpoints=(val)
|
185
|
+
unless val.is_a?(Hash)
|
186
|
+
raise 'Endpoints expects a hash {endpoint_name: endpoint_handler}'
|
187
|
+
end
|
188
|
+
|
189
|
+
self._endpoints = val
|
190
|
+
end
|
191
|
+
end
|
192
|
+
end
|
193
|
+
end
|
194
|
+
end
|