Skip to content

High-performance client-server library for Go, built around the Command pattern

License

Notifications You must be signed in to change notification settings

cmd-stream/cmd-stream-go

Folders and files

NameName
Last commit message
Last commit date

Latest commit

 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 

Repository files navigation

cmd-stream-go

Go Reference GoReportCard Follow on X

cmd-stream-go is a high-performance, modular client–server library for Go, based on the Command Pattern. It's designed for efficient, low-latency communication over TCP/TLS, with support for streaming and observability.

In short, the concept is simple: a client sends Commands to the server, where an Invoker executes them, and a Receiver provides the actual server-side functionality.

Want to learn more about how the Command Pattern applies to network communication? Check out this series of posts.

Contents

Why cmd-stream-go?

It delivers high-performance and resource efficiency, helping reduce infrastructure costs and scale more effectively.

Overview

  • Works over TCP, TLS or mutual TLS.
  • Has an asynchronous client that uses only one connection for both sending Commands and receiving Results.
  • Supports the server streaming, i.e. a Command can send back multiple Results.
  • Provides reconnect and keepalive features.
  • Supports the Circuit Breaker pattern.
  • Has OpenTelemetry integration.
  • Can work with various serialization formats.
  • Follows a modular design.

Tests

The main cmd-stream-go module contains basic integration tests, while each submodule (see Architecture) has approximately 90% code coverage.

Benchmarks

QPS Benchmark

See go-client-server-benchmarks for detailed performance comparisons.

How To

Getting started is easy:

  1. Implement the Command Pattern.
  2. Use one of the codecs:

Tip: Start with JSON for simplicity, and switch to MUS later for maximum performance.

Quick Look

Here's a minimal end-to-end example showing how Commands can be defined, sent, and executed over the network:

// Calc represents the Receiver (application layer).
// A struct is used instead of an interface for brevity.
type Calc struct{}
func (c Calc) Add(a, b int) int { return a + b }
func (c Calc) Sub(a, b int) int { return a - b }

// AddCmd is a Command that uses Calc to perform addition.
type AddCmd struct {A, B int}
func (c AddCmd) Exec(ctx context.Context, seq core.Seq, at time.Time,
  calc Calc, proxy core.Proxy,
) (err error) {
  result := CalcResult(calc.Add(c.A, c.B))
  _, err = proxy.Send(seq, result) // send result back
  return
}

// SubCmd is a Command that uses Calc to perform subtraction.
type SubCmd struct {A, B int}
func (c SubCmd) Exec(ctx context.Context, seq core.Seq, at time.Time,
  calc Calc, proxy core.Proxy,
) (err error) {
  result := CalcResult(calc.Sub(c.A, c.B))
  _, err = proxy.Send(seq, result)  // send result back
  return
}

// CalcResult is the Result returned by Commands.
type CalcResult int
func (r CalcResult) LastOne() bool { return true }

func main() {
  const addr = "127.0.0.1:9000"
  var (
    invoker     = srv.NewInvoker(Calc{})
    cmdTypes = []reflect.Type{
      reflect.TypeFor[AddCmd](),
      reflect.TypeFor[SubCmd](),
    }
    resultTypes = []reflect.Type{
      reflect.TypeFor[CalcResult](),
    }
    serverCodec = codecjson.NewServerCodec[Calc](cmdTypes, resultTypes)
    clientCodec = codecjson.NewClientCodec[Calc](cmdTypes, resultTypes)
  )
  // Start server.
  go func() {
    server := cmdstream.MakeServer(serverCodec, invoker)
    server.ListenAndServe(addr)
  }()
  // Make sender.
  sender, _ := sndr.Make(addr, clientCodec)

  // Send AddCmd.
  sum, _ := sender.Send(context.Background(), AddCmd{A: 2, B: 3})
  fmt.Println(sum) // Output: 5
  // Send SubCmd.
  diff, _ := sender.Send(context.Background(), SubCmd{A: 8, B: 4})
  fmt.Println(diff) // Output: 4
}

The full, runnable example is available in the calc_json.

For further learning, see the resources below.

Additional Resources

Network Protocols Support

Built on Go’s standard net package, cmd-stream-go supports connection-oriented protocols, such as TCP, TLS, and mutual TLS (for client authentication).

High-performance Communication Channel

To maximize performance between services:

  1. Use N parallel connections. More connections typically improve throughput, until a saturation point.
  2. Pre-establish all connections instead of opening them on-demand.
  3. Keep connections alive to avoid the overhead from reconnections.

These practices, implemented via the ClientGroup, can significantly enhance throughput and reduce latency between your services.

cmd-stream-go and RPC

Already using RPC? You can use cmd-stream-go as a faster transport layer. See the RPC example.

Architecture

cmd-stream-go is split into the following submodules:

  • core-go: The core module that includes client and server definitions.
  • delegate-go: The client delegates all communication-related tasks to its delegate, the server follows the same approach. The connection is also initialized at this level.
  • handler-go: The server delegate uses a handler to receive and process Commands.
  • transport-go: Responsible for Commands/Results delivery.
  • testkit-go: Mocks and test utilities.

cmd-stream-go was designed in such a way that you can easily replace any part of it.

About

High-performance client-server library for Go, built around the Command pattern

Resources

License

Stars

Watchers

Forks

Sponsor this project

Packages

No packages published

Languages