railway-ipc 0.1.4 → 1.0.1

Sign up to get free protection for your applications and to get access to all the features.
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