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.
Files changed (54) hide show
  1. checksums.yaml +4 -4
  2. data/.gitignore +4 -3
  3. data/CHANGELOG.MD +43 -0
  4. data/Gemfile +2 -2
  5. data/README.md +1 -1
  6. data/Rakefile +10 -4
  7. data/bin/console +3 -3
  8. data/bin/rspec +29 -0
  9. data/bin/rubocop +29 -0
  10. data/lib/railway_ipc.rb +6 -4
  11. data/lib/railway_ipc/Rakefile +2 -0
  12. data/lib/railway_ipc/consumer/consumer.rb +21 -81
  13. data/lib/railway_ipc/consumer/consumer_response_handlers.rb +2 -0
  14. data/lib/railway_ipc/consumer/process_incoming_message.rb +105 -0
  15. data/lib/railway_ipc/errors.rb +9 -1
  16. data/lib/railway_ipc/handler.rb +5 -6
  17. data/lib/railway_ipc/handler_manifest.rb +2 -0
  18. data/lib/railway_ipc/handler_store.rb +3 -0
  19. data/lib/railway_ipc/incoming_message.rb +51 -0
  20. data/lib/railway_ipc/logger.rb +4 -3
  21. data/lib/railway_ipc/models/consumed_message.rb +41 -27
  22. data/lib/railway_ipc/models/published_message.rb +11 -9
  23. data/lib/railway_ipc/publisher.rb +58 -1
  24. data/lib/railway_ipc/rabbitmq/adapter.rb +24 -14
  25. data/lib/railway_ipc/rabbitmq/payload.rb +9 -4
  26. data/lib/railway_ipc/railtie.rb +2 -0
  27. data/lib/railway_ipc/responder.rb +6 -3
  28. data/lib/railway_ipc/response.rb +4 -1
  29. data/lib/railway_ipc/rpc/client/client.rb +27 -17
  30. data/lib/railway_ipc/rpc/client/client_response_handlers.rb +2 -0
  31. data/lib/railway_ipc/rpc/client/errors/timeout_error.rb +2 -0
  32. data/lib/railway_ipc/rpc/concerns/error_adapter_configurable.rb +2 -0
  33. data/lib/railway_ipc/rpc/concerns/message_observation_configurable.rb +2 -0
  34. data/lib/railway_ipc/rpc/concerns/publish_location_configurable.rb +2 -0
  35. data/lib/railway_ipc/rpc/rpc.rb +2 -0
  36. data/lib/railway_ipc/rpc/server/server.rb +10 -3
  37. data/lib/railway_ipc/rpc/server/server_response_handlers.rb +2 -0
  38. data/lib/railway_ipc/tasks/generate_migrations.rake +16 -16
  39. data/lib/railway_ipc/tasks/start_consumers.rake +3 -1
  40. data/lib/railway_ipc/tasks/start_servers.rake +3 -1
  41. data/lib/railway_ipc/unhandled_message_error.rb +2 -0
  42. data/lib/railway_ipc/unknown_message.pb.rb +18 -0
  43. data/lib/railway_ipc/version.rb +3 -1
  44. data/priv/migrations/add_railway_ipc_consumed_messages.rb +3 -1
  45. data/priv/migrations/add_railway_ipc_published_messages.rb +3 -1
  46. data/railway_ipc.gemspec +33 -30
  47. metadata +64 -65
  48. data/.rspec +0 -3
  49. data/.tool-versions +0 -1
  50. data/.travis.yml +0 -7
  51. data/Gemfile.lock +0 -186
  52. data/lib/railway_ipc/base_message.pb.rb +0 -21
  53. data/lib/railway_ipc/null_handler.rb +0 -7
  54. data/lib/railway_ipc/null_message.rb +0 -7
@@ -1,3 +1,5 @@
1
+ # frozen_string_literal: true
2
+
1
3
  module RailwayIpc
2
4
  class Railtie < Rails::Railtie
3
5
  railtie_name :railway_ipc
@@ -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
- def self.block
8
- @block
9
+ class << self
10
+ attr_reader :block
9
11
  end
10
12
 
11
13
  def respond(request)
12
- RailwayIpc.logger.info(request, "Responding to 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
 
@@ -1,7 +1,10 @@
1
+ # frozen_string_literal: true
2
+
1
3
  module RailwayIpc
2
4
  class Response
3
5
  attr_reader :body, :success
4
- def initialize(message, success:true)
6
+
7
+ def initialize(message, success: true)
5
8
  @body = message
6
9
  @success = success
7
10
  end
@@ -1,12 +1,15 @@
1
- require "railway_ipc/rpc/client/client_response_handlers"
2
- require "railway_ipc/rpc/concerns/publish_location_configurable"
3
- require "railway_ipc/rpc/concerns/error_adapter_configurable"
4
- require "railway_ipc/rpc/client/errors/timeout_error"
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 = { automatic_recovery: false }, rabbit_adapter: RailwayIpc::Rabbitmq::Adapter)
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 = 10)
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, "Handling response")
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, "#{self.class} does not know how to handle #{decoded_payload.type}"
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(e, payload)
80
+ def log_exception(exception, payload)
74
81
  RailwayIpc.logger.log_exception(
75
- feature: "railway_consumer",
76
- error: e.class,
77
- error_message: e.message,
78
- payload: decode_for_error(e, payload),
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, "Sending request")
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(e, payload)
100
- return e.message unless payload
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
@@ -1,3 +1,5 @@
1
+ # frozen_string_literal: true
2
+
1
3
  module RailwayIpc
