Documentation
¶
Overview ¶
Package transport defines the contract between the application lifecycle and the servers it runs, and the call-scoped view middleware gets of the transport underneath it.
Server is all the lifecycle requires: Start and Stop. Everything else is an optional capability discovered by type assertion — Endpointer for the address to publish to a registry, Healthzer for readiness, GracefulStopper for draining, ReplyHeaderer for a mutable reply header. A server that does not implement one makes no claim, and consumers must not require more than they need.
Transporter is what middleware sees: the transport Kind, the opaque Operation string, the endpoint, and the request header. It travels in the context — FromServerContext on the serving side, FromClientContext on the calling side. Kind is an open type: transports outside this module declare their own.
MarkNotSent and WasNotSent carry delivery evidence: a transport marks an error only when it can prove the request never left the process, which is what the retry middleware needs to retry safely without an idempotence declaration (see docs/design/retry.md).
The concrete transports live in the subpackages http, grpc, and message.
Index ¶
- func MarkNotSent(err error) error
- func NewClientContext(ctx context.Context, tr Transporter) context.Context
- func NewServerContext(ctx context.Context, tr Transporter) context.Context
- func WasNotSent(err error) bool
- type Endpointer
- type GracefulStopper
- type Header
- type Healthzer
- type Kind
- type ReplyHeaderer
- type Server
- type Transporter
Constants ¶
This section is empty.
Variables ¶
This section is empty.
Functions ¶
func MarkNotSent ¶
MarkNotSent records that the request reporting err was never written to the wire, making the failure safe to retry regardless of whether the operation is idempotent. It returns err unchanged when err is nil or already marked.
A transport MUST mark only what it can prove. "The connection never opened" and "no connection was available to write to" are proof; "the request was written and no response came back" is not — a server may have executed it and lost the reply. When a transport cannot tell the two apart, it leaves the error unmarked: the absence of the mark reads as "the request may have executed", which is the safe assumption.
func NewClientContext ¶
func NewClientContext(ctx context.Context, tr Transporter) context.Context
NewClientContext returns a new Context that carries value.
func NewServerContext ¶
func NewServerContext(ctx context.Context, tr Transporter) context.Context
NewServerContext returns a new Context that carries value.
func WasNotSent ¶
WasNotSent reports whether err carries the MarkNotSent evidence anywhere in its chain, meaning a transport proved the request never reached a server.
A false result is not proof of the opposite. It means no transport claimed the request was withheld — either because it was sent, or because the transport could not tell.
Types ¶
type Endpointer ¶
Endpointer is registry endpoint.
type GracefulStopper ¶
type GracefulStopper interface {
// GracefulStop stops accepting new work, waits for in-flight work to
// finish, and returns nil once the server has stopped. When ctx ends
// first, it abandons the wait and returns the context's error; the drain
// keeps running in the background, and the caller decides whether to
// force termination with Stop.
//
// Stop keeps its own contract — terminate within the bounds the context
// allows, by force if necessary. A lifecycle manager shutting down a
// server that implements GracefulStopper prefers it and falls back to
// Stop when the drain is abandoned or fails.
GracefulStop(context.Context) error
}
GracefulStopper is implemented by servers that can drain in-flight work before stopping. It is an optional capability alongside Server: consumers type-assert for it.
type Header ¶
type Header interface {
Get(key string) string
Set(key string, value string)
Add(key string, value string)
Keys() []string
Values(key string) []string
}
Header is the storage medium used by a Header.
type Healthzer ¶
type Healthzer interface {
// Healthz reports readiness, not liveness: whether the server can accept
// new work right now. It is false before the server starts accepting
// traffic, true while it accepts, and false again as soon as shutdown or
// draining begins — before the listener actually closes. Liveness — is
// the process running at all — is expressed by the process itself and
// needs no method.
//
// Healthz must be safe to call concurrently with the server lifecycle
// and must not block.
Healthz() bool
}
Healthzer is implemented by servers that can report whether they are ready to accept new work. Like Endpointer and ReplyHeaderer it is an optional capability: consumers type-assert for it, and a Server that does not implement it makes no readiness claim.
type Kind ¶
type Kind string
Kind defines the type of Transport. It is an open type: a transport outside this module may declare its own constant rather than extending the set below.
type ReplyHeaderer ¶
type ReplyHeaderer interface {
// ReplyHeader returns the transport reply header. Only valid for a server
// transport.
// http: http.Header
// grpc: metadata.MD
ReplyHeader() Header
}
ReplyHeaderer is implemented by transports that expose a mutable reply header. Request/response transports do; message and stream transports need not. Consumers type-assert for it.
type Transporter ¶
type Transporter interface {
// Kind returns the transport kind, such as KindHTTP or KindGRPC. The set
// is open: a transport outside this module may declare its own Kind.
Kind() Kind
// Endpoint returns the server or client endpoint.
// Server Transport: grpc://127.0.0.1:9000
// Client Transport: discovery:///provider-demo
Endpoint() string
// Operation identifies the call in flight. The format belongs to the
// transport: gRPC reports the protobuf method selector
// (/helloworld.Greeter/SayHello), a message transport reports the
// destination (orders.created), a JSON-RPC transport reports the method
// name.
//
// Callers MUST treat the value as opaque and MUST NOT parse it. It is
// meant for labeling and keying — span names, rate-limit dimensions,
// selector matching, log fields. Dispatch on Kind and read the concrete
// transport type when structure is required.
Operation() string
// RequestHeader returns the transport request header.
// http: http.Header
// grpc: metadata.MD
RequestHeader() Header
}
Transporter carries what middleware needs to know about the call in flight.
Its methods describe what every transport has, not the shape of a request/response exchange. A transport that has no meaningful reply header — a message queue, a bidirectional stream — implements this interface and, if it does expose one, ReplyHeaderer as well.
func FromClientContext ¶
func FromClientContext(ctx context.Context) (tr Transporter, ok bool)
FromClientContext returns the Transport value stored in ctx, if any.
func FromServerContext ¶
func FromServerContext(ctx context.Context) (tr Transporter, ok bool)
FromServerContext returns the Transport value stored in ctx, if any.
Directories
¶
| Path | Synopsis |
|---|---|
|
Package grpc provides Forge's gRPC transport: a server wrapping google.golang.org/grpc with Forge's lifecycle and middleware contracts, and a client constructor that wires the same contracts into a *grpc.ClientConn.
|
Package grpc provides Forge's gRPC transport: a server wrapping google.golang.org/grpc with Forge's lifecycle and middleware contracts, and a client constructor that wires the same contracts into a *grpc.ClientConn. |
|
Package http provides Forge's HTTP transport: a server that generated service code registers routes on, and a client that generated code calls through.
|
Package http provides Forge's HTTP transport: a server that generated service code registers routes on, and a client that generated code calls through. |
|
healthz
Package healthz serves a readiness probe over HTTP for anything that implements transport.Healthzer — one server, or an App aggregating all of its servers.
|
Package healthz serves a readiness probe over HTTP for anything that implements transport.Healthzer — one server, or an App aggregating all of its servers. |
|
transcoding
Package transcoding carries the Protobuf half of Forge's HTTP transport: Google HTTP transcoding, ProtoJSON projection, path and query binding, raw HTTP bodies, and stream body fields.
|
Package transcoding carries the Protobuf half of Forge's HTTP transport: Google HTTP transcoding, ProtoJSON projection, path and query binding, raw HTTP bodies, and stream body fields. |
|
Package message defines the protocol-neutral contract for asynchronous message transports.
|
Package message defines the protocol-neutral contract for asynchronous message transports. |