service_mesh 0.6.0 → 0.7.0

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: 643fe078e4376b1f4d19e3e45e0dbbe7e8b61e620e96591f67c7b0ed18865a50
4
- data.tar.gz: 57c88b02dd056895234d1536b16f00973202cdec9b6600f7ab31621452e52d93
3
+ metadata.gz: 966f879206d92063d0a9fb94576db740746b6809e629548df3cad531547b543f
4
+ data.tar.gz: 0e411f07db7f14c1fd9e7bbe483a8d44d75c8bc13df6b111eb4ffdd8b0377d7e
5
5
  SHA512:
6
- metadata.gz: 56f15b80a1db1ad69e0e95105e8ed221b873b4ae762ff85296e576ad7cb1625b22209d5bf13aad4e85b903a2144b08bd9f6bdfef0169b49860f6c3350ebcdc4d
7
- data.tar.gz: 7be31a262f4c7cf55b5a2f7661c69baf7922e2261a5924a59537bbb3e0c0c3141eb0247977aca65941ed033a5eeb6dd66f5a900978e980d4a28d66cff6cc3aff
6
+ metadata.gz: 9590a21777d4afacd500e6e294042a44ad31581a8688d32119e51d547e4c4917ecb7e5149b834862785971a8942e071f406ab590eb65aa3c81f1c9859f6e7a21
7
+ data.tar.gz: 374757753729d92f5e20930aaef9739676f600a75eb6d9fbdfecf3194590e03c29c9c9f11a0d748105b645b9fdf94438412c276083a13716a321ec732faa166f
data/README.md CHANGED
@@ -1,5 +1,7 @@
1
1
  # service-mesh-ruby
2
2
 
3
+ This version implements the Service Mesh API Specification v0.4.0.
4
+
3
5
  service-mesh-ruby is the Ruby contract for the
