railway-ipc 0.1.4 → 1.0.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +4 -4
- data/.gitignore +4 -3
- data/CHANGELOG.MD +43 -0
- data/Gemfile +2 -2
- data/README.md +1 -1
- data/Rakefile +10 -4
- data/bin/console +3 -3
- data/bin/rspec +29 -0
- data/bin/rubocop +29 -0
- data/lib/railway_ipc.rb +6 -4
- data/lib/railway_ipc/Rakefile +2 -0
- data/lib/railway_ipc/consumer/consumer.rb +21 -81
- data/lib/railway_ipc/consumer/consumer_response_handlers.rb +2 -0
- data/lib/railway_ipc/consumer/process_incoming_message.rb +105 -0
- data/lib/railway_ipc/errors.rb +9 -1
- data/lib/railway_ipc/handler.rb +5 -6
- data/lib/railway_ipc/handler_manifest.rb +2 -0
- data/lib/railway_ipc/handler_store.rb +3 -0
- data/lib/railway_ipc/incoming_message.rb +51 -0
- data/lib/railway_ipc/logger.rb +4 -3
- data/lib/railway_ipc/models/consumed_message.rb +41 -27
- data/lib/railway_ipc/models/published_message.rb +11 -9
- data/lib/railway_ipc/publisher.rb +58 -1
- data/lib/railway_ipc/rabbitmq/adapter.rb +24 -14
- data/lib/railway_ipc/rabbitmq/payload.rb +9 -4
- data/lib/railway_ipc/railtie.rb +2 -0
- data/lib/railway_ipc/responder.rb +6 -3
- data/lib/railway_ipc/response.rb +4 -1
- data/lib/railway_ipc/rpc/client/client.rb +27 -17
- data/lib/railway_ipc/rpc/client/client_response_handlers.rb +2 -0
- data/lib/railway_ipc/rpc/client/errors/timeout_error.rb +2 -0
- data/lib/railway_ipc/rpc/concerns/error_adapter_configurable.rb +2 -0
- data/lib/railway_ipc/rpc/concerns/message_observation_configurable.rb +2 -0
- data/lib/railway_ipc/rpc/concerns/publish_location_configurable.rb +2 -0
- data/lib/railway_ipc/rpc/rpc.rb +2 -0
- data/lib/railway_ipc/rpc/server/server.rb +10 -3
- data/lib/railway_ipc/rpc/server/server_response_handlers.rb +2 -0
- data/lib/railway_ipc/tasks/generate_migrations.rake +16 -16
- data/lib/railway_ipc/tasks/start_consumers.rake +3 -1
- data/lib/railway_ipc/tasks/start_servers.rake +3 -1
- data/lib/railway_ipc/unhandled_message_error.rb +2 -0
- data/lib/railway_ipc/unknown_message.pb.rb +18 -0
- data/lib/railway_ipc/version.rb +3 -1
- data/priv/migrations/add_railway_ipc_consumed_messages.rb +3 -1
- data/priv/migrations/add_railway_ipc_published_messages.rb +3 -1
- data/railway_ipc.gemspec +33 -30
- metadata +64 -65
- data/.rspec +0 -3
- data/.tool-versions +0 -1
- data/.travis.yml +0 -7
- data/Gemfile.lock +0 -186
- data/lib/railway_ipc/base_message.pb.rb +0 -21
- data/lib/railway_ipc/null_handler.rb +0 -7
- data/lib/railway_ipc/null_message.rb +0 -7
data/lib/railway_ipc/railtie.rb
CHANGED
@@ -1,17 +1,20 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
1
3
|
module RailwayIpc
|
2
4
|
class Responder
|
3
5
|
def self.respond(&block)
|
4
6
|
@block = block
|
5
7
|
end
|
6
8
|
|
7
|
-
|
8
|
-
|
9
|
+
class << self
|
10
|
+
attr_reader :block
|
9
11
|
end
|
10
12
|
|
11
13
|
def respond(request)
|
12
|
-
RailwayIpc.logger.info(request,
|
14
|
+
RailwayIpc.logger.info(request, 'Responding to request')
|
13
15
|
response = self.class.block.call(request)
|
14
16
|
raise ResponseTypeError.new(response.class) unless response.is_a?(Google::Protobuf::MessageExts)
|
17
|
+
|
15
18
|
response
|
16
19
|
end
|
17
20
|
|
data/lib/railway_ipc/response.rb
CHANGED
@@ -1,12 +1,15 @@
|
|
1
|
-
|
2
|
-
|
3
|
-
require
|
4
|
-
require
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require 'railway_ipc/rpc/client/client_response_handlers'
|
4
|
+
require 'railway_ipc/rpc/concerns/publish_location_configurable'
|
5
|
+
require 'railway_ipc/rpc/concerns/error_adapter_configurable'
|
6
|
+
require 'railway_ipc/rpc/client/errors/timeout_error'
|
5
7
|
|
6
8
|
module RailwayIpc
|
7
9
|
class Client
|
8
10
|
attr_accessor :response_message, :request_message
|
9
11
|
attr_reader :rabbit_connection, :message
|
12
|
+
|
10
13
|
extend RailwayIpc::RPC::PublishLocationConfigurable
|
11
14
|
extend RailwayIpc::RPC::ErrorAdapterConfigurable
|
12
15
|
|
@@ -18,12 +21,12 @@ module RailwayIpc
|
|
18
21
|
RPC::ClientResponseHandlers.instance.register(response_type)
|
19
22
|
end
|
20
23
|
|
21
|
-
def initialize(request_message, opts
|
24
|
+
def initialize(request_message, opts={ automatic_recovery: false }, rabbit_adapter: RailwayIpc::Rabbitmq::Adapter)
|
22
25
|
@rabbit_connection = rabbit_adapter.new(exchange_name: self.class.exchange_name, options: opts)
|
23
26
|
@request_message = request_message
|
24
27
|
end
|
25
28
|
|
26
|
-
def request(timeout
|
29
|
+
def request(timeout=10)
|
27
30
|
setup_rabbit_connection
|
28
31
|
attach_reply_queue_to_message
|
29
32
|
publish_message
|
@@ -35,18 +38,20 @@ module RailwayIpc
|
|
35
38
|
RailwayIpc::RPC::ClientResponseHandlers.instance.registered
|
36
39
|
end
|
37
40
|
|
41
|
+
# rubocop:disable Metrics/AbcSize
|
38
42
|
def process_payload(response)
|
39
43
|
decoded_payload = decode_payload(response)
|
40
44
|
case decoded_payload.type
|
41
45
|
when *registered_handlers
|
42
46
|
@message = get_message_class(decoded_payload).decode(decoded_payload.message)
|
43
|
-
RailwayIpc.logger.info(message,
|
47
|
+
RailwayIpc.logger.info(message, 'Handling response')
|
44
48
|
RailwayIpc::Response.new(message, success: true)
|
45
49
|
else
|
46
50
|
@message = LearnIpc::ErrorMessage.decode(decoded_payload.message)
|
47
|
-
raise RailwayIpc::UnhandledMessageError
|
51
|
+
raise RailwayIpc::UnhandledMessageError.new("#{self.class} does not know how to handle #{decoded_payload.type}")
|
48
52
|
end
|
49
53
|
end
|
54
|
+
# rubocop:enable Metrics/AbcSize
|
50
55
|
|
51
56
|
def setup_rabbit_connection
|
52
57
|
rabbit_connection
|
@@ -60,7 +65,9 @@ module RailwayIpc
|
|
60
65
|
self.response_message = process_payload(payload)
|
61
66
|
end
|
62
67
|
rescue RailwayIpc::Rabbitmq::Adapter::TimeoutError
|
68
|
+
# rubocop:disable Style/RedundantSelf
|
63
69
|
error = self.class.rpc_error_adapter_class.error_message(TimeoutError.new, self.request_message)
|
70
|
+
# rubocop:enable Style/RedundantSelf
|
64
71
|
self.response_message = RailwayIpc::Response.new(error, success: false)
|
65
72
|
rescue StandardError
|
66
73
|
self.response_message = RailwayIpc::Response.new(message, success: false)
|
@@ -70,12 +77,12 @@ module RailwayIpc
|
|
70
77
|
|
71
78
|
private
|
72
79
|
|
73
|
-
def log_exception(
|
80
|
+
def log_exception(exception, payload)
|
74
81
|
RailwayIpc.logger.log_exception(
|
75
|
-
feature:
|
76
|
-
error:
|
77
|
-
error_message:
|
78
|
-
payload: decode_for_error(
|
82
|
+
feature: 'railway_consumer',
|
83
|
+
error: exception.class,
|
84
|
+
error_message: exception.message,
|
85
|
+
payload: decode_for_error(exception, payload)
|
79
86
|
)
|
80
87
|
end
|
81
88
|
|
@@ -92,13 +99,16 @@ module RailwayIpc
|
|
92
99
|
end
|
93
100
|
|
94
101
|
def publish_message
|
95
|
-
RailwayIpc.logger.info(request_message,
|
96
|
-
rabbit_connection.publish(RailwayIpc::Rabbitmq::Payload.encode(request_message), routing_key:
|
102
|
+
RailwayIpc.logger.info(request_message, 'Sending request')
|
103
|
+
rabbit_connection.publish(RailwayIpc::Rabbitmq::Payload.encode(request_message), routing_key: '')
|
97
104
|
end
|
98
105
|
|
99
|
-
def decode_for_error(
|
100
|
-
return
|
106
|
+
def decode_for_error(exception, payload)
|
107
|
+
return exception.message unless payload
|
108
|
+
|
109
|
+
# rubocop:disable Style/RedundantSelf
|
101
110
|
self.class.rpc_error_adapter_class.error_message(payload, self.request_message)
|
111
|
+
# rubocop:enable Style/RedundantSelf
|
102
112
|
end
|
103
113
|
end
|
104
114
|
end
|
data/lib/railway_ipc/rpc/rpc.rb
CHANGED
@@ -1,3 +1,5 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
1
3
|
require 'railway_ipc/rpc/server/server_response_handlers'
|
2
4
|
require 'railway_ipc/rpc/concerns/error_adapter_configurable'
|
3
5
|
require 'railway_ipc/rpc/concerns/message_observation_configurable'
|
@@ -12,7 +14,7 @@ module RailwayIpc
|
|
12
14
|
RailwayIpc::RPC::ServerResponseHandlers.instance.register(handler: with, message: message_type)
|
13
15
|
end
|
14
16
|
|
15
|
-
def initialize(opts
|
17
|
+
def initialize(opts={ automatic_recovery: true }, rabbit_adapter: RailwayIpc::Rabbitmq::Adapter)
|
16
18
|
@rabbit_connection = rabbit_adapter.new(
|
17
19
|
queue_name: self.class.queue_name,
|
18
20
|
exchange_name: self.class.exchange_name,
|
@@ -29,6 +31,8 @@ module RailwayIpc
|
|
29
31
|
subscribe_to_queue
|
30
32
|
end
|
31
33
|
|
34
|
+
# rubocop:disable Metrics/AbcSize
|
35
|
+
# rubocop:disable Metrics/MethodLength
|
32
36
|
def work(payload)
|
33
37
|
decoded_payload = RailwayIpc::Rabbitmq::Payload.decode(payload)
|
34
38
|
case decoded_payload.type
|
@@ -38,7 +42,7 @@ module RailwayIpc
|
|
38
42
|
responder.respond(message)
|
39
43
|
else
|
40
44
|
@message = LearnIpc::ErrorMessage.decode(decoded_payload.message)
|
41
|
-
raise RailwayIpc::UnhandledMessageError
|
45
|
+
raise RailwayIpc::UnhandledMessageError.new("#{self.class} does not know how to handle #{decoded_payload.type}")
|
42
46
|
end
|
43
47
|
rescue StandardError => e
|
44
48
|
RailwayIpc.logger.log_exception(
|
@@ -49,7 +53,10 @@ module RailwayIpc
|
|
49
53
|
)
|
50
54
|
raise e
|
51
55
|
end
|
56
|
+
# rubocop:enable Metrics/AbcSize
|
57
|
+
# rubocop:enable Metrics/MethodLength
|
52
58
|
|
59
|
+
# rubocop:disable Metrics/AbcSize
|
53
60
|
def handle_request(payload)
|
54
61
|
response = work(payload)
|
55
62
|
rescue StandardError => e
|
@@ -62,6 +69,7 @@ module RailwayIpc
|
|
62
69
|
)
|
63
70
|
end
|
64
71
|
end
|
72
|
+
# rubocop:enable Metrics/AbcSize
|
65
73
|
|
66
74
|
private
|
67
75
|
|
@@ -84,6 +92,5 @@ module RailwayIpc
|
|
84
92
|
handle_request(payload)
|
85
93
|
end
|
86
94
|
end
|
87
|
-
|
88
95
|
end
|
89
96
|
end
|
@@ -1,25 +1,25 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
1
3
|
require 'fileutils'
|
2
4
|
|
3
5
|
namespace :railway_ipc do
|
4
6
|
namespace :generate do
|
5
|
-
desc
|
7
|
+
desc 'Generates migrations to store Railway messages'
|
6
8
|
task :migrations do
|
7
|
-
|
8
|
-
|
9
|
-
|
10
|
-
|
11
|
-
|
12
|
-
|
9
|
+
raise 'Migration generation requires active record' unless defined?(ActiveRecord::Base)
|
10
|
+
|
11
|
+
puts 'generating Railway IPC table migrations'
|
12
|
+
seconds = 0
|
13
|
+
gem_path = Gem.loaded_specs['railway-ipc'].full_gem_path
|
14
|
+
folder_dest = "#{Rails.root}/db/migrate"
|
15
|
+
FileUtils.mkdir_p(folder_dest)
|
13
16
|
|
14
|
-
|
15
|
-
|
16
|
-
|
17
|
-
|
18
|
-
|
19
|
-
|
20
|
-
end
|
21
|
-
else
|
22
|
-
raise "Migration generation requires active record"
|
17
|
+
Dir.glob("#{gem_path}/priv/migrations/*.rb").each do |file_path|
|
18
|
+
file_name = File.basename(file_path)
|
19
|
+
migration_timestamp = (Time.now + seconds).utc.strftime('%Y%m%d%H%M%S') % '%.14d'
|
20
|
+
new_file_name = "#{migration_timestamp}_#{file_name}"
|
21
|
+
FileUtils.copy_file(file_path, "#{folder_dest}/#{new_file_name}")
|
22
|
+
seconds += 1
|
23
23
|
end
|
24
24
|
end
|
25
25
|
end
|
@@ -0,0 +1,18 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require 'google/protobuf'
|
4
|
+
|
5
|
+
Google::Protobuf::DescriptorPool.generated_pool.build do
|
6
|
+
add_message 'railway_ipc.messages.Unknown' do
|
7
|
+
optional :user_uuid, :string, 1
|
8
|
+
optional :correlation_id, :string, 2
|
9
|
+
optional :uuid, :string, 3
|
10
|
+
map :context, :string, :string, 4
|
11
|
+
end
|
12
|
+
end
|
13
|
+
|
14
|
+
module RailwayIpc
|
15
|
+
module Messages
|
16
|
+
Unknown = Google::Protobuf::DescriptorPool.generated_pool.lookup('railway_ipc.messages.Unknown').msgclass
|
17
|
+
end
|
18
|
+
end
|
data/lib/railway_ipc/version.rb
CHANGED
@@ -1,6 +1,8 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
1
3
|
class AddRailwayIpcConsumedMessages < ActiveRecord::Migration
|
2
4
|
def change
|
3
|
-
create_table :railway_ipc_consumed_messages, id: false do |
|
5
|
+
create_table :railway_ipc_consumed_messages, id: false do |t|
|
4
6
|
t.uuid :uuid, null: false
|
5
7
|
t.string :message_type
|
6
8
|
t.uuid :user_uuid
|
@@ -1,6 +1,8 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
1
3
|
class AddRailwayIpcPublishedMessages < ActiveRecord::Migration
|
2
4
|
def change
|
3
|
-
create_table :railway_ipc_published_messages, id: false do |
|
5
|
+
create_table :railway_ipc_published_messages, id: false do |t|
|
4
6
|
t.uuid :uuid, null: false
|
5
7
|
t.string :message_type
|
6
8
|
t.uuid :user_uuid
|
data/railway_ipc.gemspec
CHANGED
@@ -1,50 +1,53 @@
|
|
1
|
-
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
lib = File.expand_path('lib', __dir__)
|
2
4
|
$LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
|
3
|
-
require
|
5
|
+
require 'railway_ipc/version'
|
4
6
|
|
5
7
|
Gem::Specification.new do |spec|
|
6
|
-
spec.name =
|
8
|
+
spec.name = 'railway-ipc'
|
7
9
|
spec.version = RailwayIpc::VERSION
|
8
|
-
spec.authors =
|
9
|
-
spec.email =
|
10
|
+
spec.authors = ''
|
11
|
+
spec.email = ''
|
10
12
|
|
11
|
-
spec.summary =
|
12
|
-
spec.description =
|
13
|
-
spec.homepage =
|
14
|
-
spec.license =
|
13
|
+
spec.summary = 'IPC components for Rails'
|
14
|
+
spec.description = 'IPC components for Rails'
|
15
|
+
spec.homepage = 'http://learn.co'
|
16
|
+
spec.license = 'MIT'
|
15
17
|
|
16
18
|
# Prevent pushing this gem to RubyGems.org. To allow pushes either set the 'allowed_push_host'
|
17
19
|
# to allow pushing to a single host or delete this section to allow pushing to any host.
|
18
20
|
if spec.respond_to?(:metadata)
|
19
|
-
spec.metadata[
|
21
|
+
spec.metadata['allowed_push_host'] = 'https://rubygems.org/'
|
20
22
|
else
|
21
|
-
raise
|
22
|
-
|
23
|
+
raise 'RubyGems 2.0 or newer is required to protect against ' \
|
24
|
+
'public gem pushes.'
|
23
25
|
end
|
24
26
|
|
25
27
|
# Specify which files should be added to the gem when it is released.
|
26
28
|
# The `git ls-files -z` loads the files in the RubyGem that have been added into git.
|
27
|
-
spec.files = Dir.chdir(File.expand_path(
|
28
|
-
`git ls-files -z`.split("\x0").reject { |f| f.match(
|
29
|
+
spec.files = Dir.chdir(File.expand_path(__dir__)) do
|
30
|
+
`git ls-files -z`.split("\x0").reject { |f| f.match(/^(.circleci|.rspec|.rubocop.yml|test|spec|features)/) }
|
29
31
|
end
|
30
|
-
spec.bindir =
|
32
|
+
spec.bindir = 'exe'
|
31
33
|
spec.executables = spec.files.grep(%r{^exe/}) { |f| File.basename(f) }
|
32
|
-
spec.require_paths = [
|
34
|
+
spec.require_paths = ['lib']
|
35
|
+
|
36
|
+
spec.add_development_dependency 'bundler', '2.0.1'
|
37
|
+
spec.add_development_dependency 'factory_bot', '~> 5.1'
|
38
|
+
spec.add_development_dependency 'google-protobuf', '~> 3.9'
|
39
|
+
spec.add_development_dependency 'rake', '>= 10.0.0'
|
40
|
+
spec.add_development_dependency 'rspec', '~> 3.0'
|
41
|
+
spec.add_development_dependency 'rubocop', '~> 0.86'
|
33
42
|
|
34
|
-
spec.
|
35
|
-
spec.
|
36
|
-
spec.add_development_dependency "rspec", "~> 3.0"
|
37
|
-
spec.add_development_dependency "factory_bot", "~> 5.1"
|
38
|
-
spec.add_development_dependency "pry-byebug", "3.4.2"
|
39
|
-
spec.add_development_dependency "google-protobuf", "~> 3.9"
|
40
|
-
spec.add_dependency "sneakers", "~> 2.3.5"
|
41
|
-
spec.add_dependency "bunny", "~> 2.2.0"
|
43
|
+
spec.add_dependency 'bunny', '~> 2.2.0'
|
44
|
+
spec.add_dependency 'sneakers', '~> 2.3.5'
|
42
45
|
|
43
46
|
# Setup for testing Rails type code within mock Rails app
|
44
|
-
spec.add_development_dependency
|
45
|
-
spec.add_development_dependency
|
46
|
-
spec.add_development_dependency
|
47
|
-
spec.add_development_dependency
|
48
|
-
spec.add_development_dependency
|
49
|
-
spec.add_development_dependency
|
47
|
+
spec.add_development_dependency 'database_cleaner', '~> 1.7'
|
48
|
+
spec.add_development_dependency 'listen', '~> 3.0.5'
|
49
|
+
spec.add_development_dependency 'pg', '~> 0.18'
|
50
|
+
spec.add_development_dependency 'rails', '~> 5.0.7'
|
51
|
+
spec.add_development_dependency 'rspec-rails'
|
52
|
+
spec.add_development_dependency 'shoulda-matchers', '~> 4.2'
|
50
53
|
end
|