railway-ipc 1.1.0 → 2.1.0

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: f2a31b80fc9d4f13598bdc2fbd14c84c78360bd4adeb588bb63b3bb20c33a2de
4
- data.tar.gz: 2bfef85b0fbe56b0d66df365f8ffa5b7913b188658edbb63484aaa0138dfa6ba
3
+ metadata.gz: 3b65c6b026a85e5cd4ae6693711ec05d9efe714517c2a05c3bfd7111bde92eab
4
+ data.tar.gz: 944093374956d0ad82460ebbddb61f952d3ac70dbdb8294f032dd63ee2e0df9e
5
5
  SHA512:
6
- metadata.gz: a27c830370df223add103179c9e8b60d5259abbb5b21b664f0b2642d96e5736926325c07e271b08822401c312ef532ec8a6f3c03dba30ce5a637edcbbba1ed12
7
- data.tar.gz: 555cb81425239fba2c5752e238bd541db554f48eb7d46d1336122d730781e40fdd0b339a8266a49a42ace8b73909d7a26f145b9e3ea5d9602fbfcefb9db1a022
6
+ metadata.gz: 7fad19c0a2c6bc99a7e56242eaa70b6c5f449d9c641372cc4088cc5aaba1f8ac3cfcc45f6e8b003c34713c65342b676114dd7ada579ed8d8bf3b31a94838d614
7
+ data.tar.gz: 27e95ff1100792b27e07414ee681062ceb54f12c7c31308e022045184031c15793f5f187b9dfbe51746ffe0bd4cb4ab0bf1d81163cb04126598fba15d720a6ec
@@ -10,6 +10,29 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
10
10
  ### Removed
11
11
  ### Fixed
12
12
 
13
+ ## [2.0.3] - 2020-09-02
14
+ ### Fixed
15
+ * 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.
16
+
17
+ ## [2.0.2] - 2020-08-27
18
+ ### Changed
19
+ * RPC `RailwayIpc::Client` does not need to log the queue name.
20
+
21
+ ## [2.0.1] - 2020-08-24
22
+ ### Fixed
23
+ * `RailwayIpc::Logger` now handles block syntax (i.e. `logger.info { 'my message' }`) correctly.
24
+
25
+ ## [2.0.0] - 2020-08-20
26
+ ### Added
27
+ * Several additions to internal logging:
28
+ - Log messages now include a `feature` key. This can be used by logging aggregator tools to group log messages across different systems that use the gem. If one isn't provided a default value of `railway_ipc` is used.
29
+ - Protobufs are logged as a sub-hash which contains both the protobuf type and payload.
30
+ - Exchange and queue names are logged where applicable.
31
+ - The internal Bunny connection now uses the `RailwayIpc::Logger` instead of a generic `Logger`.
32
+
33
+ ### Changed
34
+ * *Breaking Change* `RailwayIpc.configure` now takes `device`, `level`, and `formatter` instead of a complete `Logger` instance. The instance is now managed internally by Railway. This is a breaking change to the `RailwayIpc.configure` API, clients will need to be updated to use the new syntax.
35
+
13
36
  ## [1.1.0] - 2020-08-07
14
37
  ### Changed
15
38
  * allow multiple consumers to handle the same message
@@ -43,7 +66,11 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
43
66
  ### Added
44
67
  - 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)
45
68
 
46
- [Unreleased]: https://github.com/learn-co/railway_ipc_gem/compare/v1.1.0...HEAD
69
+ [Unreleased]: https://github.com/learn-co/railway_ipc_gem/compare/v2.0.3...HEAD
70
+ [2.0.3]: https://github.com/learn-co/railway_ipc_gem/compare/v2.0.2...v2.0.3
71
+ [2.0.2]: https://github.com/learn-co/railway_ipc_gem/compare/v2.0.1...v2.0.2
72
+ [2.0.1]: https://github.com/learn-co/railway_ipc_gem/compare/v2.0.0...v2.0.1
73
+ [2.0.0]: https://github.com/learn-co/railway_ipc_gem/compare/v1.1.0...v2.0.0
47
74
  [1.1.0]: https://github.com/learn-co/railway_ipc_gem/compare/v1.0.1...v1.1.0
48
75
  [1.0.1]: https://github.com/learn-co/railway_ipc_gem/compare/v1.0.0...v1.0.1
49
76
  [1.0.0]: https://github.com/learn-co/railway_ipc_gem/compare/v0.1.7...v1.0.0
