railway-ipc 2.0.2 → 2.2.2

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 CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 38510e51a7320246c8351c026b49b77a72c3886d96f39735749bb2d8b0c580e8
4
- data.tar.gz: '06182d40648d84f3c1a421073fc566fae21c8d966f241602ab29d260aea74d8e'
3
+ metadata.gz: a407ec255b81d23755164c8a2a45393092bd7d5eb2d39caa9e89125974f1822b
4
+ data.tar.gz: 4fd881a27222a11f767f64908aff24851c03a09a3f23cd1dfcf32ea7295c1971
5
5
  SHA512:
6
- metadata.gz: 95f03fe787853fa46d71adba1bb452cbd6f514bae0c25a9c068df148769ac6aa1f22237162bdbbc6c099cc4f81623086be76d8b53083661eddfd3427835be5ba
7
- data.tar.gz: f8a5736baf4ca3d84c57896d30db7deefcd26068b3c56c108b5f673d9e62368fea48fb9c9004479e92282edcdf77e86c0523374966f4e627530a665c6fec8f6f
6
+ metadata.gz: 79135cc5e3a2ee00ec1c79b00f168c5aa4ff7b9bf36c3aba6564c66a5644da1fe787f077443ebf5020660280cd98b58dbd2cc638b64962cc91663226ca87a359
7
+ data.tar.gz: 0ff544182b441fafc71d9be9bfdfc8dfc344dbe9142812559570d7f01cd57cc81d4311599d0a160951d45da9b81309f843f18ae57a3d4010282ba619034b1967
data/.gitignore CHANGED
@@ -8,6 +8,9 @@
8
8
  /tmp/
9
9
  Gemfile.lock
10
10
 
11
+ # built gems
12
+ railway-ipc-*.gem
13
+
11
14
  # rspec failure tracking
12
15
  .rspec_status
13
16
 
@@ -10,6 +10,27 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
10
10
  ### Removed
11
11
  ### Fixed
12
12
 
