daniel.w 09cb6fd077 | ||
---|---|---|
.. | ||
code | ||
easy_func.go | ||
easy_func_test.go | ||
errors.go | ||
errors_test.go | ||
go.mod | ||
readme.md |
readme.md
Purpose of errs package
- compatible with
error
interface - encapsulate error message with functions in
easy_function.go
- easy for gRPC client/server
- support err's chain by Working with Errors in Go 1.13
Example - Normal function
Using builtin functions InvalidInput
to generate Err struct
please add your own functions if not exist
package main
import "adc.github.trendmicro.com/commercial-mgcp/library-go/pkg/errs"
func handleParam(s string) error {
// check user_id format
if ok := userIDFormat(s); !ok {
return errs.InvalidFormat("param user_id")
}
return nil
}
Example - gRPC Server
GetAgent
is a method of gRPC server, it wraps Err
struct to status.Status
struct
func (as *agentService) GetAgent(ctx context.Context, req *cloudep.GetAgentRequest) (*cloudep.GetAgentResponse, error) {
l := log.WithFields(logger.Fields{"tenant_id": req.TenantId, "agent_id": req.AgentId, "method": "GetAgent"})
tenantID, err := primitive.ObjectIDFromHex(req.TenantId)
if err != nil {
// err maybe errs.Err or general error
// it's safe to use Convert() here
return nil, status.Convert(err).Err()
}
...
}
Example - gRPC Client
Calling GetAgent
and retry when Category is "DB"
client := cloudep.NewAgentServiceClient(conn)
req := cloudep.GetAgentRequest{
TenantId: "not-a-valid-object-id",
AgentId: "5eb4fa99006d53c0cb6f9cfe",
}
// Retry if DB error
for retry := 3; retry > 0 ; retry-- {
resp, err := client.GetAgent(context.Background(), &req)
if err != nil {
e := errs.FromGRPCError(err)
if e.Category() == code.CatGRPC {
if e.Code() == uint32(codes.Unavailable) {
log.warn("GRPC service unavailable. Retrying...")
continue
}
log.errorf("GRPC built-in error: %v", e)
}
if e.Category() == code.CatDB {
log.warn("retry...")
continue
}
}
break
}
Example - REST server
- handling gRPC client error
- transfer to HTTP code
- transfer to Error body
func Handler(c *gin.Context) {
// handle error from gRPC client
resp, err := client.GetAgent(context.Background(), &req)
if err != nil {
// to Err
e := errs.FromGRPCError(err)
// get HTTP code & response struct
// 2nd parameter true means return general error message to user
c.JSON(e.HTTPStatus(), general.NewError(e, true))
}
}
Example - Error Chain
- set internal error by func
Wrap
- check Err has any error in err's chain matches the target by
errors.Is
- finds the first error in err's chain that matches target by
errors.As
// define a specific err type
type testErr struct {
code int
}
func (e *testErr) Error() string {
return strconv.Itoa(e.code)
}
func main() {
layer1Err := &testErr{code: 123}
// error chain: InvalidFormat -> layer 1 err
layer2Err := InvalidFormat("field A", "")
layer2Err.Wrap(layer1Err) //set internal error
// errors.Is should report true
hasLayer1Err := errors.Is(layer2Err, layer1Err)
// errors.As should return internal error
var internalErr *testErr
ok := errors.As(layer2Err, &internalErr)
}