Orion - a small lightweight framework written around grpc/protobuf with the aim to shorten time to build microservices at Carousell.

Overview

Orion Build Status Go Report Card codecov GoDoc

Orion is a small lightweight framework written around grpc/protobuf with the aim to shorten time to build microservices at Carousell.

It is derived from 'Framework' a small microservices framework written and used inside https://carousell.com, It comes with a number of sensible defaults such as zipkin tracing, hystrix, live reload of configuration, etc.

Getting Started

Follow the guide at https://github.com/carousell/Orion/blob/master/orion/README.md

Setup Instructions

Orion is written in golang, please follow instructions on https://golang.org/doc/install to install, or you can also run

brew install golang

or

sudo dnf install golang

Make sure you are on go 1.9 or later add the following lines to your ~/.profile

export GOPATH="$HOME/code/go"
export GOBIN="$GOPATH/bin"
export PATH="$GOBIN:$PATH"
export PATH="$HOME/.gotools:$PATH"

source your ~/.profile

source ~/.profile

then create the code dir

mkdir -p $GOPATH

we use govendor to vendor package in Orion, install it by running

go get -u github.com/kardianos/govendor

another helpful tool to check for unupdated packages is Go-Package-Store, install it by running

go get -u github.com/shurcooL/Go-Package-Store/cmd/Go-Package-Store

now clone this repo

mkdir -p $GOPATH/src/github.com/carousell/
git clone [email protected]:carousell/Orion.git $GOPATH/src/github.com/carousell/Orion

You need the following tools to better develop for go

go get -u golang.org/x/lint/golint

now you can build the package by using make build

gRPC

for gRPC, you need to follow the following steps

get gRPC codebase

go get -u google.golang.org/grpc

install protobuf

brew install protobuf

install the protoc plugin for go

go get -u github.com/golang/protobuf/{proto,protoc-gen-go}

install the protoc plugin for orion

go get -u github.com/carousell/Orion/protoc-gen-orion

Project Status

Orion is in use at production at Carousell and powers multiple (100+) services serving thousands of requests per second, we ensure all updates are backward compatible unless it involves a major bug or security issue.

License

This code is available under the following https://github.com/carousell/Orion/blob/master/LICENSE

