railway-ipc 0.1.5 → 1.1.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/.gitignore +4 -3
- data/CHANGELOG.md +50 -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 +31 -83
- data/lib/railway_ipc/consumer/process_incoming_message.rb +103 -0
- data/lib/railway_ipc/errors.rb +9 -1
- data/lib/railway_ipc/handler.rb +5 -6
- data/lib/railway_ipc/handler_store.rb +5 -2
- 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 -28
- 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 +23 -15
- 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 +8 -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 +5 -3
- data/priv/migrations/add_railway_ipc_published_messages.rb +3 -1
- data/railway_ipc.gemspec +34 -30
- metadata +62 -64
- 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/consumer/consumer_response_handlers.rb +0 -14
- data/lib/railway_ipc/handler_manifest.rb +0 -10
- 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,6 +53,8 @@ module RailwayIpc
|
|
49
53
|
)
|
50
54
|
raise e
|
51
55
|
end
|
56
|
+
# rubocop:enable Metrics/AbcSize
|
57
|
+
# rubocop:enable Metrics/MethodLength
|
52
58
|
|
53
59
|
def handle_request(payload)
|
54
60
|
response = work(payload)
|
@@ -84,6 +90,5 @@ module RailwayIpc
|
|
84
90
|
handle_request(payload)
|
85
91
|
end
|
86
92
|
end
|
87
|
-
|
88
93
|
end
|
89
94
|
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,19 +1,21 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
1
3
|
class AddRailwayIpcConsumedMessages < ActiveRecord::Migration
|
2
4
|
def change
|
3
|
-
create_table :railway_ipc_consumed_messages
|
5
|
+
create_table :railway_ipc_consumed_messages do |t|
|
4
6
|
t.uuid :uuid, null: false
|
5
7
|
t.string :message_type
|
6
8
|
t.uuid :user_uuid
|
7
9
|
t.uuid :correlation_id
|
8
10
|
t.text :encoded_message
|
9
11
|
t.string :status, null: false
|
10
|
-
t.string :queue
|
12
|
+
t.string :queue, null: false
|
11
13
|
t.string :exchange
|
12
14
|
|
13
15
|
t.datetime :updated_at
|
14
16
|
t.datetime :inserted_at
|
15
17
|
end
|
16
18
|
|
17
|
-
add_index :railway_ipc_consumed_messages,
|
19
|
+
add_index :railway_ipc_consumed_messages, %i[uuid queue], unique: true
|
18
20
|
end
|
19
21
|
end
|
@@ -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,54 @@
|
|
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 = ''
|
12
|
+
spec.required_ruby_version = '>= 2.5'
|
10
13
|
|
11
|
-
spec.summary =
|
12
|
-
spec.description =
|
13
|
-
spec.homepage =
|
14
|
-
spec.license =
|
14
|
+
spec.summary = 'IPC components for Rails'
|
15
|
+
spec.description = 'IPC components for Rails'
|
16
|
+
spec.homepage = 'http://learn.co'
|
17
|
+
spec.license = 'MIT'
|
15
18
|
|
16
19
|
# Prevent pushing this gem to RubyGems.org. To allow pushes either set the 'allowed_push_host'
|
17
20
|
# to allow pushing to a single host or delete this section to allow pushing to any host.
|
18
21
|
if spec.respond_to?(:metadata)
|
19
|
-
spec.metadata[
|
22
|
+
spec.metadata['allowed_push_host'] = 'https://rubygems.org/'
|
20
23
|
else
|
21
|
-
raise
|
22
|
-
|
24
|
+
raise 'RubyGems 2.0 or newer is required to protect against ' \
|
25
|
+
'public gem pushes.'
|
23
26
|
end
|
24
27
|
|
25
28
|
# Specify which files should be added to the gem when it is released.
|
26
29
|
# 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(
|
30
|
+
spec.files = Dir.chdir(File.expand_path(__dir__)) do
|
31
|
+
`git ls-files -z`.split("\x0").reject { |f| f.match(/^(.circleci|.rspec|.rubocop.yml|test|spec|features)/) }
|
29
32
|
end
|
30
|
-
spec.bindir =
|
33
|
+
spec.bindir = 'exe'
|
31
34
|
spec.executables = spec.files.grep(%r{^exe/}) { |f| File.basename(f) }
|
32
|
-
spec.require_paths = [
|
35
|
+
spec.require_paths = ['lib']
|
36
|
+
|
37
|
+
spec.add_development_dependency 'bundler', '2.0.1'
|
38
|
+
spec.add_development_dependency 'factory_bot', '~> 5.1'
|
39
|
+
spec.add_development_dependency 'google-protobuf', '~> 3.9'
|
40
|
+
spec.add_development_dependency 'rake', '>= 10.0.0'
|
41
|
+
spec.add_development_dependency 'rspec', '~> 3.0'
|
42
|
+
spec.add_development_dependency 'rubocop', '~> 0.86'
|
33
43
|
|
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"
|
44
|
+
spec.add_dependency 'bunny', '~> 2.2.0'
|
45
|
+
spec.add_dependency 'sneakers', '~> 2.3.5'
|
42
46
|
|
43
47
|
# 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
|
48
|
+
spec.add_development_dependency 'database_cleaner', '~> 1.7'
|
49
|
+
spec.add_development_dependency 'listen', '~> 3.0.5'
|
50
|
+
spec.add_development_dependency 'pg', '~> 0.18'
|
51
|
+
spec.add_development_dependency 'rails', '~> 5.0.7'
|
52
|
+
spec.add_development_dependency 'rspec-rails'
|
53
|
+
spec.add_development_dependency 'shoulda-matchers', '~> 4.2'
|
50
54
|
end
|