cmd-stream-go allows execution of Commands on the server using the Command pattern.
It provides an extremely fast and flexible communication mechanism.
ymz-ncnk.medium.com/command-pattern-as-an-api-architecture-style-be9ac25d6d94
- Can work 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 (client streaming is not directly supported, but can also be implemented).
- Supports deadlines for sending Commands and Results.
- Supports timeouts.
- Supports reconnect feature.
- Supports keepalive feature.
- Can work with various serialization formats (here is an example using the Protobuf serializer).
- Has a modular architecture.
- cmd-stream-go
- Why cmd-stream-go?
- Command Pattern as an API Architecture Style
- Brief cmd-stream-go Description
- Contents
- Tests
- Benchmarks
- High-performance Communication Channel
- cmd-stream-go and RPC
- Network Protocols Support
- Client
- Server
- How To Use
- Architecture
The cmd-stream-go module includes only a few integration tests, while each submodule (see the Architecture section) has approximately 90% test coverage.
github.com/ymz-ncnk/go-client-server-communication-benchmarks
To build a high-performance communication channel between two services:
- Use N connections. Several connections can transfer significantly more data than a single one. The number N, depends on your system and represents the point after which adding more connections will not provide additional benefits.
- To minimize system latency, use all available connections from the start instead of creating new ones on demand.
- Use keepalive connections.
If you are already using RPC, cmd-stream-go can boost its performance by providing a faster communication tool. Here's an example.
cmd-stream-go is built on top of the standard Golang net package, and supports connection-oriented protocols like TCP, TLS or mutual TLS (for client authentication).
The client is asynchronous and can be used from different goroutines simultaneously. It uses only one connection to send Commands and receive Results. Commands sent from a single goroutine will be delivered to the server in order.
The client may lose connection to the server in the following cases:
- While sending a Command – Client.Send() will return an error.
- While waiting for a Result – whether the Command was executed on the server remains unknown.
In both cases, if the client.NewReconnect()
constructor is used, we can try to
resend the Command (idempotent Command) after a while. If the client has already
successfully reconnected, normal operation will continue, otherwise
Client.Send()
will return an error again.
An example of using the "reconnect" client can be found here.
The server initializes the connection to the client by sending ServerInfo
.
Using which, the client can determine its compatibility with the server, for
instance, whether they both support the same set of Commands.
A few words about Command execution:
- Each Command is executed by a single
Invoker
(it should be thread-safe) in a separete goroutine. - A Command can send multiple Results, all of which will be delivered to the client in order. See this example.
Server.Close()
terminates all connections and immediately stops the server.
Server.Shutdown()
allows the server to complete processing of already
established connections without accepting new ones.
There are the following cmd-stream-go submodules:
- base-go: Basic module, that contains the 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 execute Commands.
- transport-go: Resposible for Commands/Results delivery.
cmd-stream-go was designed in such a way that you can easily replace any part of it.