Issues
  • Add GRPCRecovery Interceptor

    Add GRPCRecovery Interceptor

    • main purpose is to prevent silent crash because of server panic, should recover and send the error out (through notifier/log).
    • add GRPCRecoveryInterceptor to DefaultInterceptors()
    • in GRPCRecoveryInterceptor, it will use grpc_recovery middleware with defined handler return an Orion/utils/errors ErrorExt. The error will skip 4 stack frames and show the function triggered the panic.

    Concept Flow not include the change for http middlewares https://drive.google.com/file/d/13AkM-68szUG_ITRaWJUpnJGcQF4Xqb3J/view?usp=sharing

    Panic Log with no skip

    {"@timestamp":"2019-07-01T16:19:33.3244498Z","caller":"interceptors/interceptors.go:137","err":"runtime error: index out of range","grpcMethod":"/{service}/{rpcName}","level":"error",
    "stack":[
    {"file":"/go/src/github.com/.../vendor/github.com/carousell/Orion/interceptors/interceptors.go","line":153,"function":"GRPCRecoveryInterceptor.func1.1"},
    {"file":"/usr/local/go/src/runtime/asm_amd64.s","line":522,"function":"call32"},
    {"file":"/usr/local/go/src/runtime/panic.go","line":513,"function":"gopanic"},
    {"file":"/usr/local/go/src/runtime/panic.go","line":44,"function":"panicindex"},
    {"file":"/go/src/github.com/.../service.go","line":442,"function":"{panic func}"},
    ...
    

    so skip 4 stack frames to remove non-related information.

    Example on Sentry (Internal) https://sentry.carou.sl/carousell/home/issues/244262/?query=is:unresolved

    opened by stevenCarousell 4
  • reorder defaultclientinterceptors

    reorder defaultclientinterceptors

    A request that failed could be many reasons including network-level issues, connection re-establishment, etc.. Hystrix as implementing circuit breaker pattern considers how to avoid intermittent network hiccups as well. Also, we don't want to have circuit open because of too many retries that were probably intended.

    In other words, we consider Hystrix Command as a whole for a request to other services regardless of whether retry or not.

    However, it may be a breaking change to some services that have been using grpc_retry options. We will have to notice those services after we merge this PR.

    opened by hothero 3
  • Fix travis ci error

    Fix travis ci error

    We have an error when travis building code on tip env with go1.19. Run go mod tidy for download missing packages on the env. Add more go version for building the code.

    opened by cs-lexliu 2
  • modify error tag to fit opentracing convention

    modify error tag to fit opentracing convention

    According to the opentracing tags spec, the error should be boolean. https://github.com/opentracing/specification/blob/master/semantic_conventions.md#span-tags-table

    The vendor e.g Jaeger will treat the tag as a special render on jaeger-query page. It will be easier to find error spans by filter the error=true tag also.

    Screen Shot 2020-12-22 at 1 50 15 PM Screen Shot 2020-12-22 at 9 59 40 PM

    opened by stevenCarousell 2
  • Add grpc_retry.UnaryClientInterceptor() as a default client interceptor

    Add grpc_retry.UnaryClientInterceptor() as a default client interceptor

    Adding grpc_retry.UnaryClientInterceptor() to DefaultClientInterceptors makes it easy for services to enable retries for gRPC method calls. By default, the number of retries is zero, so this change has no effect on services unless they opt in to the behaviour.

    Services will most commonly use these options to configure the retry behaviour:

    • grpc_retry.WithMax - specifies the number of retries
    • grpc_retry.WithCodes - specifies which gRPC error codes to retry on (defaults to ResourceExhausted and Unavailable)

    Simplest usage example:

    import (
    	...
    	grpc_retry "github.com/grpc-ecosystem/go-grpc-middleware/retry"
    )
    
    func (c *client) GetThing (ctx context.Context, req *GetThingRequest) (*GetThingResponse, error) {
    	return c.thingClient.GetThing(ctx, req, grpc_retry.WithMax(3))
    }
    

    I have added it as the first interceptor, so that it wraps around the tracing interceptor.

    opened by humjosh 2
  • Treatment of errors in Orion

    Treatment of errors in Orion

    Context

    At present all errors from a service are treated as errors on Orion and so treated as errors on New Relic. However, for SSO, we have a use case where we would like to ignore HTTP 401s for the login endpoints (this is the case when a user gives incorrect login credentials) and treat that as a non-error.

    I tried to do this by creating a custom decoder for login, but that didn't work because it's not possible to change the endpointError variable from the decoder. At present, I can't think of a clean way to send a HTTP 401 to clients and still not treat that as an error.

    Impact

    NR is reporting a 20% error rate for SSO on prod, but they're mostly rpc error: code = Unauthenticated desc = Unauthorized took 71.696791ms errors which are used to return a 401, making it hard to detect legitimate errors on NR.

    Proposed Solution

    One workaround that I can think of is to ignore such errors in the New Relic config, as in https://docs.newrelic.com/docs/agents/go-agent/configuration/go-agent-configuration#error-ignore-status. Hence, it'll be great if Orion could provide an API or some way for services to customise this.

    opened by staceytay 2
  • multiple-value uuid.NewV4() in single-value context

    multiple-value uuid.NewV4() in single-value context

    Symptom: github.com/carousell/Orion/utils/worker/workerinfo.go:58:22: multiple-value uuid.NewV4() in single-value context

    I check the code of github.com/satori/uuid. The NewV4() will return 2 values. You can refer to https://github.com/satori/go.uuid/blob/36e9d2ebbde5e3f13ab2e25625fd453271d6522e/generator.go#L67

    opened by n0rmanc 2
  • Services in a single proto file register encoders that are not in their service

    Services in a single proto file register encoders that are not in their service

    When defining multiple services in a proto file, for example

    service SSOService {
        // ORION:URL: OPTIONS/POST /ssoservice/login/
        rpc Login (LoginRequest) returns (LoginResponse) {}
    }
    
    service SSOServiceInternal {
        // ORION:URL: GET /ssoservice-internal/backend-token/
        rpc GetBackendToken (GetBackendTokenRequest) returns (GetBackendTokenResponse) {}
    }
    

    will result in sso.proto.orion.pb.go having

    func RegisterSSOServiceOrionServer(srv orion.ServiceFactory, orionServer orion.Server) {
    	orionServer.RegisterService(&_SSOService_serviceDesc, srv)
    	RegisterSSOServiceLoginEncoder(orionServer, nil)
    	RegisterSSOServiceInternalGetBackendTokenEncoder(orionServer, nil)
    }
    
    func RegisterSSOServiceInternalOrionServer(srv orion.ServiceFactory, orionServer orion.Server) {
    	orionServer.RegisterService(&_SSOServiceInternal_serviceDesc, srv)
    	RegisterSSOServiceLoginEncoder(orionServer, nil)
    	RegisterSSOServiceInternalGetBackendTokenEncoder(orionServer, nil)
    }
    

    I find this is unexpected, I'm thinking that the expected results should be

    func RegisterSSOServiceOrionServer(srv orion.ServiceFactory, orionServer orion.Server) {
    	orionServer.RegisterService(&_SSOService_serviceDesc, srv)
    	RegisterSSOServiceLoginEncoder(orionServer, nil)
    }
    
    func RegisterSSOServiceInternalOrionServer(srv orion.ServiceFactory, orionServer orion.Server) {
    	orionServer.RegisterService(&_SSOServiceInternal_serviceDesc, srv)
    	RegisterSSOServiceInternalGetBackendTokenEncoder(orionServer, nil)
    }
    
    opened by staceytay 2
  • Fix passing trace metadata

    Fix passing trace metadata

    This PR fixes metadata forwarding issue for trace headers present in DefaultClientInterceptors.

    Current behaviour Client Side Outgoing grpc calls from Orion services are recommended to user DefaultClientInterceptors. Among other, these interceptors are GRPCClientInterceptor and ForwardMetadataInterceptor, in that order.

    GRPCClientInterceptor is a wrapper around grpc_opentracing.UnaryClientInterceptor It starts a client span and adds the tracing headers to outgoing metadata using metadata.NewOutgoingContext

    ForwardMetadataInterceptor reads the incoming metadata from context and appends to outgoing metadata context using metadata.AppendToOutgoingContext

    The result of these two interceptor can be illustrated as following: Suppose ServiceA -> ServiceB, the outgoing metadata in this grpc call looks like:

    {
        "traceid" : ["<trace id from new grpc client span>", "<trace id in the incoming metadata>"],
        "spanid" : ["<span id from new grpc client span>", "<span id in the incoming metadata>"],
    // .... other trace headers.
    
    }
    

    Note: the trace header key will depend on the propagation mechanism configured in tracer initialisation.

    Server side The Orion server receiving these header will read them in the grpc_opentracing.UnaryServerInterceptor

    This interceptors reads trace headers from metadata, create a parent span context from them and sets it to a newly created service side span.

    This logic in this interceptors read the last value for a particular key. So in our example <trace id in the incoming metadata> and <span id in the incoming metadata> will be used to create the parent span context.

    This is undesirable because a wrong parent context is created at the server side. The parent context should be of the client span created by grpc_opentracing.UnaryClientInterceptor.

    Solution This PR fixes the order of client interceptors to ForwardMetadataInterceptor before GRPCClientInterceptor.

    ForwardMetadataInterceptor appends the incoming metadata to outgoing metadata as is. But GRPCClientInterceptor overwrites (since it uses metadata.NewOutgoingContext) the trace metadata with the current span info.

    In above example this will be received by ServiceB server interceptor.

    {
        "traceid" : ["<trace id from new grpc client span>],
        "spanid" : ["<span id from new grpc client span>],
    // .... other trace headers.
    
    }
    

    This is desirable since the server interceptors only need to know the span info of it's caller.

    opened by praveensanap 1
  • Remove missing dependency `micro/protobuf`

    Remove missing dependency `micro/protobuf`

    The package micro/protobuf has been removed from github. Go return error when executing go mod tidy, because the repository is unreachable. Replace the package with protobuf/protoc-gen-go/generator which has the same functionality.

    opened by cs-lexliu 1
  • Deprecate trace function in notifier package

    Deprecate trace function in notifier package

    This PR deprecates trace-id functionality from notifier package.

    notifier package relies on "trace" set in the span baggage of the parent span based on opentracing spec.

    With release of Metadata passing functionality, we want metadata to carry trace information and not the spancontext baggage. https://github.com/carousell/Orion/pull/149

    We recommend forwarding trace information using grpc_opentracing.UnaryClientInterceptor from github.com/grpc-ecosystem/go-grpc-middleware module.

    opened by praveensanap 1
  • Support tool installation after Go 1.17

    Support tool installation after Go 1.17

    Situation:

    Starting in Go 1.17, installing executables with go get is deprecated. go install may be used instead. And go get is no longer supported outside a module in Go 1.18. (Source)

    Which means Orion is no longer available in Go 1.18. We will stuck with older version of Go in the future.

    Install protoc-gen-orion with different Go version.

    ||Go 1.16|Go 1.17|Go 1.18| |-|-|-|-| |go get|Passed|Warned|Failed| |go install|Failed|Failed|Failed|

    go get -u github.com/carousell/Orion/protoc-gen-orion go install github.com/carousell/Orion/[email protected]

    Target:

    Allow protoc-gen-orion to be installed by go install.

    Action:

    Remove replace directives from go.mod.

    Result:

    We can install protoc-gen-go with go install command in Go 1.16, 1.17, and 1.18.

    Install protoc-gen-orion with different Go version.

    ||Go 1.16|Go 1.17|Go 1.18| |-|-|-|-| |go get|Passed|Warned|Failed| |go install|Passed|Passed|Passed|

    go get -u github.com/carousell/Orion/[email protected] go install github.com/carousell/Orion/[email protected] 46c52b6f = this commit

    opened by cs-lexliu 2
  • Unable to register service to Orion Server

    Unable to register service to Orion Server

    Context

    The grpc.ServiceDesc has been exported from protoc-gen-go-grpc v1.1.0. The protoc-gen-orion generates the file that contains an unresolved reference to the unexported name of service desc.

    Process

    Use the Orion example.

    Execute protoc -I. --go-grpc_out=. --go_out=. --orion_out=. simple.proto.

    Environment

    go version         1.17.6
    protoc-gen-go-grpc v1.2.0
    protoc-gen-orion   latest
    protoc-gen-go      v1.27.1
    

    Expected result

    The simple service should be registered in Orion Serve, and simple_proto/simple.proto.orion.pb.go should not contain any error.

    Current result

    In simple_proto/simple.proto.orion.pb.go, we got a following error.

    Unresolved reference '_SimpleService_serviceDesc'
    

    Possible Fix

    Follow the protoc-gen-go-grpc naming role in https://github.com/grpc/grpc-go/pull/4035. And modify the generating code. https://github.com/carousell/Orion/blob/ec021a79aefef548f78fd349884cb3f50b8db9ed/protoc-gen-orion/orion.go#L262

    opened by cs-lexliu 0
  • add this repo into sonarqube check

    add this repo into sonarqube check

    1. Add sonar-test, sonar-check-pr, and sonar-check-baseline commands into Makefile
    2. Add sonar.properties file to set up the configuration of sonarqube check
    3. Enable sonarcloud and add new commands into the script section in .travis yml
    4. Set up the connection between github repo and sonarqube
    5. Add this new project into sonarqube http://10.108.16.28/projects?search=orion
    6. Add new environment variable and cron job into Travis job https://travis-ci.com/github/carousell/orion/settings
    opened by ChenChiaHung 0
  • Forward headers package

    Forward headers package

    The main idea is to have the capability to whitelist outgoing headers and not break our DefaultClientInterceptor.

    • Create a forwardheaders package responsible for server and client interceptors, allowlist management through context and some util functions
    • Extend orion.config to have forwardheaders as the allowlist
    • Extend orion.config to have NoDefaultInterceptors (we have the capability but seems no one set it yet)
    • Extend DefaultServerInterceptors to set allowlist for forwardheaders
    • Transform HTTP headers into gRPC headers (metadata)
    opened by hothero 1
Owner
Carousell
Carousell is a community marketplace that makes selling as simple as taking a photo, buying as simple as chatting.
Carousell
Go-grpc-template - A small template for quickly bootstrapping a, developer platform independent gRPC golang application

go-grpc-template A small template for quickly bootstrapping a developer platform

null 1 Jan 20, 2022
Our aim is to expand the capabilities of blockchain and make a secure way for transferring NFT between RMRK and MOVR blockchain.

remov Inspiration Our aim is to expand the capabilities of blockchain and make a secure way for transferring NFT between RMRK and MOVR blockchain. The

RMRK Team 4 Jan 10, 2022
The aim of this project is to publish and archive newsletters to a target email address.

Publish Newsletter Curated by a Group of People Even though the name says Group of People, it can be just you. The aim of this project is to publish a

코딩냄비 12 Jan 30, 2022
protoc-gen-grpc-gateway-ts is a Typescript client generator for the grpc-gateway project. It generates idiomatic Typescript clients that connect the web frontend and golang backend fronted by grpc-gateway.

protoc-gen-grpc-gateway-ts protoc-gen-grpc-gateway-ts is a Typescript client generator for the grpc-gateway project. It generates idiomatic Typescript

gRPC Ecosystem 63 May 9, 2022
⚡️Lightweight framework for microservices & web services in golang

Quickstart Zepto is a lightweight framework for the development of microservices & web services in golang. As an opinionated framework, zepto proposes

null 115 Mar 14, 2022
Using Wireshark to decrypt TLS gRPC Client-Server protobuf messages

Using Wireshark to decrypt TLS gRPC Client-Server protobuf messages Sample client server in golang that demonstrates how to decode protobuf messages f

null 3 Nov 24, 2021
A simple RPC framework with protobuf service definitions

Twirp is a framework for service-to-service communication emphasizing simplicity and minimalism. It generates routing and serialization from API defin

Twitch 5.8k May 19, 2022
Lightweight http response time based load balancer written in Go

HTTP Load Balancer Specifications http servers should always return time taken to proceed request in headers as EXECUTION_TIME in ms this load balance

Gaëtan 0 Feb 22, 2022
A suite of gRPC debugging tools. Like Fiddler/Charles but for gRPC.

grpc-tools A suite of tools for gRPC debugging and development. Like Fiddler/Charles but for gRPC! The main tool is grpc-dump which transparently inte

Bradley Kemp 1.1k Apr 27, 2022
grpc-http1: A gRPC via HTTP/1 Enabling Library for Go

grpc-http1: A gRPC via HTTP/1 Enabling Library for Go This library enables using all the functionality of a gRPC server even if it is exposed behind a

StackRox 76 May 2, 2022
Server and client implementation of the grpc go libraries to perform unary, client streaming, server streaming and full duplex RPCs from gRPC go introduction

Description This is an implementation of a gRPC client and server that provides route guidance from gRPC Basics: Go tutorial. It demonstrates how to u

Joram Wambugu 0 Nov 24, 2021
Go based grpc - grpc gateway micro service example

go-grpc-gateway-server This repository provides an example for go based microservice. Go micro services developed based on gRPC protobuf's and also us

Suresh Yekasiri 0 Dec 8, 2021
Simple grpc web and grpc transcoding with Envoy

gRPC Web and gRPC Transcoding with Envoy This is a simple stand-alone set of con

null 0 Dec 25, 2021
Go-grpc - This is grpc server for golang.

go-grpc This is grpc server for golang. protocのインストール brew install protoc Golang用のプラグインのインストール go install google.golang.org/protobuf/cmd/protoc-gen-go

jotaro yuza 1 Jan 2, 2022
GRPC - Creating a gRPC service from scratch

#Go gRPC services course Creating a gRPC service from scratch Command line colle

Rafael Diaz Miles 1 Jan 2, 2022
Totem - A Go library that can turn a single gRPC stream into bidirectional unary gRPC servers

Totem is a Go library that can turn a single gRPC stream into bidirectional unar

Joe Kralicky 2 Jan 10, 2022
Grpc-gateway-map-null - gRPC Gateway test using nullable values in map

Demonstrate gRPC gateway behavior with nullable values in maps Using grpc-gatewa

null 1 Jan 6, 2022
Todo-app-grpc - Go/GRPC codebase containing RealWorld examples (CRUD, auth, advanced patterns, etc)

Go/GRPC codebase containing RealWorld examples (CRUD, auth, advanced patterns, e

Sammi Aldhi Yanto 2 May 14, 2022
GRPC - A client-server mockup, using gRPC to expose functionality.

gRPC This is a mockup application that I built to help me visualise and understand the basic concepts of gRPC. In this exchange, the client can use a

Fergal Bittles 0 Jan 4, 2022