Orion Microservices Framework

repository·master·Indexed 41 days ago

https://github.com/carousell/orion

A lightweight microservices framework written in Go, built around gRPC and Protobuf. Orion accelerates development with sensible defaults including Zipkin tracing, Hystrix circuit breaking, and live configuration reloading. It features a custom protoc plugin for code generation, automatic gRPC-to-HTTP exposure, and a comprehensive set of interceptors for logging, New Relic integration, and panic recovery.

Tokens
13.4K
Snippets
67
Records
82
Agent score
95%

What's inside Orion

  1. Overview of Orion framework

    master

    Orion is a lightweight microservices framework built around gRPC. It aims to reduce the time required to build microservices by providing sensible defaults for common infrastructure concerns. It uses Protocol Buffers as the source of truth for service contracts, enabling both gRPC and HTTP communication from a single service implementation.

    Key features included by default:

    • Resiliency: Hystrix
    • Observability: Zipkin (tracing), Prometheus (metrics), NewRelic, and Pprof
    • Configuration: Viper-based configuration with live reload support
  2. Manage request and response headers via context using the headers package

    master

    The github.com/carousell/Orion/utils/headers package provides utility functions to store and retrieve HTTP request and response headers within a context.Context. This allows you to pass header information through different layers of your application without explicitly passing header maps.

    Key Functions

    Request Headers

    • AddToRequestHeaders(ctx context.Context, key string, value string) context.Context: Adds a specific key-value pair to the request headers stored in the context. Returns a new context containing the updated headers.
    • RequestHeadersFromContext(ctx context.Context) http.Header: Retrieves all request headers currently stored in the provided context.

    Response Headers

    • AddToResponseHeaders(ctx context.Context, key string, value string) context.Context: Adds a specific key-value pair to the response headers stored in the context. Returns a new context containing the updated headers.
    • ResponseHeadersFromContext(ctx context.Context) http.Header: Retrieves all response headers currently stored in the provided context.
    import "github.com/carousell/Orion/utils/headers"
  3. Use Orion modifiers to control request behavior

    master

    The modifiers package provides functions that can be used to modify the behavior of a request context within Orion. These modifiers allow you to control serialization formats, error reporting, and identify the underlying transport protocol (HTTP vs gRPC).

    import "github.com/carousell/Orion/orion/modifiers"
  4. Implement a custom Orion Server using DefaultServerImpl

    master

    If you are building a custom orion.Server, you can embed DefaultServerImpl to inherit a standard implementation of the server lifecycle and registration methods.

    Commonly used methods on *DefaultServerImpl include:

    • Start(): Starts the Orion server.
    • Stop(timeout time.Duration): Stops the server gracefully.
    • Wait(): Waits for all serving servers to quit.
    • GetOrionConfig(): Returns the current (read-only) Config.
    • AddMiddleware(serviceName, method string, middlewares ...string): Adds middlewares to a specific service/method.
    • AddOption(serviceName, method, option string): Adds an option to a specific service/method.
    type DefaultServerImpl struct {
        // contains filtered or unexported fields
    }
  5. Use Contextual Logs for request tracing

    master

    The log package uses context.Context to pass additional information to logs. You can use loggers.AddToLogContext to attach metadata to a context. This metadata (such as method, path, grpcMethod, or transport) is automatically added to all log calls made within that service context, making debugging and request tracing much easier.

    Orion also generates a trace ID per request, which can be used to trace an entire request path through the logs.

  6. Use the options package to pass request metadata

    master

    The options package provides a mechanism to pass request-scoped metadata (options) from Orion to a server using Go's context.Context. The core abstraction is the Options type, which is a map[string]interface{} containing key-value pairs.

    import "github.com/carousell/Orion/utils/options"
  7. How Orion manages service lifecycle with ServiceFactory

    master

    Orion manages the lifecycle of your service using the orion.ServiceFactory interface. This is particularly useful for handling configuration reloads: when a config reloads, Orion initializes a new service instance and disposes of the old one.

    To implement this, you must provide a factory that implements two methods:

    1. NewService(orion.Server) interface{}: Called when a new service instance is initialized.
    2. DisposeService(svc interface{}): Called when a service instance is being disposed (e.g., during a config reload).
    package service
    
    import "github.com/carousell/Orion/orion"
    
    type svcFactory struct{}
    
    func (s *svcFactory) NewService(orion.Server) interface{} {
    	return &svc{}
    }
    
    func (s *svcFactory) DisposeService(svc interface{}) {
    	// do nothing
    }
    
    func GetFactory() orion.ServiceFactory {
    	return &svcFactory{}
    }
  8. How to use Orion: Service Definition and Code Generation

    master

    Orion follows a contract-first approach using Protocol Buffers.

    1. Define your service in a .proto file. For example:
    syntax = "proto3";
    
    package simple_proto;
    
    service SimpleService{
        rpc Echo (EchoRequest) returns (EchoResponse){}
    }
    
    message EchoRequest {
        string msg = 1;
    }
    
    message EchoResponse {
        string msg = 1;
    }
    1. Generate code using protoc with the grpc and orion plugins. This generates the standard gRPC files (.pb.go) and the Orion-specific registration files (.proto.orion.pb.go).

    2. Implement the interface: Once code is generated, you implement the server interface provided by gRPC. Orion then uses this implementation to handle both gRPC and HTTP calls.

    protoc -I . simple.proto --go_out=plugins=grpc:. --orion_out=.
  9. Use default interceptors for Orion clients and servers

    master

    Orion provides sets of pre-configured interceptors to simplify the setup of gRPC clients and servers.

    For Clients, use DefaultClientInterceptors(address string) to get a slice of grpc.UnaryClientInterceptor that should be applied to all client calls. Alternatively, DefaultClientInterceptor(address string) provides a single interceptor.

    For Servers, use DefaultInterceptors() to get a slice of grpc.UnaryServerInterceptor applied to all Orion methods, and DefaultStreamInterceptors() for stream RPCs.

    // For clients
    interceptors := interceptors.DefaultClientInterceptors("your-service-address")
    
    // For unary servers
    serverInterceptors := interceptors.DefaultInterceptors()
    
    // For stream servers
    streamInterceptors := interceptors.DefaultStreamInterceptors()
  10. Generate Orion service code from Protobuf

    master

    Orion uses a custom protoc plugin to generate both standard gRPC code and Orion-specific service code. To generate the necessary files, use the --orion_out flag along with the standard gRPC plugin.

    protoc -I . stringproto.proto --go_out=plugins=grpc:. --orion_out=.
  11. Make HTTP calls to Orion services

    master

    Orion automatically exposes your gRPC services via HTTP. By default, Orion responds with application/json. You can request application/protobuf by setting the Accept header.

    # Default JSON request
    curl -X POST -i -d '{"msg":"Hello World"}' http://127.0.0.1:9282/stringservice/upper
    
    # Requesting Protobuf response
    curl -X POST -i -H "Accept:application/protobuf" -d '{"msg":"Hello World"}' http://127.0.0.1:9282/stringservice/upper