0.0
The project is in a healthy, maintained state
Ruby contract for the Service Mesh API Specification
2005
2006
2007
2008
2009
2010
2011
2012
2013
2014
2015
2016
2017
2018
2019
2020
2021
2022
2023
2024
2025
2026
 Dependencies
 Project Readme

service-mesh-ruby

This version implements the Service Mesh API Specification v0.4.0.

service-mesh-ruby is the Ruby contract for the Service Mesh API Specification. It is packaged as the gem service_mesh. It holds what every transport and every caller must agree on, and nothing that moves bytes. Transports are separate gems that depend on it and implement Client and Runtime.

Install

# Gemfile
gem "service_mesh"

Requires Ruby 3.3 or newer. The gem has no runtime dependencies.

What it Implements

  • The value types from the specification: ServiceMesh::Target, ServiceMesh::ServiceMap, ServiceMesh::Message, ServiceMesh::Endpoint, and ServiceMesh::Subscriber.
  • Target Kinds are implemented as :route and :topic. A Target built with a kind outside the two raises KindMismatch.
  • Message#payload is always Encoding::BINARY.
  • Target#same_channel? compares segments and kind and ignores metadata.
  • The configuration key the specification defines, DEPLOYMENT_GROUP_KEY, which is runtime configuration.
  • The consumer group is the consumer_group member of Endpoint and Subscriber, defaulting to nil. CONSUMER_GROUP_NONE is the value for no group.
  • The reserved metadata prefix RESERVED_PREFIX (Mesh-).
  • The metadata keys the specification defines: HANDLER_ERROR_KEY, TIMEOUT_KEY, DEADLINE_KEY, DELIVERY_ATTEMPT_KEY, and MESSAGE_ID_KEY.
  • The errors defined by the specification as ServiceMesh::Error: ServiceMesh::KindMismatch, ServiceMesh::InvalidTarget, and ServiceMesh::NoDeploymentGroup.
  • A conformance suite a transport runs against its own Client and Runtime.

Client and Runtime are duck types. The specification names their methods, and a transport satisfies the contract by responding to them and by passing the conformance suite.

Usage

A transport that implements Client and Runtime according to the specification uses the types defined here.

require "service_mesh"

TARGET = ServiceMesh::Target.new(segments: %w[accounts lookup], kind: :route)

def lookup(client, id)
  reply = client.request(ServiceMesh::Message.new(target: TARGET, payload: id))
  reply.payload
end

Conformance

A transport implemented to use these types should include the shared examples defined in this library in its own spec suite and supply its own constructors and a pair of valid targets:

require "service_mesh/rspec"

RSpec.describe MyTransport do
  it_behaves_like "a service mesh transport" do
    let(:new_runtime) do
      ->(client, config, endpoints:, subscribers:) { MyTransport::Runtime.new(client, config, endpoints:, subscribers:) }
    end
    let(:new_client) { ->(config, map) { MyTransport::Client.new(config, map) } }
    let(:runtime_config) { {"deployment_group" => "test", "url" => url} }
    let(:client_config) { {"url" => url} }
    let(:route_target) { ServiceMesh::Target.new(segments: %w[test echo], kind: :route) }
    let(:topic_target) { ServiceMesh::Target.new(segments: %w[test event], kind: :topic) }
  end
end

A transport that needs its own settings for the suite to pass supplies any of five optional lets, each defaulting to an empty Hash:

let(:target_metadata) { {...} }     # merged under the metadata of every Target the suite builds
let(:endpoint_metadata) { {...} }   # merged under the metadata of every Endpoint the suite builds
let(:subscriber_metadata) { {...} } # merged under the metadata of every Subscriber the suite builds
let(:request_options) { {...} }     # the options of every request the suite makes
let(:publish_options) { {...} }     # the options of every publish the suite makes

Metadata an example sets itself wins over target_metadata, endpoint_metadata, and subscriber_metadata.

The suite covers:

  • kind checks
  • the deployment group requirement
  • request and reply with metadata both ways
  • publish
  • the consumer-group delivery permutations across two runtimes
  • a standalone client refusing requests after close
  • the runtime's client being the one it was given and closed by stop
  • the lifecycle state machine
  • drain completing and expiring

Anything that names a transport's own errors, config keys, or address syntax stays in the transport's specs.

Development

mise install
just install
just check      # lint, test, build
just test       # tests only

Releasing is described in publishing.md. just bump patch, just bump minor, or just bump major raises the version in lib/service_mesh/version.rb and commits that file.