railway-ipc 0.1.3 → 0.1.4

Sign up to get free protection for your applications and to get access to all the features.
Files changed (39) hide show
  1. checksums.yaml +4 -4
  2. data/.gitignore +8 -0
  3. data/.tool-versions +1 -0
  4. data/Gemfile.lock +125 -1
  5. data/README.md +5 -0
  6. data/lib/railway_ipc.rb +28 -21
  7. data/lib/railway_ipc/base_message.pb.rb +21 -0
  8. data/lib/railway_ipc/consumer/consumer.rb +112 -0
  9. data/lib/railway_ipc/consumer/consumer_response_handlers.rb +14 -0
  10. data/lib/railway_ipc/errors.rb +1 -0
  11. data/lib/railway_ipc/handler.rb +2 -0
  12. data/lib/railway_ipc/handler_manifest.rb +10 -0
  13. data/lib/railway_ipc/handler_store.rb +21 -0
  14. data/lib/railway_ipc/models/consumed_message.rb +48 -0
  15. data/lib/railway_ipc/models/published_message.rb +27 -0
  16. data/lib/railway_ipc/null_message.rb +1 -1
  17. data/lib/railway_ipc/publisher.rb +9 -4
  18. data/lib/railway_ipc/rabbitmq/adapter.rb +93 -0
  19. data/lib/railway_ipc/rabbitmq/payload.rb +7 -3
  20. data/lib/railway_ipc/rpc/client/client.rb +104 -0
  21. data/lib/railway_ipc/rpc/client/client_response_handlers.rb +25 -0
  22. data/lib/railway_ipc/rpc/client/errors/timeout_error.rb +5 -0
  23. data/lib/railway_ipc/rpc/concerns/error_adapter_configurable.rb +13 -0
  24. data/lib/railway_ipc/rpc/concerns/message_observation_configurable.rb +18 -0
  25. data/lib/railway_ipc/rpc/concerns/publish_location_configurable.rb +13 -0
  26. data/lib/railway_ipc/rpc/rpc.rb +2 -0
  27. data/lib/railway_ipc/rpc/server/server.rb +89 -0
  28. data/lib/railway_ipc/rpc/server/server_response_handlers.rb +17 -0
  29. data/lib/railway_ipc/tasks/generate_migrations.rake +26 -0
  30. data/lib/railway_ipc/version.rb +1 -1
  31. data/priv/migrations/add_railway_ipc_consumed_messages.rb +19 -0
  32. data/priv/migrations/add_railway_ipc_published_messages.rb +18 -0
  33. data/railway_ipc.gemspec +25 -16
  34. metadata +123 -8
  35. data/lib/railway_ipc/client.rb +0 -87
  36. data/lib/railway_ipc/concerns/message_handling.rb +0 -118
  37. data/lib/railway_ipc/consumer.rb +0 -26
  38. data/lib/railway_ipc/rabbitmq/connection.rb +0 -55
  39. data/lib/railway_ipc/server.rb +0 -50
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 4e93883b1436475f8b412a9bb1b689adf4d912575e3ebc406bba614321df1f4c
4
- data.tar.gz: 42ba48cba7b1a384a3074715feae7d04b86012090e87b74a725925891214b238
3
+ metadata.gz: 945917b242216c009d199f73de3c559b16b005cdae28504273b2ee68d04ed8df
4
+ data.tar.gz: 39bc88b82f608a2a74de630c334bd6a7021a92666e8843fc4ba81e3f1b3a2b03
5
5
  SHA512:
6
- metadata.gz: 82a6d816b613df92db94065ce6c7027b44d49e8f8df91c59c82f2ddc3c6c0bd818ec8d2c8d511285acd393ee4624bb34f66ed1c39ed5a85be7f3779aac9900d0
7
- data.tar.gz: 128ea826e0036463fcb635685e28bbc58916d073c48b5ff0100aa196bd2b824eee5117921eb571d87110b0d29b210779295b0f0fcd6d7f798c3f91e4f617e3e7
6
+ metadata.gz: 42425f432289124825d92ec02bc3350875070da6554c824fc4cb9f802d961817ae65980b6011566be24696abbecf6613e48166373e5d6476e1cf6498ae64057a
7
+ data.tar.gz: 9d09e840a91d94a02e4551fa44f2d653e40e716e4606288649320709d54c47cccc8240268b38a550466b92ebd0882f4718bd271256ca520b735d283cbbcd3294
data/.gitignore CHANGED
@@ -9,3 +9,11 @@
9
9
 
10
10
  # rspec failure tracking
