Skip to content

About

Ruby contract for the Service Mesh API Specification

Resources

Stars

0 stars

Watchers

0 watching

Forks

Repository files navigation

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.

About

Ruby contract for the Service Mesh API Specification

Resources

Stars

0 stars

Watchers

0 watching

Forks

Releases

Packages

Used by

Contributors

Languages