surfliner-metadata_consumer 0.1.0.pre.alpha.6 → 0.1.0.pre.alpha.7

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: 25566009d8ccce03904d9020a0340511bbeb2fac08b5151c65705cd2d6117096
4
- data.tar.gz: 24136a3ca25672bf7fcc8670ea61f11a34c547b515022f92e46b440fe1d315cc
3
+ metadata.gz: c496d7587eb02bc3020be31fb8a9052e67e52aa08b97c3dbc81bb26d44f29fc3
4
+ data.tar.gz: 57d58bc7f428b049efc1e1f4db521970a8f43e389b966c20fb99156313c6c085
5
5
  SHA512:
6
- metadata.gz: fef5c2196922e8f5476422ffd83400bc17edc957b0822a323628dd9cd525440e231e1d7402b761c71894806282c2ad11c8c450eb6dc37a6a6e99dac7d3adc9c5
7
- data.tar.gz: 5014bdadb04910ca9888d8fe445342641462e33f6ec445333c4502dd322e428df5c5ecd01710018d7f905e80a889ce84815f7ff59b1d3908c00b405d5f02c048
6
+ metadata.gz: ebb4d7a8b61f8b03d4376454a526921d19e18eb94cca49029e8e75736ddee0ec61372a6bde72fafda21162eaa4f0ef655dc759f90150c309c8e20ec5404b450b
7
+ data.tar.gz: 43a75ff273881bf59ea4c20ae84e299b853b8c6779bc03e48e6fd42d6846a9268236aa034234ce8db6275ce600b255cac5eff23d722540496bc531347a589e7a
data/CHANGES.md CHANGED
@@ -1,3 +1,12 @@
1
+ # 0.1.0.pre.alpha.7 (2025-04-28)
2
+
3
+ - Fix issue where `RABBITMQ_AWAIT_ON_CLOSE` environment variable could
4
+ not be omitted.
5
+ - Remove `:routing_key` from `Mq::QueueConfig`, to allow using multiple
6
+ routing keys with the same queue.
7
+ - Add `Mq::Router` for routing messages from a single queue to multiple
8
+ handlers by routing key.
9
+
1
10
  # 0.1.0.pre.alpha.6 (2025-04-25)
2
11
 
3
12
  - Update to Bunny 2.24
data/Gemfile.lock CHANGED
@@ -1,7 +1,7 @@
1
1
  PATH
2
2
  remote: .
3
3
  specs:
4
- surfliner-metadata_consumer (0.1.0.pre.alpha.6)
4
+ surfliner-metadata_consumer (0.1.0.pre.alpha.7)
5
5
  bunny (~> 2.24)
6
6
  opentelemetry-exporter-otlp (~> 0.26.3)
7
7
  opentelemetry-instrumentation-all (~> 0.60.0)
@@ -294,7 +294,7 @@ GEM
294
294
  diff-lcs (>= 1.2.0, < 2.0)
295
295
  rspec-support (~> 3.13.0)
296
296
  rspec-support (3.13.2)
297
- rubocop (1.75.3)
297
+ rubocop (1.75.4)
298
298
  json (~> 2.3)
299
299
  language_server-protocol (~> 3.17.0.2)
300
300
  lint_roller (~> 1.1.0)
data/README.md CHANGED
@@ -71,6 +71,13 @@ connection.with_topic(topic_config) do |topic|
71
71
  end
72
72
  ```
73
73
 
74
+ `TopicConfig#publish` can either accept an explicit routing key, or read a default value
75
+ from the environment:
76
+
77
+ | Variable | Sample value | Description |
78
+ |---------------------------------|-------------------------------|----------------------|
79
+ | `RABBITMQ_PLATFORM_ROUTING_KEY` | `surfliner.metadata.daylight` | RabbitMQ routing key |
80
+
74
81
  Similarly, `Mq::Topic#bind_queue` can either take an explicit `QueueConfig`, or implicitly
75
82
  read a default with `QueConfig#from_env`. `QueueConfig#from_env` expects the following environment
76
83
  variables:
@@ -78,7 +85,6 @@ variables:
78
85
  | Variable | Sample value | Description |
79
86
  |---------------------------------|-------------------------------|----------------------|
80
87
  | `RABBITMQ_QUEUE` | `surfliner.metadata` | RabbitMQ queue name |
81
- | `RABBITMQ_PLATFORM_ROUTING_KEY` | `surfliner.metadata.daylight` | RabbitMQ routing key |
82
88
 
83
89
  And `QueueConfig#from_env` similarly accepts keyword options, which are forwarded to