13
+ ## [2.2.2] - 2020-11-20
14
+ ### Fixed
15
+ * Fixed Publisher class channel leak. Channels were being created on each
16
+ instantiation of a Publisher instead of being re-used.
17
+
18
+ ## [2.2.1] - 2020-10-20
19
+ ### Added
20
+ * Logging to indicate when options passed via `listen_to`/`from_queue` are overriding the defaults.
21
+
22
+ ## [2.2.0] - 2020-10-20
23
+ ### Added
24
+ * The ability to configure workers to handle different workloads via `rake railway_ipc::consumers:spawn`
25
+
26
+ ## [2.1.0] - 2020-10-19
27
+ ### Added
28
+ * :options parameter to `listen_to` which passes keys along to Sneaker's `from_queue` method.
29
+
30
+ ## [2.0.3] - 2020-09-02
31
+ ### Fixed
32
+ * Fix RPC server. RPC servers need to conform to the Sneaker worker API (i.e. their initializers need to be able to accept queue name / pool and they require a `stop` method.
33
+
13
34
  ## [2.0.2] - 2020-08-27
14
35
  ### Changed
15
36
  * RPC `RailwayIpc::Client` does not need to log the queue name.
@@ -62,7 +83,12 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
62
83
  ### Added
63
84
  - Correlation ID and message UUID are auto generated for messages for IDs are not passed in [#23](https://github.com/learn-co/railway_ipc_gem/pull/23)
64
85
 
65
- [Unreleased]: https://github.com/learn-co/railway_ipc_gem/compare/v2.0.2...HEAD
86
+ [Unreleased]: https://github.com/learn-co/railway_ipc_gem/compare/v2.2.2...HEAD
87
+ [2.2.2]: https://github.com/learn-co/railway_ipc_gem/compare/v2.2.1...v2.2.2
88
+ [2.2.1]: https://github.com/learn-co/railway_ipc_gem/compare/v2.2.0...v2.2.1
89
+ [2.2.0]: https://github.com/learn-co/railway_ipc_gem/compare/v2.1.0...v2.2.0
90
+ [2.1.0]: https://github.com/learn-co/railway_ipc_gem/compare/v2.0.3...v2.1.0
91
+ [2.0.3]: https://github.com/learn-co/railway_ipc_gem/compare/v2.0.2...v2.0.3
66
92
  [2.0.2]: https://github.com/learn-co/railway_ipc_gem/compare/v2.0.1...v2.0.2
67
93
  [2.0.1]: https://github.com/learn-co/railway_ipc_gem/compare/v2.0.0...v2.0.1
68
94
  [2.0.0]: https://github.com/learn-co/railway_ipc_gem/compare/v1.1.0...v2.0.0
data/README.md CHANGED
@@ -52,6 +52,26 @@ Then, run your consumers
52
52
  bundle exec rake railway_ipc:consumers:start CONSUMERS=YourConsumer,YourOtherConsumer
53
53
  ```
54
54
 
55
+ You may also configure your consumers more granularly using:
56
+
57
+ `./config/sneaker_worker_groups.yml`
58
+ ```yaml
59
+ HighPriority:
60
+ classes: YourConsumer,YourOtherConsumer
61
+ workers: 5
62
+ LowPriority:
63
+ classes: YourThirdConsumer
64
+ workers: 1
65
+ ```
66
+
67
+ ```bash
68
+ bundle exec rake railway_ipc:consumers:spawn
69
+ ```
70
+
71
+ By default, `spawn` will map to `./config/sneaker_worker_groups.yml` but you can override it by using `WORKER_GROUP_CONFIG`.
72
+
73
+ See the [Sneaker Documentation](https://github.com/jondot/sneakers/wiki/Handling-different-workloads) for more information.
74
+
55
75
  # Request/Response
56
76
 
57
77
  Define your server, client and responder. Docs coming soon.
@@ -2,9 +2,10 @@
2
2
 
3
3
  require 'railway_ipc/version'
4
4
  require 'sneakers'
5
+ require 'sneakers/spawner'
5
6
  require 'bunny'
6
7
  require 'active_record'
7
- require 'railway_ipc/version'
8
+ require 'singleton'
8
9
  require 'railway_ipc/logger'
9
10
  require 'railway_ipc/unhandled_message_error'
10
11
  require 'railway_ipc/response'
@@ -14,6 +15,7 @@ require 'railway_ipc/rabbitmq/adapter'
14
15
  require 'railway_ipc/handler'
15
16
  require 'railway_ipc/handler_store'
16
17
  require 'railway_ipc/incoming_message'
18
+ require 'railway_ipc/connection_manager'
17
19
  require 'railway_ipc/publisher'
18
20
  require 'railway_ipc/responder'
19
21
  require 'railway_ipc/rpc/rpc'
@@ -29,12 +31,16 @@ module RailwayIpc
29
31
  Rake::Task['sneakers:run'].invoke
30
32
  end
31
33
 
32
- def self.configure(log_device=STDOUT, level=::Logger::INFO, log_formatter=nil)
34
+ def self.spawn
35
+ Sneakers::Spawner.spawn
36
+ end
37
+
38
+ def self.configure(log_device=$stdout, level=::Logger::INFO, log_formatter=nil)
33
39
  @logger = RailwayIpc::Logger.new(log_device, level, log_formatter)
34
40
  end
35
41
 
36
42
  def self.logger
37
- @logger || RailwayIpc::Logger.new(STDOUT)
43
+ @logger || RailwayIpc::Logger.new($stdout)
38
44
  end
39
45
 
40
46
  def self.bunny_connection
@@ -0,0 +1,52 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'singleton'
4
+
5
+ module RailwayIpc
6
+ # RabbitMQ connection manager. Ensures there is a single RabbitMQ
7
+ # connection and channel per thread, which prevents channel leaks.
8
+ #
9
+ class ConnectionManager
10
+ include Singleton
11
+
12
+ def initialize
13
+ establish_connection
14
+ end
15
+
16
+ def establish_connection
17
+ @connection = Bunny.new(
18
+ host: settings[:host],
19
+ user: settings[:user],
20
+ pass: settings[:pass],
21
+ port: settings[:port],
22
+ vhost: settings[:vhost] || '/',
23
+ logger: RailwayIpc.logger
24
+ )
25
+ @connection.start
26
+ @channel = @connection.create_channel
27
+
28
+ @connection
29
+ end
30
+
31
+ def channel
32
+ return @channel if connected?
33
+
34
+ establish_connection
35
+ @channel
36
+ end
37
+
38
+ def connected?
39
+ @connection&.connected? && @channel&.open?
40
+ end
41
+
42
+ private
43
+
44
+ def amqp_url
45
+ @amqp_url ||= ENV.fetch('RAILWAY_RABBITMQ_CONNECTION_URL', 'amqp://guest:guest@localhost:5672')
46
+ end
47
+
48
+ def settings
49
+ @settings ||= AMQ::Settings.parse_amqp_url(amqp_url)
50
+ end
51
+ end
52
+ end
@@ -3,7 +3,10 @@
3
3
  module RailwayIpc
4
4
  class Consumer
5
5
  include Sneakers::Worker
6
+
6
7
  def self.inherited(base)
8
+ super
9
+
7
10
  base.instance_eval do
8
11
  def handlers
9
12
  @handlers ||= RailwayIpc::HandlerStore.new
@@ -11,12 +14,21 @@ module RailwayIpc
11
14
  end
12
15
  end
13
16
 
14
- def self.listen_to(queue:, exchange:)
15
- from_queue queue,
16
- exchange: exchange,
17
- durable: true,
18
- exchange_type: :fanout,
19
- connection: RailwayIpc.bunny_connection
17
+ def self.listen_to(queue:, exchange:, options: {})
18
+ unless options.empty?
19
+ RailwayIpc.logger.info(
20
+ "Overriding configuration for #{queue} with new options",
21
+ feature: 'railway_ipc_consumer',
22
+ options: options
23
+ )
24
+ end
25
+
26
+ from_queue queue, {
27
+ exchange: exchange,
28
+ durable: true,
29
+ exchange_type: :fanout,
30
+ connection: RailwayIpc.bunny_connection
31
+ }.merge(options)
20
32
  end
21
33
 
22
34
  def self.handle(message_type, with:)
@@ -21,7 +21,7 @@ module RailwayIpc
21
21
  # logger = RailwayIpc::Logger.new(STDOUT, Logger::INFO, OjFormatter)
22
22
  #
23
23
  class Logger
24
- def initialize(device=STDOUT, level=::Logger::INFO, formatter=nil)
24
+ def initialize(device=$stdout, level=::Logger::INFO, formatter=nil)
25
25
  @logger = ::Logger.new(device)
26
26
  @logger.level = level
27
27
  @logger.formatter = formatter if formatter
@@ -32,7 +32,7 @@ module RailwayIpc
32
32
  data.merge!(feature: 'railway_ipc') unless data.key?(:feature)
33
33
  return logger.send(level, data.merge(message: message)) unless block
34
34
 
35
- data = message.merge(data) if message&.is_a?(Hash)
35
+ data = message.merge(data) if message.is_a?(Hash)
36
36
  data.merge!(message: block.call)
37
37
 
38
38
  # This is for compatability w/ Ruby's Logger. Ruby's Logger class
@@ -41,7 +41,7 @@ module RailwayIpc
41
41
  # is assumed to be the `progname`.
42
42
  #
43
43
  # https://github.com/ruby/logger/blob/master/lib/logger.rb#L471
44
- data.merge!(progname: message) if message&.is_a?(String)
44
+ data.merge!(progname: message) if message.is_a?(String)
45
45
  logger.send(level, data)
46
46
  end
47
47
  end
@@ -1,7 +1,5 @@
1
1
  # frozen_string_literal: true
2
2
 
3
- require 'singleton'
4
-
5
3
  module RailwayIpc
6
4
  class SingletonPublisher < Sneakers::Publisher
7
5
  include ::Singleton
@@ -53,19 +51,12 @@ module RailwayIpc
53
51
  end
54
52
 
55
53
  module RailwayIpc
56
- class Publisher < Sneakers::Publisher
54
+ class Publisher
57
55
  attr_reader :exchange_name, :message_store
58
56
 
59
57
  def initialize(opts={})
60
58
  @exchange_name = opts.fetch(:exchange_name)
61
59
  @message_store = opts.fetch(:message_store, RailwayIpc::PublishedMessage)
62
- connection = opts.fetch(:connection, nil)
63
- options = {
64
- exchange: exchange_name,
65
- connection: connection,
66
- exchange_type: :fanout
67
- }.compact
68
- super(options)
69
60
  end
70
61
 
71
62
  # rubocop:disable Metrics/AbcSize
@@ -75,7 +66,7 @@ module RailwayIpc
75
66
  RailwayIpc.logger.info('Publishing message', log_message_options(message))
76
67
 
77
68
  stored_message = message_store.store_message(exchange_name, message)
78
- super(RailwayIpc::Rabbitmq::Payload.encode(message))
69
+ exchange.publish(RailwayIpc::Rabbitmq::Payload.encode(message))
79
70
  rescue RailwayIpc::InvalidProtobuf => e
80
71
  RailwayIpc.logger.error('Invalid protobuf', log_message_options(message))
81
72
  raise e
@@ -88,8 +79,16 @@ module RailwayIpc
88
79
  end
89
80
  # rubocop:enable Metrics/AbcSize
90
81
 
82
+ def exchange
83
+ @exchange ||= channel.exchange(exchange_name, type: :fanout, durable: true, auto_delete: false, arguments: {})
84
+ end
85
+
91
86
  private
92
87
 
88
+ def channel
89
+ RailwayIpc::ConnectionManager.instance.channel
90
+ end
91
+
93
92
  def log_message_options(message)
94
93
  {
95
94
  feature: 'railway_ipc_publisher',
@@ -16,7 +16,7 @@ module RailwayIpc
16
16
  :port,
17
17
  :user
18
18
 
19
- def initialize(amqp_url: ENV['RAILWAY_RABBITMQ_CONNECTION_URL'], exchange_name:, queue_name: '', options: {})
19
+ def initialize(exchange_name:, amqp_url: ENV['RAILWAY_RABBITMQ_CONNECTION_URL'], queue_name: '', options: {})
20
20
  @queue_name = queue_name
21
21
  @exchange_name = exchange_name
22
22
  settings = AMQ::Settings.parse_amqp_url(amqp_url)
@@ -3,7 +3,7 @@
3
3
  module RailwayIpc
4
4
  module RPC
5
5
  module MessageObservationConfigurable
6
- def listen_to(exchange:, queue:)
6
+ def listen_to(queue:, exchange:)
7
7
  @exchange_name = exchange
8
8
  @queue_name = queue
9
9
  end
@@ -14,7 +14,7 @@ module RailwayIpc
14
14
  RailwayIpc::RPC::ServerResponseHandlers.instance.register(handler: with, message: message_type)
15
15
  end
16
16
 
17
- def initialize(opts={ automatic_recovery: true }, rabbit_adapter: RailwayIpc::Rabbitmq::Adapter)
17
+ def initialize(_queue, _pool, opts={ automatic_recovery: true }, rabbit_adapter: RailwayIpc::Rabbitmq::Adapter)
18
18
  @rabbit_connection = rabbit_adapter.new(
19
19
  queue_name: self.class.queue_name,
20
20
  exchange_name: self.class.exchange_name,
@@ -31,6 +31,10 @@ module RailwayIpc
31
31
  subscribe_to_queue
32
32
  end
33
33
 
34
+ def stop
35
+ rabbit_connection.disconnect
36
+ end
37
+
34
38
  # rubocop:disable Metrics/AbcSize
35
39
  # rubocop:disable Metrics/MethodLength
36
40
  def work(payload)
@@ -2,9 +2,15 @@
2
2
 
3
3
  namespace :railway_ipc do
4
4
  namespace :consumers do
5
+ desc 'Start consumers via explicitly defining them'
5
6
  task :start do
6
7
  ENV['WORKERS'] = ENV['CONSUMERS']
7
8
  RailwayIpc.start
8
9
  end
10
+
11
+ desc 'Start consumers via ./config/sneaker_worker_groups.yml'
12
+ task :spawn do
13
+ RailwayIpc.spawn
14
+ end
9
15
  end
10
16
  end
@@ -1,5 +1,5 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module RailwayIpc
4
- VERSION = '2.0.2'
4
+ VERSION = '2.2.2'
5
5
  end
@@ -34,7 +34,7 @@ Gem::Specification.new do |spec|
34
34
  spec.executables = spec.files.grep(%r{^exe/}) { |f| File.basename(f) }
35
35
  spec.require_paths = ['lib']
36
36
 
37
- spec.add_development_dependency 'bundler', '2.0.1'
37
+ spec.add_development_dependency 'bundler', '2.1.4'
38
38
  spec.add_development_dependency 'factory_bot', '~> 5.1'
39
39
  spec.add_development_dependency 'google-protobuf', '~> 3.9'
40
40
  spec.add_development_dependency 'rake', '>= 10.0.0'
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: railway-ipc
3
3
  version: !ruby/object:Gem::Version
4
- version: 2.0.2
4
+ version: 2.2.2
5
5
  platform: ruby
6
6
  authors:
7
7
  - ''
8
8
  autorequire:
9
9
  bindir: exe
10
10
  cert_chain: []
11
- date: 2020-08-27 00:00:00.000000000 Z
11
+ date: 2020-11-20 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: bundler
@@ -16,14 +16,14 @@ dependencies:
16
16
  requirements:
17
17
  - - '='
18
18
  - !ruby/object:Gem::Version
19
- version: 2.0.1
19
+ version: 2.1.4
20
20
  type: :development
21
21
  prerelease: false
22
22
  version_requirements: !ruby/object:Gem::Requirement
23
23
  requirements:
24
24
  - - '='
25
25
  - !ruby/object:Gem::Version
26
- version: 2.0.1
26
+ version: 2.1.4
27
27
  - !ruby/object:Gem::Dependency
28
28
  name: factory_bot
29
29
  requirement: !ruby/object:Gem::Requirement
@@ -225,6 +225,7 @@ files:
225
225
  - bin/setup
226
226
  - lib/railway_ipc.rb
227
227
  - lib/railway_ipc/Rakefile
228
+ - lib/railway_ipc/connection_manager.rb
228
229
  - lib/railway_ipc/consumer/consumer.rb
229
230
  - lib/railway_ipc/consumer/process_incoming_message.rb
230
231
  - lib/railway_ipc/errors.rb