data/README.md CHANGED
@@ -19,7 +19,7 @@ And then execute:
19
19
  ```ruby
20
20
  # config/initializers/railway_ipc.rb
21
21
 
22
- RailwayIpc.configure(logger: Rails.logger)
22
+ RailwayIpc.configure(STDOUT, Logger::INFO, MyFormatter)
23
23
  ```
24
24
 
25
25
  * Load the rake tasks in your Rakefile
@@ -29,16 +29,12 @@ module RailwayIpc
29
29
  Rake::Task['sneakers:run'].invoke
30
30
  end
31
31
 
32
- def self.configure(logger: ::Logger.new(STDOUT))
33
- @logger = RailwayIpc::Logger.new(logger)
32
+ def self.configure(log_device=STDOUT, level=::Logger::INFO, log_formatter=nil)
33
+ @logger = RailwayIpc::Logger.new(log_device, level, log_formatter)
34
34
  end
35
35
 
36
36
  def self.logger
37
- @logger || RailwayIpc::Logger.new(::Logger.new(STDOUT))
38
- end
39
-
40
- def self.bunny_logger
41
- logger.logger
37
+ @logger || RailwayIpc::Logger.new(STDOUT)
42
38
  end
43
39
 
44
40
  def self.bunny_connection
@@ -3,6 +3,7 @@
3
3
  module RailwayIpc
4
4
  class Consumer
5
5
  include Sneakers::Worker
6
+
6
7
  def self.inherited(base)
7
8
  base.instance_eval do
8
9
  def handlers
@@ -11,12 +12,13 @@ module RailwayIpc
11
12
  end
12
13
  end
13
14
 
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
15
+ def self.listen_to(queue:, exchange:, options: {})
16
+ from_queue queue, {
17
+ exchange: exchange,
18
+ durable: true,
19
+ exchange_type: :fanout,
20
+ connection: RailwayIpc.bunny_connection
21
+ }.merge(options)
20
22
  end
21
23
 
22
24
  def self.handle(message_type, with:)
@@ -44,10 +46,12 @@ module RailwayIpc
44
46
  RailwayIpc::ProcessIncomingMessage.call(self, message)
45
47
  ack!
46
48
  rescue StandardError => e