11
11
  .rspec_status
12
+
13
+ # rails support app files
14
+ /spec/support/rails_app/.bundle
15
+ /spec/support/rails_app/log/*
16
+ /spec/support/rails_app/tmp/*
17
+ /spec/support/rails_app!/log/.keep
18
+ /spec/support/rails_app!/tmp/.keep
19
+ /spec/support/rails_app.byebug_history
data/.tool-versions ADDED
@@ -0,0 +1 @@
1
+ ruby 2.6.3
data/Gemfile.lock CHANGED
@@ -1,28 +1,122 @@
1
1
  PATH
2
2
  remote: .
3
3
  specs:
4
- railway-ipc (0.1.3)
4
+ railway-ipc (0.1.4)
5
5
  bunny (~> 2.2.0)
6
6
  sneakers (~> 2.3.5)
7
7
 
8
8
  GEM
9
9
  remote: https://rubygems.org/
10
10
  specs:
11
+ actioncable (5.0.7.2)
12
+ actionpack (= 5.0.7.2)
13
+ nio4r (>= 1.2, < 3.0)
14
+ websocket-driver (~> 0.6.1)
15
+ actionmailer (5.0.7.2)
16
+ actionpack (= 5.0.7.2)
17
+ actionview (= 5.0.7.2)
18
+ activejob (= 5.0.7.2)
19
+ mail (~> 2.5, >= 2.5.4)
20
+ rails-dom-testing (~> 2.0)
21
+ actionpack (5.0.7.2)
22
+ actionview (= 5.0.7.2)
23
+ activesupport (= 5.0.7.2)
24
+ rack (~> 2.0)
25
+ rack-test (~> 0.6.3)
26
+ rails-dom-testing (~> 2.0)
27
+ rails-html-sanitizer (~> 1.0, >= 1.0.2)
28
+ actionview (5.0.7.2)
29
+ activesupport (= 5.0.7.2)
30
+ builder (~> 3.1)
31
+ erubis (~> 2.7.0)
32
+ rails-dom-testing (~> 2.0)
33
+ rails-html-sanitizer (~> 1.0, >= 1.0.3)
34
+ activejob (5.0.7.2)
35
+ activesupport (= 5.0.7.2)
36
+ globalid (>= 0.3.6)
37
+ activemodel (5.0.7.2)
38
+ activesupport (= 5.0.7.2)
39
+ activerecord (5.0.7.2)
40
+ activemodel (= 5.0.7.2)
41
+ activesupport (= 5.0.7.2)
42
+ arel (~> 7.0)
43
+ activesupport (5.0.7.2)
44
+ concurrent-ruby (~> 1.0, >= 1.0.2)
45
+ i18n (>= 0.7, < 2)
46
+ minitest (~> 5.1)
47
+ tzinfo (~> 1.1)
11
48
  amq-protocol (2.3.0)
49
+ arel (7.1.4)
50
+ builder (3.2.4)
12
51
  bunny (2.2.2)
13
52
  amq-protocol (>= 2.0.1)
14
53
  byebug (9.1.0)
15
54
  coderay (1.1.2)
55
+ concurrent-ruby (1.1.5)
56
+ crass (1.0.5)
57
+ database_cleaner (1.7.0)
16
58
  diff-lcs (1.3)
59
+ erubis (2.7.0)
60
+ factory_bot (5.1.1)
61
+ activesupport (>= 4.2.0)
62
+ ffi (1.11.3)
63
+ globalid (0.4.2)
64
+ activesupport (>= 4.2.0)
17
65
  google-protobuf (3.9.2)
66
+ i18n (1.7.0)
67
+ concurrent-ruby (~> 1.0)
68
+ listen (3.0.8)
69
+ rb-fsevent (~> 0.9, >= 0.9.4)
70
+ rb-inotify (~> 0.9, >= 0.9.7)
71
+ loofah (2.4.0)
72
+ crass (~> 1.0.2)
73
+ nokogiri (>= 1.5.9)
74
+ mail (2.7.1)
75
+ mini_mime (>= 0.1.1)
18
76
  method_source (0.9.2)
77
+ mini_mime (1.0.2)
78
+ mini_portile2 (2.4.0)
79
+ minitest (5.13.0)
80
+ nio4r (2.5.2)
81
+ nokogiri (1.10.7)
82
+ mini_portile2 (~> 2.4.0)
83
+ pg (0.21.0)
19
84
  pry (0.12.2)
20
85
  coderay (~> 1.1.0)
21
86
  method_source (~> 0.9.0)
22
87
  pry-byebug (3.4.2)
23
88
  byebug (~> 9.0)
24
89
  pry (~> 0.10)
90
+ rack (2.0.7)
91
+ rack-test (0.6.3)
92
+ rack (>= 1.0)
93
+ rails (5.0.7.2)
94
+ actioncable (= 5.0.7.2)
95
+ actionmailer (= 5.0.7.2)
96
+ actionpack (= 5.0.7.2)
97
+ actionview (= 5.0.7.2)
98
+ activejob (= 5.0.7.2)
99
+ activemodel (= 5.0.7.2)
100
+ activerecord (= 5.0.7.2)
101
+ activesupport (= 5.0.7.2)
102
+ bundler (>= 1.3.0)
103
+ railties (= 5.0.7.2)
104
+ sprockets-rails (>= 2.0.0)
105
+ rails-dom-testing (2.0.3)
106
+ activesupport (>= 4.2.0)
107
+ nokogiri (>= 1.6)
108
+ rails-html-sanitizer (1.3.0)
109
+ loofah (~> 2.3)
110
+ railties (5.0.7.2)
111
+ actionpack (= 5.0.7.2)
112
+ activesupport (= 5.0.7.2)
113
+ method_source
114
+ rake (>= 0.8.7)
115
+ thor (>= 0.18.1, < 2.0)
25
116
  rake (13.0.0)
117
+ rb-fsevent (0.10.3)
118
+ rb-inotify (0.10.0)
119
+ ffi (~> 1.0)
26
120
  rspec (3.8.0)
27
121
  rspec-core (~> 3.8.0)
28
122
  rspec-expectations (~> 3.8.0)
@@ -35,28 +129,58 @@ GEM
35
129
  rspec-mocks (3.8.1)
36
130
  diff-lcs (>= 1.2.0, < 2.0)
37
131
  rspec-support (~> 3.8.0)
132
+ rspec-rails (3.8.3)
133
+ actionpack (>= 3.0)
134
+ activesupport (>= 3.0)
135
+ railties (>= 3.0)
136
+ rspec-core (~> 3.8.0)
137
+ rspec-expectations (~> 3.8.0)
138
+ rspec-mocks (~> 3.8.0)
139
+ rspec-support (~> 3.8.0)
38
140
  rspec-support (3.8.2)
39
141
  serverengine (1.5.11)
40
142
  sigdump (~> 0.2.2)
143
+ shoulda-matchers (4.2.0)
144
+ activesupport (>= 4.2.0)
41
145
  sigdump (0.2.4)
42
146
  sneakers (2.3.5)
43
147
  bunny (~> 2.2.0)
44
148
  serverengine (~> 1.5.11)
45
149
  thor
46
150
  thread (~> 0.1.7)
151
+ sprockets (4.0.0)
152
+ concurrent-ruby (~> 1.0)
153
+ rack (> 1, < 3)
154
+ sprockets-rails (3.2.1)
155
+ actionpack (>= 4.0)
156
+ activesupport (>= 4.0)
157
+ sprockets (>= 3.0.0)
47
158
  thor (0.20.3)
48
159
  thread (0.1.7)
160
+ thread_safe (0.3.6)
161
+ tzinfo (1.2.5)
162
+ thread_safe (~> 0.1)
163
+ websocket-driver (0.6.5)
164
+ websocket-extensions (>= 0.1.0)
165
+ websocket-extensions (0.1.4)
49
166
 
50
167
  PLATFORMS
51
168
  ruby
52
169
 
53
170
  DEPENDENCIES
54
171
  bundler (= 2.0.1)
172
+ database_cleaner (~> 1.7)
173
+ factory_bot (~> 5.1)
55
174
  google-protobuf (~> 3.9)
175
+ listen (~> 3.0.5)
176
+ pg (~> 0.18)
56
177
  pry-byebug (= 3.4.2)
178
+ rails (~> 5.0.7)
57
179
  railway-ipc!
58
180
  rake (>= 10.0.0)
59
181
  rspec (~> 3.0)
182
+ rspec-rails
183
+ shoulda-matchers (~> 4.2)
60
184
 
61
185
  BUNDLED WITH
62
186
  2.0.1
data/README.md CHANGED
@@ -35,7 +35,12 @@ require "railway_ipc"
35
35
  RABBITMQ_CONNECTION_URL=amqp://<railway_user>:<railway_password>@localhost:5672
36
36
  ```
37
37
 
38
+ * Load table migrations and migrate by executing:
38
39
 
40
+ ```bash
41
+ bundle exec rake railway_ipc:generate:migrations
42
+ bundle exec rake db:migrate
43
+ ```
39
44
 
40
45
  # Publish/Consume
41
46
 
data/lib/railway_ipc.rb CHANGED
@@ -1,26 +1,30 @@
1
- require "railway_ipc/version"
2
- require "sneakers"
3
- require "bunny"
4
- require "railway_ipc/version"
5
- require "railway_ipc/logger"
6
- require "railway_ipc/unhandled_message_error"
7
- require "railway_ipc/response"
8
- require "railway_ipc/rabbitmq/payload"
9
- require "railway_ipc/null_message"
10
- require "railway_ipc/concerns/message_handling"
11
- require "railway_ipc/rabbitmq/connection"
12
- require "railway_ipc/handler"
13
- require "railway_ipc/consumer"
14
- require "railway_ipc/publisher"
15
- require "railway_ipc/null_handler"
16
- require "railway_ipc/responder"
17
- require "railway_ipc/client"
18
- require "railway_ipc/server"
19
- require "railway_ipc/railtie" if defined?(Rails)
1
+ require 'railway_ipc/version'
2
+ require 'sneakers'
3
+ require 'bunny'
4
+ require 'active_record'
5
+ require 'railway_ipc/version'
6
+ require 'railway_ipc/errors'
7
+ require 'railway_ipc/logger'
8
+ require 'railway_ipc/unhandled_message_error'
9
+ require 'railway_ipc/response'
10
+ require 'railway_ipc/rabbitmq/payload'
11
+ require 'railway_ipc/null_message'
12
+ require 'railway_ipc/base_message.pb'
13
+ require 'railway_ipc/rabbitmq/adapter'
14
+ require 'railway_ipc/handler'
15
+ require 'railway_ipc/handler_store'
16
+ require 'railway_ipc/publisher'
17
+ require 'railway_ipc/null_handler'
18
+ require 'railway_ipc/responder'
19
+ require 'railway_ipc/rpc/rpc'
20
+ require 'railway_ipc/consumer/consumer'
21
+ require 'railway_ipc/models/published_message'
22
+ require 'railway_ipc/models/consumed_message'
23
+ require 'railway_ipc/railtie' if defined?(Rails)
20
24
 
21
25
  module RailwayIpc
22
26
  def self.start
23
- Rake::Task["sneakers:run"].invoke
27
+ Rake::Task['sneakers:run'].invoke
24
28
  end
25
29
 
26
30
  def self.configure(logger: ::Logger.new(STDOUT))
@@ -36,6 +40,9 @@ module RailwayIpc
36
40
  end
37
41
 
38
42
  def self.bunny_connection
39
- @bunny_connection ||= RailwayIpc::Rabbitmq::Connection.create_bunny_connection
43
+ @bunny_connection ||= RailwayIpc::Rabbitmq::Adapter.new(
44
+ exchange_name: 'default',
45
+ options: { automatic_recovery: true }
46
+ ).connection
40
47
  end
41
48
  end
@@ -0,0 +1,21 @@
1
+ # Generated by the protocol buffer compiler. DO NOT EDIT!
2
+ # source: lib/src/events/base_message.proto
3
+
4
+ require 'google/protobuf'
5
+
6
+ Google::Protobuf::DescriptorPool.generated_pool.build do
7
+ add_message "railway_ipc.BaseMessage" do
8
+ optional :user_uuid, :string, 1
9
+ optional :correlation_id, :string, 2
10
+ optional :uuid, :string, 3
11
+ map :context, :string, :string, 4
12
+ optional :data, :message, 5, "railway_ipc.BaseMessage.Data"
13
+ end
14
+ add_message "railway_ipc.BaseMessage.Data" do
15
+ end
16
+ end
17
+
18
+ module RailwayIpc
19
+ BaseMessage = Google::Protobuf::DescriptorPool.generated_pool.lookup("railway_ipc.BaseMessage").msgclass
20
+ BaseMessage::Data = Google::Protobuf::DescriptorPool.generated_pool.lookup("railway_ipc.BaseMessage.Data").msgclass
21
+ end
@@ -0,0 +1,112 @@
1
+ require "json"
2
+ require "base64"
3
+ require "railway_ipc/consumer/consumer_response_handlers"
4
+
5
+ module RailwayIpc
6
+ class Consumer
7
+ include Sneakers::Worker
8
+ attr_reader :message, :handler, :protobuff_message, :delivery_info, :decoded_payload
9
+
10
+ def self.listen_to(queue:, exchange:)
11
+ from_queue queue,
12
+ exchange: exchange,
13
+ durable: true,
14
+ exchange_type: :fanout,
15
+ connection: RailwayIpc.bunny_connection
16
+ end
17
+
18
+ def self.handle(message_type, with:)
19
+ ConsumerResponseHandlers.instance.register(message: message_type, handler: with)
20
+ end
21
+
22
+ def registered_handlers
23
+ ConsumerResponseHandlers.instance.registered
24
+ end
25
+
26
+ def work_with_params(payload, delivery_info, _metadata)
27
+ @delivery_info = delivery_info
28
+ @decoded_payload = RailwayIpc::Rabbitmq::Payload.decode(payload)
29
+
30
+ case decoded_payload.type
31
+ when *registered_handlers
32
+ @handler = handler_for(decoded_payload)
33
+ message_klass = message_handler_for(decoded_payload)
34
+ @protobuff_message = message_klass.decode(decoded_payload.message)
35
+ process_known_message_type
36
+ else
37
+ @handler = RailwayIpc::NullHandler.new
38
+ @protobuff_message = RailwayIpc::BaseMessage.decode(decoded_payload.message)
39
+ process_unknown_message_type
40
+ end
41
+
42
+ rescue StandardError => e
43
+ RailwayIpc.logger.log_exception(
44
+ feature: "railway_consumer",
45
+ error: e.class,
46
+ error_message: e.message,
47
+ payload: payload,
48
+ )
49
+ raise e
50
+ end
51
+
52
+ private
53
+
54
+ def process_protobuff!(message)
55
+ if handler.handle(protobuff_message).success?
56
+ message.status = RailwayIpc::ConsumedMessage::STATUSES[:success]
57
+ else
58
+ message.status = RailwayIpc::ConsumedMessage::STATUSES[:failed_to_process]
59
+ end
60
+
61
+ message.save!
62
+ end
63
+
64
+ def process_known_message_type
65
+ message = RailwayIpc::ConsumedMessage.find_by(uuid: protobuff_message.uuid)
66
+
67
+ if message && message.processed?
68
+ handler.ack!
69
+ elsif message && !message.processed?
70
+ message.with_lock("FOR UPDATE NOWAIT") { process_protobuff!(message) }
71
+ else
72
+ message = create_message_with_status!(RailwayIpc::ConsumedMessage::STATUSES[:processing])
73
+ message.with_lock("FOR UPDATE NOWAIT") { process_protobuff!(message) }
74
+ end
75
+
76
+ nil
77
+ end
78
+
79
+ def process_unknown_message_type
80
+ handler.ack!
81
+
82
+ if RailwayIpc::ConsumedMessage.exists?(uuid: protobuff_message.uuid)
83
+ return
84
+ else
85
+ create_message_with_status!(RailwayIpc::ConsumedMessage::STATUSES[:unknown_message_type])
86
+ end
87
+
88
+ nil
89
+ end
90
+
91
+ def create_message_with_status!(status)
92
+ RailwayIpc::ConsumedMessage.create!(
93
+ uuid: protobuff_message.uuid,
94
+ status: status,
95
+ message_type: decoded_payload.type,
96
+ user_uuid: protobuff_message.user_uuid,
97
+ correlation_id: protobuff_message.correlation_id,
98
+ queue: delivery_info.consumer.queue.name,
99
+ exchange: delivery_info.exchange,
100
+ encoded_message: decoded_payload.message
101
+ )
102
+ end
103
+
104
+ def message_handler_for(decoded_payload)
105
+ ConsumerResponseHandlers.instance.get(decoded_payload.type).message
106
+ end
107
+
108
+ def handler_for(decoded_payload)
109
+ ConsumerResponseHandlers.instance.get(decoded_payload.type).handler.new
110
+ end
111
+ end
112
+ end
@@ -0,0 +1,14 @@
1
+ require 'railway_ipc/handler_store'
2
+ module RailwayIpc
3
+ class ConsumerResponseHandlers
4
+ include Singleton
5
+ extend Forwardable
6
+ def_delegators :handler_store, :registered, :register, :get
7
+
8
+ private
9
+
10
+ def handler_store
11
+ @handler_store ||= RailwayIpc::HandlerStore.new
12
+ end
13
+ end
14
+ end
@@ -0,0 +1 @@
1
+ class RailwayIpc::InvalidProtobuf < StandardError; end
@@ -19,6 +19,8 @@ module RailwayIpc
19
19
  RailwayIpc.logger.error(message, "Failed to handle message")
20
20
  ack!
21
21
  end
22
+
23
+ response
22
24
  end
23
25
  end
24
26
  end