# README
kitty
go get github.com/objenious/kitty
Kitty is a slightly opinionated framework based on go-kit. It's goal is to ease development of microservices deployed on Kubernetes (or any similar orchestration platform).
Kitty has an opinion on:
- transports: HTTP only (additional transports can be added as long as they implement kitty.Transport, a Google Pub/Sub transport is available as a separate package),
- errors: an error may be Retryable (e.g. 5XX status codes) or not (e.g. 4XX status codes),
- status codes: unless specified, request decoding errors will generate 400 HTTP status codes.
Kitty has no opinion on:
- logging: no logs are generated by default, you can plug your logger and it will get additional context,
- packages: kitty only imports go-kit and the standard library,
- routers: you can use any router (a Gorilla Mux implementation is available in a sub-package, other routers can easily be plugged),
- encoding: use whatever encoding you want (JSON, messagepack, protobuf, ...),
- monitoring, metrics and tracing: use Istio, a sidecar process or a middleware.
Kitty includes 2 sub-packages:
- backoff: Retryable-aware exponential backoff (only Retryable errors trigger retries),
- circuitbreaker: Retryable-aware circuit breaker (only Retryable errors trigger the circuit breaker).
Example
Server-side
t := kitty.NewHTTPTransport(kitty.Config{HTTPPort: 8081}).
Router(gorilla.Router()).
Endpoint("POST", "/foo", Foo, kitty.Decoder(decodeFooRequest)).
Endpoint("GET", "/bar", Bar)
kitty.NewServer(t).Run(ctx)
// Foo is a go-kit Endpoint
func Foo(ctx context.Context, request interface{}) (interface{}, error) {
fr := request.(fooRequest)
return fooResponse{Message: fmt.Sprintf("Good morning %s !", fr.Name)}, nil
}
// decodeFooRequest
func decodeFooRequest(ctx context.Context, r *http.Request) (interface{}, error) {
var request fooRequest
if err := json.NewDecoder(r.Body).Decode(&request); err != nil {
return nil, err
}
return request, nil
}
Client-side (with circuit breaker & exponential backoff)
u, err := url.Parse("http://example.com/foo")
e := kitty.NewClient(
"POST",
u,
kithttp.EncodeJSONRequest,
decodeFooResponse
).Endpoint()
cb := gobreaker.NewCircuitBreaker(gobreaker.Settings{Name: "foo"})
e = kittycircuitbreaker.NewCircuitBreaker(cb)(e)
bo := backoff.NewExponentialBackOff()
e = kittybackoff.NewBackoff(bo)(e)
How-to
Log requests
kitty.NewServer(t).
// Log as JSON
Logger(log.NewJSONLogger(log.NewSyncWriter(os.Stdout))).
// Add path and method to all log lines
LogContext("http-path", "http-method").
// Log request only if an error occurred
Middlewares(kitty.LogEndpoint(kitty.LogErrors))
Integrate with Istio
TBD
Integrate liveness/readiness checks
Using github.com/heptiolabs/healthcheck:
health := healthcheck.NewHandler()
health.AddLivenessCheck("goroutine-threshold", healthcheck.GoroutineCountCheck(100))
health.AddReadinessCheck("database", healthcheck.DatabasePingCheck(db, 1*time.Second))
t := kitty.NewTransport(kitty.Config{}).Liveness(health.LiveEndpoint).Readiness(health.ReadyEndpoint)
Use Google Pub/Sub as a transport
https://github.com/objenious/kitty-gcp adds a Google Pub/Sub transport to kitty:
import "github.com/objenious/kitty-gcp/pubsub"
tr := pubsub.NewTransport(ctx, "project-id").
Endpoint(subscriptionName, endpoint, Decoder(decodeFunc))
err := kitty.NewServer(tr).Run(ctx)
Requirements
Go > 1.11
Contribution guidelines
Contributions are welcome, as long as :
- unit tests & comments are included,
- no external package is added to the top-level package (implementations can be added as sub-packages).
Thanks
kitty is heavily inspired by gizmo/kit (https://godoc.org/github.com/NYTimes/gizmo/server/kit), with a different approach to server setup and without the gRPC clutter.
License
MIT - See LICENSE file
# Packages
No description provided by the author
No description provided by the author
No description provided by the author
# Functions
Decoder defines the request decoder for a HTTP endpoint.
Encoder defines the response encoder for a HTTP endpoint.
HTTPError builds an error based on a http.Response.
IsRetryable checks if an error is retryable (i.e.
LogEndpoint creates a middleware that logs Endpoint calls.
Logger will return the logger that has been injected into the context by the kitty server.
LogMessage will log a message.
NewClient creates a kitty client.
NewClientWithError creates a kitty client that doesn't deal with HTTP errors.
NewHTTPTransport creates a new HTTP transport, based on the specified config.
NewServer creates a kitty server.
NotFoundHandler will set the not found handler of the router.
Retryable defines an error as retryable.
ServerOptions defines a liste of go-kit ServerOption to be used by a HTTP endpoint.
StdlibRouter returns a Router based on the stdlib http package.
# Constants
LogErrors logs the request in case of an error.
LogRequest logs the request.
LogResponse logs the response.
# Variables
DefaultConfig defines the default config of kitty.HTTPTransport.
# Structs
Client is a wrapper above the go-kit http client.
Config holds configuration info for kitty.HTTPTransport.
HTTPTransport defines a HTTP transport for a kitty Server.
Server defines a kitty server.
# Interfaces
Retryabler defines an error that may be temporary.
Router is an interface for router implementations.
Transport is the interface all transports must implement.
# Type aliases
HTTPEndpointOption is an option for an HTTP endpoint.
LogOption is a LogEndpoint middleware option.
RouterOption sets optional Router options.