47
- RailwayIpc.logger.log_exception(
48
- feature: 'railway_consumer',
49
+ RailwayIpc.logger.error(
50
+ e.message,
51
+ feature: 'railway_ipc_consumer',
52
+ exchange: exchange_name,
53
+ queue: queue_name,
49
54
  error: e.class,
50
- error_message: e.message,
51
55
  payload: payload
52
56
  )
53
57
  raise e
@@ -16,8 +16,9 @@ module RailwayIpc
16
16
 
17
17
  def run
18
18
  logger.warn(
19
- incoming_message.decoded,
20
- "Ignoring unknown message of type '#{incoming_message.type}'"
19
+ "Ignoring unknown message of type '#{incoming_message.type}'",
20
+ feature: 'railway_ipc_consumer',
21
+ protobuf: { type: incoming_message.type, data: incoming_message.decoded }
21
22
  )
22
23
  end
23
24
  end
@@ -36,8 +37,9 @@ module RailwayIpc
36
37
 
37
38
  def run
38
39
  logger.warn(
39
- incoming_message.decoded,
40
- "Ignoring message, no registered handler for '#{incoming_message.type}'"
40
+ "Ignoring message, no registered handler for '#{incoming_message.type}'",
41
+ feature: 'railway_ipc_consumer',
42
+ protobuf: { type: incoming_message.type, data: incoming_message.decoded }
41
43
  )
42
44
  end
43
45
  end
@@ -81,7 +83,13 @@ module RailwayIpc
81
83
 
82
84
  def raise_message_invalid_error
83
85
  error = "Message is invalid: #{incoming_message.stringify_errors}."
84
- logger.error(incoming_message.decoded, error)
86
+ logger.error(
87
+ error,
88
+ feature: 'railway_ipc_consumer',
89
+ exchange: consumer.exchange_name,
90
+ queue: consumer.queue_name,
91
+ protobuf: { type: incoming_message.class, data: incoming_message.decoded }
92
+ )
85
93
  raise RailwayIpc::IncomingMessage::InvalidMessage.new(error)
86
94
  end
87
95
 
@@ -11,15 +11,27 @@ module RailwayIpc
11
11
  end
12
12
 
13
13
  def handle(message)
14
- RailwayIpc.logger.info(message, 'Handling message')
14
+ RailwayIpc.logger.info('Handling message', log_message_options(message))
15
15
  response = self.class.block.call(message)
16
16
  if response.success?
17
- RailwayIpc.logger.info(message, 'Successfully handled message')
17
+ RailwayIpc.logger.info('Successfully handled message', log_message_options(message))
18
18
  else
19
- RailwayIpc.logger.error(message, 'Failed to handle message')
19
+ RailwayIpc.logger.error('Failed to handle message', log_message_options(message))
20
20
  end
21
21
 
22
22
  response
23
23
  end
24
+
25
+ private
26
+
27
+ def log_message_options(message)
28
+ {
29
+ feature: 'railway_ipc_consumer',
30
+ protobuf: {
31
+ type: message.class.name,
32
+ data: message
33
+ }
34
+ }
35
+ end
24
36
  end
25
37
  end
@@ -1,36 +1,53 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module RailwayIpc
4
+ # Custom logger that accepts a `device`, `level`, and `formatter`.
5
+ # `formatter` can be any object that responds to `call`; a
6
+ # `Logger::Formatter` is used if the argument is not provided.
7
+ #
8
+ # Here is an example formatter that uses `Oj` to format structured log
9
+ # messages:
10
+ #
11
+ # require 'oj'
12
+ # OjFormatter = proc do |severity, datetime, progname, data|
13
+ # data.merge!(
14
+ # name: progname,
15
+ # timestamp: datetime,
16
+ # severity: severity
17
+ # )
18
+ # Oj.dump(data, { mode: :compat, time_format: :xmlschema })
19
+ # end
20
+ #
21
+ # logger = RailwayIpc::Logger.new(STDOUT, Logger::INFO, OjFormatter)
22
+ #
4
23
  class Logger
5
- attr_reader :logger
6
-
7
- def initialize(logger)
8
- @logger = logger
9
- end
10
-
11
- def info(message, statement)
12
- logger.info("[#{message_header(message)}] #{statement}")
24
+ def initialize(device=STDOUT, level=::Logger::INFO, formatter=nil)
25
+ @logger = ::Logger.new(device)
26
+ @logger.level = level
27
+ @logger.formatter = formatter if formatter
13
28
  end
14
29
 
15
- def warn(message, statement)
16
- logger.warn("[#{message_header(message)}] #{statement}")
30
+ %w[fatal error warn info debug].each do |level|
31
+ define_method(level) do |message=nil, data={}, &block|
32
+ data.merge!(feature: 'railway_ipc') unless data.key?(:feature)
33
+ return logger.send(level, data.merge(message: message)) unless block
34
+
35
+ data = message.merge(data) if message&.is_a?(Hash)
36
+ data.merge!(message: block.call)
37
+
38
+ # This is for compatability w/ Ruby's Logger. Ruby's Logger class
39
+ # assumes that if both a `message` argument and a block are given,
40
+ # that the block contains the actual message. The `message` argument
41
+ # is assumed to be the `progname`.
42
+ #
43
+ # https://github.com/ruby/logger/blob/master/lib/logger.rb#L471
44
+ data.merge!(progname: message) if message&.is_a?(String)
45
+ logger.send(level, data)
46
+ end
17
47
  end
18
48
 
19
- def debug(message, statement)
20
- logger.debug("[#{message_header(message)}] #{statement}")
21
- end
49
+ private
22
50
 
23
- def error(message, statement)
24
- logger.error("[#{message_header(message)}] #{statement}")
25
- end
26
-
27
- def log_exception(exception)
28
- logger.error(exception)
29
- end
30
-
31
- def message_header(message)
32
- log_statement = "message type: #{message.class}, uuid: #{message.uuid}, correlation_id: #{message.correlation_id}"
33
- message.respond_to?(:user_uuid) ? "#{log_statement}, user_uuid: #{message.user_uuid}" : log_statement
34
- end
51
+ attr_reader :logger
35
52
  end
36
53
  end
@@ -21,16 +21,15 @@ module RailwayIpc
21
21
  end
22
22
 
23
23
  def publish(message, published_message_store=RailwayIpc::PublishedMessage)
24
- RailwayIpc.logger.logger.warn('DEPRECATED: Use new PublisherInstance class')
24
+ RailwayIpc.logger.warn('DEPRECATED: Use new PublisherInstance class', log_message_options)
25
25
  ensure_message_uuid(message)
26
26
  ensure_correlation_id(message)
27
- RailwayIpc.logger.info(message, 'Publishing message')
28
-
27
+ RailwayIpc.logger.info('Publishing message', log_message_options(message))
29
28
  result = super(RailwayIpc::Rabbitmq::Payload.encode(message))
30
29
  published_message_store.store_message(self.class.exchange_name, message)
31
30
  result
32
31
  rescue RailwayIpc::InvalidProtobuf => e
33
- RailwayIpc.logger.error(message, 'Invalid protobuf')
32
+ RailwayIpc.logger.error('Invalid protobuf', log_message_options(message))
34
33
  raise e
35
34
  end
36
35
 
@@ -45,6 +44,11 @@ module RailwayIpc
45
44
  message.correlation_id = SecureRandom.uuid if message.correlation_id.blank?
46
45
  message
47
46
  end
47
+
48
+ def log_message_options(message=nil)
49
+ options = { feature: 'railway_ipc_publisher', exchange: self.class.exchange_name }
50
+ message.nil? ? options : options.merge(protobuf: { type: message.class, data: message })
51
+ end
48
52
  end
49
53
  end
50
54
 
@@ -68,20 +72,33 @@ module RailwayIpc
68
72
  def publish(message)
69
73
  message.uuid = SecureRandom.uuid if message.uuid.blank?
70
74
  message.correlation_id = SecureRandom.uuid if message.correlation_id.blank?
71
- RailwayIpc.logger.info(message, 'Publishing message')
75
+ RailwayIpc.logger.info('Publishing message', log_message_options(message))
72
76
 
73
77
  stored_message = message_store.store_message(exchange_name, message)
74
78
  super(RailwayIpc::Rabbitmq::Payload.encode(message))
75
79
  rescue RailwayIpc::InvalidProtobuf => e
76
- RailwayIpc.logger.error(message, 'Invalid protobuf')
80
+ RailwayIpc.logger.error('Invalid protobuf', log_message_options(message))
77
81
  raise e
78
82
  rescue ActiveRecord::RecordInvalid => e
79
- RailwayIpc.logger.error(message, 'Failed to store outgoing message')
83
+ RailwayIpc.logger.error('Failed to store outgoing message', log_message_options(message))
80
84
  raise RailwayIpc::FailedToStoreOutgoingMessage.new(e)
81
85
  rescue StandardError => e
82
86
  stored_message&.destroy
83
87
  raise e
84
88
  end
85
89
  # rubocop:enable Metrics/AbcSize
90
+
91
+ private
92
+
93
+ def log_message_options(message)
94
+ {
95
+ feature: 'railway_ipc_publisher',
96
+ exchange: exchange_name,
97
+ protobuf: {
98
+ type: message.class,
99
+ data: message
100
+ }
101
+ }
102
+ end
86
103
  end
87
104
  end
@@ -28,7 +28,7 @@ module RailwayIpc
28
28
  port: settings[:port],
29
29
  vhost: vhost,
30
30
  automatic_recovery: false,
31
- logger: RailwayIpc.bunny_logger
31
+ logger: RailwayIpc.logger
32
32
  }.merge(options))