84
90
  [`Bunny::Channel#queue`](https://api.rubybunny.info/Bunny/Channel.html#queue-instance_method):
@@ -2,6 +2,6 @@
2
2
  module Surfliner
3
3
  module MetadataConsumer
4
4
  # The gem version
5
- VERSION = "0.1.0.pre.alpha.6"
5
+ VERSION = "0.1.0.pre.alpha.7"
6
6
  end
7
7
  end
@@ -2,6 +2,7 @@ module Surfliner
2
2
  module Mq
3
3
  # An object encapsulating RabbitMQ configuration.
4
4
  class ConnectionConfig
5
+ # @return [Array<String>] values of RABBITMQ_AWAIT_ON_CLOSE interpreted as false
5
6
  FALSE_VALUES = ([""] + %w[0 off Off OFF f false False FALSE F n no No NO N]).freeze
6
7
 
7
8
  # @return [String] The RabbitMQ hostname
@@ -57,7 +58,7 @@ module Surfliner
57
58
  port: ENV.fetch("RABBITMQ_NODE_PORT_NUMBER"),
58
59
  username: ENV.fetch("RABBITMQ_USERNAME"),
59
60
  password: ENV.fetch("RABBITMQ_PASSWORD"),
60
- await_response_on_close: ENV.fetch("RABBITMQ_AWAIT_ON_CLOSE") || true,
61
+ await_response_on_close: ENV["RABBITMQ_AWAIT_ON_CLOSE"] || true,
61
62
  **opts
62
63
  )
63
64
  end
@@ -5,18 +5,13 @@ module Surfliner
5
5
  # @return [String] The queue to listen to
6
6
  attr_reader :name
7
7
 
8
- # @return [String] platform routing key to listen to
9
- attr_reader :routing_key
10
-
11
8
  # @return [Hash] RabbitMQ queue options. (See Bunny::Channel#queue)
12
9
  attr_reader :options
13
10
 
14
11
  # @param name [String] queue exchange to listen to
15
- # @param routing_key [String] platform routing key to listen to
16
12
  # @param options [Hash] RabbitMQ queue options. (See Bunny::Channel#queue)
17
- def initialize(name:, routing_key:, options: {})
13
+ def initialize(name:, options: {})
18
14
  @name = name
19
- @routing_key = routing_key
20
15
  @options = options
21
16
  end
22
17
 
@@ -27,22 +22,15 @@ module Surfliner
27
22
  # | Variable | Sample value | Description |
28
23
  # |---------------------------------|-------------------------------|----------------------|
29
24
  # | `RABBITMQ_QUEUE` | `surfliner.metadata` | RabbitMQ queue name |
30
- # | `RABBITMQ_PLATFORM_ROUTING_KEY` | `surfliner.metadata.daylight` | RabbitMQ routing key |
31
25
  #
32
26
  # @param options [Hash] RabbitMQ queue options. (See Bunny::Channel#queue)
33
27
  # @return [QueueConfig] The configuration.
34
28
  def from_env(**options)
35
29
  QueueConfig.new(
36
30
  name: ENV.fetch("RABBITMQ_QUEUE"),
37
- routing_key: default_routing_key,
38
31
  options:
39
32
  )
40
33
  end
41
-
42
- # @return [String] The default routing key from `ENV["RABBITMQ_PLATFORM_ROUTING_KEY"]`
43
- def default_routing_key
44
- ENV.fetch("RABBITMQ_PLATFORM_ROUTING_KEY")
45
- end
46
34
  end
47
35
  end
48
36
  end