2
4
  module RPC
3
5
  class ClientResponseHandlers
@@ -1,3 +1,5 @@
1
+ # frozen_string_literal: true
2
+
1
3
  module RailwayIpc
2
4
  class Client
3
5
  class TimeoutError < StandardError; end
@@ -1,3 +1,5 @@
1
+ # frozen_string_literal: true
2
+
1
3
  module RailwayIpc
2
4
  module RPC
3
5
  module ErrorAdapterConfigurable
@@ -1,3 +1,5 @@
1
+ # frozen_string_literal: true
2
+
1
3
  module RailwayIpc
2
4
  module RPC
3
5
  module MessageObservationConfigurable
@@ -1,3 +1,5 @@
1
+ # frozen_string_literal: true
2
+
1
3
  module RailwayIpc
2
4
  module RPC
3
5
  module PublishLocationConfigurable
@@ -1,2 +1,4 @@
1
+ # frozen_string_literal: true
2
+
1
3
  require 'railway_ipc/rpc/client/client'
2
4
  require 'railway_ipc/rpc/server/server'
@@ -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 = {automatic_recovery: true}, rabbit_adapter: RailwayIpc::Rabbitmq::Adapter)
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, "#{self.class} does not know how to handle #{decoded_payload.type}"
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,3 +1,5 @@
1
+ # frozen_string_literal: true
2
+
1
3
  require 'railway_ipc/handler_store'
2
4
  module RailwayIpc
3
5
  module RPC
@@ -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 "Generates migrations to store Railway messages"
7
+ desc 'Generates migrations to store Railway messages'
6
8
  task :migrations do
7
- if defined?(ActiveRecord::Base)
8
- puts "generating Railway IPC table migrations"
9
- seconds = 0
10
- gem_path = Gem.loaded_specs['railway-ipc'].full_gem_path
11
- folder_dest = "#{Rails.root.to_s}/db/migrate"
12
- FileUtils.mkdir_p(folder_dest)
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
- Dir.glob("#{gem_path}/priv/migrations/*.rb").each do |file_path|
15
- file_name = File.basename(file_path)
16
- migration_timestamp = (Time.now + seconds).utc.strftime("%Y%m%d%H%M%S") % "%.14d"
17
- new_file_name = "#{migration_timestamp}_#{file_name}"
18
- FileUtils.copy_file(file_path, "#{folder_dest}/#{new_file_name}")
19
- seconds += 1
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
@@ -1,7 +1,9 @@
1
+ # frozen_string_literal: true
2
+
1
3
  namespace :railway_ipc do
2
4
  namespace :consumers do
3
5
  task :start do
4
- ENV["WORKERS"] = ENV["CONSUMERS"]
6
+ ENV['WORKERS'] = ENV['CONSUMERS']
5
7
  RailwayIpc.start
6
8
  end
7
9
  end
@@ -1,7 +1,9 @@
1
+ # frozen_string_literal: true
2
+
1
3
  namespace :railway_ipc do
2
4
  namespace :servers do
3
5
  task :start do
4
- ENV["WORKERS"] = ENV["SERVERS"]
6
+ ENV['WORKERS'] = ENV['SERVERS']
5
7
  RailwayIpc.start
6
8
  end
7
9
  end
@@ -1,3 +1,5 @@
1
+ # frozen_string_literal: true
2
+
1
3
  module RailwayIpc
2
4
  class UnhandledMessageError < StandardError
3
5
  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
@@ -1,3 +1,5 @@
1
+ # frozen_string_literal: true
2
+
1
3
  module RailwayIpc
2
- VERSION = "0.1.4"
4
+ VERSION = '1.0.1'
3
5
  end
@@ -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 | t |
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 | t |
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
@@ -1,50 +1,53 @@
1
- lib = File.expand_path("../lib", __FILE__)
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 "railway_ipc/version"
5
+ require 'railway_ipc/version'
4
6
 
5
7
  Gem::Specification.new do |spec|
6
- spec.name = "railway-ipc"
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 = %q{IPC components for Rails}
12
- spec.description = %q{IPC components for Rails}
13
- spec.homepage = "http://learn.co"
14
- spec.license = "MIT"
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["allowed_push_host"] = "https://rubygems.org/"
21
+ spec.metadata['allowed_push_host'] = 'https://rubygems.org/'
20
22
  else
21
- raise "RubyGems 2.0 or newer is required to protect against " \
22
- "public gem pushes."
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("..", __FILE__)) do
28
- `git ls-files -z`.split("\x0").reject { |f| f.match(%r{^(test|spec|features)/}) }
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 = "exe"
32
+ spec.bindir = 'exe'
31
33
  spec.executables = spec.files.grep(%r{^exe/}) { |f| File.basename(f) }
32
- spec.require_paths = ["lib"]
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.add_development_dependency "rake", ">= 10.0.0"
35
- spec.add_development_dependency "bundler", "2.0.1"
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 "rails", "~> 5.0.7"
45
- spec.add_development_dependency "rspec-rails"
46
- spec.add_development_dependency "pg", "~> 0.18"
47
- spec.add_development_dependency "shoulda-matchers", "~> 4.2"
48
- spec.add_development_dependency "database_cleaner", "~> 1.7"
49
- spec.add_development_dependency "listen", "~> 3.0.5"
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