Skip to content

transit

Shared HTTP & gRPC transport middleware for Go services — structured request logging, OpenTelemetry instrumentation, circuit breaking, rate limiting and client retry, from one framework-free module.

go get gitlab.com/phpboyscout/go/transit

gitlab.com/phpboyscout/go/transit gives a service's HTTP and gRPC edges a single, shared implementation of the cross-cutting transport concerns — the same logging, tracing, circuit-breaking and rate-limiting behaviour whether the traffic arrives over REST or gRPC, and whether the code is a server accepting calls or a client making them. It is the middleware layer extracted from go-tool-base.

Why

  • Framework-free. It carries the gRPC SDK and the OpenTelemetry gRPC/HTTP contrib instrumentation — that is the middleware's job — but nothing else. A depfootprint_test.go guard forbids go-tool-base, Viper/Cobra, Charm and the cloud SDKs; the remaining dependencies are golang.org/x/time/rate, go/redact and cockroachdb/errors.
  • *slog.Logger at the seam. Every middleware that logs takes a plain *slog.Logger, so nothing here pulls in a logging framework.
  • Server and client, both transports. http and grpc each provide server handlers/interceptors and client round-trippers/interceptors, so a service and the clients it calls share one implementation of each concern. See the middleware model.
  • Resilience is one package. The circuit breaker and the keyed token-bucket rate-limiter store live in resilience; the HTTP and gRPC layers wrap them into transport-shaped middleware.

Where next

  • Getting started — build a logged, traced, rate-limited server and a client that survives a flaky downstream, in about fifteen minutes.
  • Compose HTTP middleware — server chains and client round-trippers (retry, circuit breaker, auth).
  • Compose gRPC interceptors — server interceptor chains and client instrumentation.
  • The middleware model — chain ordering, client vs server, and why the breaker sits outside retry.
  • Reference — every config field, its default, and what happens when it is wrong.
  • API reference — full godoc on pkg.go.dev.

What transit does not do

Worth knowing before you build on it:

  • No distributed state. Every circuit breaker and rate limiter is per-process and in-memory. A limit of 50 rps across ten replicas admits 500.
  • No configuration loading. Constructors take Go structs; decoding a config file onto them is your service's job.
  • No *http.Client constructor. transit ships transports, not connection policy — TLS, redirects and timeouts belong to the layer above.
  • No gRPC retry. The gRPC SDK already has it, via a service config policy.
  • No metrics. Retries, rejections and breaker trips are not counted; callbacks are provided so you can count them.

The full list, with the reasoning for each, is in What transit does not do.


Part of the phpboyscout Go toolkit — small, framework-free Go modules extracted from go-tool-base.

Further reading

The blog carries a curated route through this subject: Building a web service in Go collects everything written about it, ordered so you can start at the beginning rather than newest-first.

Ask phpbotscout

phpbotscout

He answers questions about the projects over on the Discord, citing the docs where they already cover it, and offering to raise an issue where they don't. Bring a bug, an idea, or a questionable engineering decision.

Join the Discord