@@ -0,0 +1,78 @@
1
+ module Surfliner
2
+ module Mq
3
+ # Queue subscriber that routes messages by routing key to multiple handlers
4
+ class Router
5
+ # @return [Topic] the topic
6
+ attr_reader :topic
7
+
8
+ # @return [Bunny::Queue] the queue
9
+ attr_reader :queue
10
+
11
+ # @return [Bunny::Consumer] the consumer (used to unsubscribe)
12
+ attr_reader :consumer
13
+
14
+ # Initializes a new Router and subscribes it to the specified queue
15
+ # on the specified topic.
16
+ #
17
+ # @param topic [Mq::Topic] The topic to listen on
18
+ # @param queue_config [Mq::QueueConfig] The queue to subscribe to
19
+ def initialize(topic, queue_config: QueueConfig.from_env)
20
+ @topic = topic
21
+ @queue = topic.queue(queue_config)
22
+ @consumer = queue.subscribe(&method(:on_delivery))
23
+ end
24
+
25
+ # Adds a handler for the specified routing key.
26
+ # Handlers will receive only messages with the specified routing key.
27
+ # Multiple handler blocks can be added to the same queue and/or routing key.
28
+ #
29
+ # @param routing_key [String] the routing key to filter messages by
30
+ # @yieldparam payload_json [String] each payload
31
+ def add_handler(routing_key, &block)
32
+ raise "Can't add handlers after router shutdown" if consumer.nil?
33
+
34
+ log("adding handler #{block}")
35
+ handlers = handlers_for(routing_key)
36
+ queue.bind(topic.exchange, routing_key:) if handlers.empty?
37
+ handlers << block
38
+ end
39
+
40
+ # Removes all handlers and unsubscribes from the queue.
41
+ def shutdown
42
+ log("shutting down")
43
+ handlers_by_routing_key.clear
44
+ consumer.cancel
45
+ @consumer = nil
46
+ end
47
+
48
+ private
49
+
50
+ # Receives messages and routes them to the appropriate handler
51
+ #
52
+ # @param delivery_info [Bunny::DeliveryInfo] the delivery info
53
+ # @param _metadata [Bunny::MessageProperties] the message properties
54
+ # @param payload_json [String] the payload as a string
55
+ def on_delivery(delivery_info, _metadata, payload_json)
56
+ routing_key = delivery_info.routing_key
57
+ handlers_for(routing_key).each do |handler|
58
+ log("delivering #{payload_json} to handler #{handler} for #{routing_key}")
59
+ handler.call(payload_json)
60
+ end
61
+ end
62
+
63
+ # @return [Hash{String => Array<Proc>}] all handlers by routing key
64
+ def handlers_by_routing_key
65
+ @handlers_by_routing_key ||= {}
66
+ end
67
+
68
+ # @return [Array<Proc>] the handlers for the specified key, if any
69
+ def handlers_for(routing_key)
70
+ (handlers_by_routing_key[routing_key] ||= [])
71
+ end
72
+
73
+ def log(msg)
74
+ topic.logger.debug("#{self.class}(#{topic.name}, #{queue.name}): #{msg}")
75
+ end
76
+ end
77
+ end
78
+ end
@@ -38,17 +38,36 @@ module Surfliner
38
38
  # @param payload [String] the payload to publish
39
39
  # @param routing_key [String] platform routing key to publish to
40
40
  # @return [Bunny::Exchange] see #exchange
41
- def publish(payload, routing_key: QueueConfig.default_routing_key)
41
+ def publish(payload, routing_key: default_routing_key)
42
42
  logger.info "Publishing to #{routing_key} with payload: #{payload}"
43
43
  exchange.publish(payload, routing_key:)
44
44
  end
45
45
 
46
+ # Creates or looks up the specified queue and binds it to receive
47
+ # messages with the specified routing key.
46
48
  # @param config [QueueConfig] queue configuration
47
- # @return [Bunny::Queue] the queue
48
- def bind_queue(config = QueueConfig.from_env)
49
- channel.queue(config.name, config.options).tap do |q|
50
- q.bind(exchange, routing_key: config.routing_key)
51
- end
49
+ # @param routing_key [String] platform routing key to bind on
50
+ # @return [Bunny::Queue] the queue
51
+ def bind_queue(config = QueueConfig.from_env, routing_key: default_routing_key)
52
+ queue(config).tap { |q| q.bind(exchange, routing_key:) }
53
+ end
54
+
55
+ # Creates or looks up the specified queue.
56
+ # @param config [QueueConfig] queue configuration
57
+ # @return [Bunny::Queue] the queue
58
+ def queue(config)
59
+ channel.queue(config.name, config.options)
60
+ end
61
+
62
+ # Returns the default (environment-variable-based) routing key
63
+ #
64
+ # | Variable | Sample value | Description |
65
+ # |---------------------------------|-------------------------------|----------------------|
66
+ # | `RABBITMQ_PLATFORM_ROUTING_KEY` | `surfliner.metadata.daylight` | RabbitMQ routing key |
67
+ #
68
+ # @return [String, nil] the configured default routing key
69
+ def default_routing_key
70
+ ENV.fetch("RABBITMQ_PLATFORM_ROUTING_KEY")
52
71
  end
53
72
 
54
73
  class << self
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: surfliner-metadata_consumer
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.1.0.pre.alpha.6
4
+ version: 0.1.0.pre.alpha.7
5
5
  platform: ruby
6
6
  authors:
7
7
  - Project Surfliner
@@ -295,6 +295,7 @@ files:
295
295
  - lib/surfliner/mq/connection.rb
296
296
  - lib/surfliner/mq/connection_config.rb
297
297
  - lib/surfliner/mq/queue_config.rb
298
+ - lib/surfliner/mq/router.rb
298
299
  - lib/surfliner/mq/topic.rb
299
300
  - lib/surfliner/mq/topic_config.rb
300
301
  - lib/surfliner/util.rb