4
6
  [Service Mesh API Specification](https://github.com/Paymentbox-com/service-mesh-api).
5
7
  It is packaged as the gem `service_mesh`. It holds what every transport and every
@@ -23,9 +25,10 @@ Requires Ruby 3.3 or newer. The gem has no runtime dependencies.
23
25
  raises `KindMismatch`.
24
26
  - `Message#payload` is always `Encoding::BINARY`.
25
27
  - `Target#same_channel?` compares segments and kind and ignores metadata.
26
- - The configuration keys the specification defines. `DEPLOYMENT_GROUP_KEY` is runtime
27
- configuration. `CONSUMER_GROUP_KEY`, with the value `CONSUMER_GROUP_NONE`, is `Endpoint` and
28
- `Subscriber` metadata.
28
+ - The configuration key the specification defines, `DEPLOYMENT_GROUP_KEY`, which is runtime
29
+ configuration.
30
+ - The consumer group is the `consumer_group` member of `Endpoint` and `Subscriber`, defaulting to
31
+ `nil`. `CONSUMER_GROUP_NONE` is the value for no group.
29
32
  - The reserved metadata prefix `RESERVED_PREFIX` (`Mesh-`).
30
33
  - The metadata keys the specification defines: `HANDLER_ERROR_KEY`, `TIMEOUT_KEY`, `DEADLINE_KEY`,
31
34
  `DELIVERY_ATTEMPT_KEY`, and `MESSAGE_ID_KEY`.
@@ -77,16 +80,18 @@ end
77
80
  ```
78
81
 
79
82
  A transport that needs its own settings for the suite to pass supplies any of
80
- four optional lets, each defaulting to an empty Hash:
83
+ five optional lets, each defaulting to an empty Hash:
81
84
 
82
85
  ```ruby
86
+ let(:target_metadata) { {...} } # merged under the metadata of every Target the suite builds
83
87
  let(:endpoint_metadata) { {...} } # merged under the metadata of every Endpoint the suite builds
84
88
  let(:subscriber_metadata) { {...} } # merged under the metadata of every Subscriber the suite builds
85
89
  let(:request_options) { {...} } # the options of every request the suite makes
86
90
  let(:publish_options) { {...} } # the options of every publish the suite makes
87
91
  ```
88
92
 
89
- Metadata an example sets itself wins over `endpoint_metadata` and `subscriber_metadata`.
93
+ Metadata an example sets itself wins over `target_metadata`, `endpoint_metadata`, and
94
+ `subscriber_metadata`.
90
95
 
91
96
  The suite covers:
92
97
 
@@ -18,6 +18,7 @@ require_relative "../service_mesh"
18
18
  # let(:topic_target) { ServiceMesh::Target.new(segments: %w[test event], kind: :topic) }
19
19
  #
20
20
  # # Optional, each defaulting to an empty Hash.
21
+ # let(:target_metadata) { {...} } # merged under the metadata of each Target the suite builds
21
22
  # let(:endpoint_metadata) { {...} } # merged under each Endpoint's metadata
22
23
  # let(:subscriber_metadata) { {...} } # merged under each Subscriber's metadata
23
24
  # let(:request_options) { {...} } # options for every request
@@ -31,17 +32,22 @@ require_relative "../service_mesh"
31
32
  RSpec.shared_examples "a service mesh transport" do
32
33
  let(:service_map) { ServiceMesh::ServiceMap.new }
33
34
  let(:wait) { 3 }
35
+ let(:target_metadata) { {} }
34
36
  let(:endpoint_metadata) { {} }
35
37
  let(:subscriber_metadata) { {} }
36
38
  let(:request_options) { {} }
37
39
  let(:publish_options) { {} }
38
40
 
41
+ def target(segments, kind, metadata: {})
42
+ ServiceMesh::Target.new(segments: segments, kind: kind, metadata: target_metadata.merge(metadata))
43
+ end
44
+
39
45
  def endpoint(target, handler, metadata: {})
40
46
  ServiceMesh::Endpoint.new(target: target, handler: handler, metadata: endpoint_metadata.merge(metadata))
41
47
  end
42
48
 
43
- def subscriber(target, handler, metadata: {})
44
- ServiceMesh::Subscriber.new(target: target, handler: handler, metadata: subscriber_metadata.merge(metadata))
49
+ def subscriber(target, handler, consumer_group: nil, metadata: {})
50
+ ServiceMesh::Subscriber.new(target: target, handler: handler, consumer_group: consumer_group, metadata: subscriber_metadata.merge(metadata))
45
51
  end
46
52
 
47
53
  def request(msg, via: client)
@@ -156,19 +162,19 @@ RSpec.shared_examples "a service mesh transport" do
156
162
  end
157
163
 
158
164
  describe "consumer groups" do
159
- none = {ServiceMesh::CONSUMER_GROUP_KEY => ServiceMesh::CONSUMER_GROUP_NONE}
160
- shared = {ServiceMesh::CONSUMER_GROUP_KEY => "order-consumers"}
165
+ none = ServiceMesh::CONSUMER_GROUP_NONE
166
+ shared = "order-consumers"
161
167
 
162
168
  [
163
- ["same deployment, key absent: one instance handles it", %w[billing billing], [{}, {}], 1],
164
- ["different deployments, key absent: each deployment handles it", %w[billing audit], [{}, {}], 2],
169
+ ["same deployment, group unset: one instance handles it", %w[billing billing], [nil, nil], 1],
170
+ ["different deployments, group unset: each deployment handles it", %w[billing audit], [nil, nil], 2],
165
171
  ["same deployment, none: every instance handles it", %w[billing billing], [none, none], 2],
166
172
  ["different deployments, shared named group: one instance handles it", %w[billing audit], [shared, shared], 1]
167
- ].each do |name, groups, metadata, want|
173
+ ].each do |name, groups, consumer_groups, want|
168
174
  it name do
169
175
  count = Queue.new
170
176
  2.times do |i|
171
- serve(config_for(groups[i]), subscribers: [subscriber(topic_target, ->(_) { count << true }, metadata: metadata[i])])
177
+ serve(config_for(groups[i]), subscribers: [subscriber(topic_target, ->(_) { count << true }, consumer_group: consumer_groups[i])])
172
178
  end
173
179
 
174
180
  publish(message(topic_target))
@@ -182,7 +188,7 @@ RSpec.shared_examples "a service mesh transport" do
182
188
  it "ignores a group set on the target, which carries none" do
183
189
  count = Queue.new
184
190
  %w[a b].each do |group|
185
- t = ServiceMesh::Target.new(segments: topic_target.segments, kind: :topic, metadata: {ServiceMesh::CONSUMER_GROUP_KEY => group})
191
+ t = target(topic_target.segments, :topic, metadata: {"consumer_group" => group})
186
192
  serve(config_for("same"), subscribers: [subscriber(t, ->(_) { count << true })])
187
193
  end
188
194
 
@@ -3,13 +3,12 @@
3
3
  module ServiceMesh
4
4
  KINDS = %i[route topic].freeze
5
5
 
6
- # Configuration keys the specification defines. Everything else belongs to
7
- # a transport. DEPLOYMENT_GROUP_KEY is runtime configuration, and nothing
8
- # else carries it. CONSUMER_GROUP_KEY is Endpoint and Subscriber metadata;
9
- # when it is unset or empty, the runtime's deployment group applies, and
10
- # CONSUMER_GROUP_NONE means no group. A Target carries neither.
6
+ # The configuration key the specification defines. Everything else belongs
7
+ # to a transport. DEPLOYMENT_GROUP_KEY is runtime configuration, and nothing
8
+ # else carries it.
11
9
  DEPLOYMENT_GROUP_KEY = "deployment_group"
12
- CONSUMER_GROUP_KEY = "consumer_group"
10
+
11
+ # The Endpoint and Subscriber consumer_group value that requests no group.
13
12
  CONSUMER_GROUP_NONE = "none"
14
13
 
15
14
  # Metadata keys that start with RESERVED_PREFIX belong to transports and
@@ -43,6 +42,13 @@ module ServiceMesh
43
42
 
44
43
  # Identifies a receiving channel on the mesh. A transport assembles the
45
44
  # segments into its own address; that string never leaves the transport.
45
+ # Metadata holds addressing and the default transport settings for the
46
+ # target, and never a deployment group or consumer group.
47
+ #
48
+ # A transport reads each of its settings from the first of these that has a
49
+ # value: the per-call options of request or publish, the Endpoint's or
50
+ # Subscriber's metadata, the Target's metadata, and the transport's own
51
+ # default.
46
52
  Target = Data.define(:segments, :kind, :metadata) do
47
53
  def initialize(segments:, kind:, metadata: {})
48
54
  raise KindMismatch, "kind must be one of #{KINDS.inspect}, got #{kind.inspect}" unless KINDS.include?(kind)
@@ -73,16 +79,26 @@ module ServiceMesh
73
79
  end
74
80
 
75
81
  # A route target paired with a handler that returns a Message.
76
- Endpoint = Data.define(:target, :metadata, :handler) do
77
- def initialize(target:, handler:, metadata: {})
78
- super(target: target, metadata: metadata.to_h.freeze, handler: handler)
82
+ #
83
+ # consumer_group names the logical group the endpoint joins. When it is nil
84
+ # or empty, the runtime's deployment group applies. CONSUMER_GROUP_NONE means
85
+ # no group, so every instance handles every message. Any other value names
86
+ # the group, and one handler in that group handles each message.
87
+ #
88
+ # Metadata holds transport settings for the endpoint, which override the
89
+ # target's.
90
+ Endpoint = Data.define(:target, :consumer_group, :metadata, :handler) do
91
+ def initialize(target:, handler:, consumer_group: nil, metadata: {})
92
+ super(target: target, consumer_group: consumer_group, metadata: metadata.to_h.freeze, handler: handler)
79
93
  end
80
94
  end
81
95
 
82
96
  # A topic target paired with a handler whose return value is ignored.
83
- Subscriber = Data.define(:target, :metadata, :handler) do
84
- def initialize(target:, handler:, metadata: {})
85
- super(target: target, metadata: metadata.to_h.freeze, handler: handler)
97
+ # consumer_group has the same meaning as on Endpoint. Metadata holds
98
+ # transport settings for the subscriber, which override the target's.
99
+ Subscriber = Data.define(:target, :consumer_group, :metadata, :handler) do
100
+ def initialize(target:, handler:, consumer_group: nil, metadata: {})
101
+ super(target: target, consumer_group: consumer_group, metadata: metadata.to_h.freeze, handler: handler)
86
102
  end
87
103
  end
88
104
  end
@@ -1,5 +1,5 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module ServiceMesh
4
- VERSION = "0.6.0"
4
+ VERSION = "0.7.0"
5
5
  end
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: service_mesh
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.6.0
4
+ version: 0.7.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Bryant Morrill