33
33
  end
34
34
 
@@ -11,7 +11,11 @@ module RailwayIpc
11
11
  end
12
12
 
13
13
  def respond(request)
14
- RailwayIpc.logger.info(request, 'Responding to request')
14
+ RailwayIpc.logger.info(
15
+ 'Responding to request',
16
+ protobuf: { type: request.class, data: request },
17
+ feature: 'railway_ipc_request'
18
+ )
15
19
  response = self.class.block.call(request)
16
20
  raise ResponseTypeError.new(response.class) unless response.is_a?(Google::Protobuf::MessageExts)
17
21
 
@@ -44,7 +44,12 @@ module RailwayIpc
44
44
  case decoded_payload.type
45
45
  when *registered_handlers
46
46
  @message = get_message_class(decoded_payload).decode(decoded_payload.message)
47
- RailwayIpc.logger.info(message, 'Handling response')
47
+ RailwayIpc.logger.info(
48
+ 'Handling response',
49
+ feature: 'railway_ipc_consumer',
50
+ exchange: self.class.exchange_name,
51
+ protobuf: { type: message.class, data: message }
52
+ )
48
53
  RailwayIpc::Response.new(message, success: true)
49
54
  else
50
55
  @message = LearnIpc::ErrorMessage.decode(decoded_payload.message)
@@ -78,10 +83,11 @@ module RailwayIpc
78
83
  private
79
84
 
80
85
  def log_exception(exception, payload)
81
- RailwayIpc.logger.log_exception(
82
- feature: 'railway_consumer',
86
+ RailwayIpc.logger.error(
87
+ exception.message,
88
+ feature: 'railway_ipc_consumer',
89
+ exchange: self.class.exchange_name,
83
90
  error: exception.class,
84
- error_message: exception.message,
85
91
  payload: decode_for_error(exception, payload)
86
92
  )
87
93
  end
@@ -99,7 +105,12 @@ module RailwayIpc
99
105
  end
100
106
 
101
107
  def publish_message
102
- RailwayIpc.logger.info(request_message, 'Sending request')
108
+ RailwayIpc.logger.info(
109
+ 'Sending request',
110
+ feature: 'railway_ipc_publisher',
111
+ exchange: self.class.exchange_name,
112
+ protobuf: { type: request_message.class, data: request_message }
113
+ )
103
114
  rabbit_connection.publish(RailwayIpc::Rabbitmq::Payload.encode(request_message), routing_key: '')
104
115
  end
105
116
 
@@ -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)
@@ -45,10 +49,12 @@ module RailwayIpc
45
49
  raise RailwayIpc::UnhandledMessageError.new("#{self.class} does not know how to handle #{decoded_payload.type}")
46
50
  end
47
51
  rescue StandardError => e
48
- RailwayIpc.logger.log_exception(
49
- feature: 'railway_consumer',
52
+ RailwayIpc.logger.error(
53
+ e.message,
54
+ feature: 'railway_ipc_consumer',
55
+ exchange: self.class.exchange_name,
56
+ queue: self.class.queue_name,
50
57
  error: e.class,
51
- error_message: e.message,
52
58
  payload: payload
53
59
  )
54
60
  raise e
@@ -56,10 +62,19 @@ module RailwayIpc
56
62
  # rubocop:enable Metrics/AbcSize
57
63
  # rubocop:enable Metrics/MethodLength
58
64
 
65
+ # rubocop:disable Metrics/AbcSize
66
+ # rubocop:disable Metrics/MethodLength
59
67
  def handle_request(payload)
60
68
  response = work(payload)
61
69
  rescue StandardError => e
62
- RailwayIpc.logger.error(message, "Error responding to message. Error: #{e.class}, #{e.message}")
70
+ RailwayIpc.logger.error(
71
+ 'Error responding to message.',
72
+ exception: e,
73
+ feature: 'railway_ipc_consumer',
74
+ exchange: self.class.exchange_name,
75
+ queue: self.class.queue_name,
76
+ protobuf: { type: message.class, data: message }
77
+ )
63
78
  response = self.class.rpc_error_adapter_class.error_message(e, message)
64
79
  ensure
65
80
  if response
@@ -68,6 +83,8 @@ module RailwayIpc
68
83
  )
69
84
  end
70
85
  end
86
+ # rubocop:enable Metrics/AbcSize
87
+ # rubocop:enable Metrics/MethodLength
71
88
 
72
89
  private
73
90
 
@@ -1,5 +1,5 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module RailwayIpc
4
- VERSION = '1.1.0'
4
+ VERSION = '2.1.0'
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: 1.1.0
4
+ version: 2.1.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - ''
8
- autorequire:
8
+ autorequire:
9
9
  bindir: exe
10
10
  cert_chain: []
11
- date: 2020-08-07 00:00:00.000000000 Z
11
+ date: 2020-10-19 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
@@ -263,7 +263,7 @@ licenses:
263
263
  - MIT
264
264
  metadata:
265
265
  allowed_push_host: https://rubygems.org/
266
- post_install_message:
266
+ post_install_message:
267
267
  rdoc_options: []
268
268
  require_paths:
269
269
  - lib
@@ -278,9 +278,8 @@ required_rubygems_version: !ruby/object:Gem::Requirement
278
278
  - !ruby/object:Gem::Version
279
279
  version: '0'
280
280
  requirements: []
281
- rubyforge_project:
282
- rubygems_version: 2.7.6
283
- signing_key:
281
+ rubygems_version: 3.0.3
282
+ signing_key:
284
283
  specification_version: 4
285
284
  summary: IPC components for Rails
286
285
  test_files: []