diff --git a/pkg/errorx/errors.go b/pkg/errorx/errors.go index bdad43a..ddac06a 100644 --- a/pkg/errorx/errors.go +++ b/pkg/errorx/errors.go @@ -64,6 +64,8 @@ func FromGRPCStatus(s *grpcStatus.Status) error { //nolint:gocyclo return TooManyRequests{Msg: msg} case errorxpb.ErrorxType_UNSUPPORTED_MEDIA_TYPE: return UnsupportedMediaType{Msg: msg} + case errorxpb.ErrorxType_REQUEST_TIMEOUT: + return RequestTimeout{Msg: msg} default: return Internal{Msg: "invalid errorx type specifier. " + msg} } @@ -405,6 +407,42 @@ func (e TooManyRequests) GRPCStatusDetails() []protov1.Message { }} } +var _ Error = RequestTimeout{} + +type RequestTimeout struct { + Msg string + Err error +} + +func (e RequestTimeout) Error() string { + if e.Err != nil { + return fmt.Sprintf("%s: %s", e.Msg, e.Err) + } + return e.Msg +} + +func (e RequestTimeout) Message() string { + return e.Msg +} + +func (e RequestTimeout) Unwrap() error { + return e.Err +} + +func (e RequestTimeout) HTTPStatusCode() int { + return http.StatusRequestTimeout +} + +func (e RequestTimeout) GRPCStatus() *grpcStatus.Status { + return WithErrorxTypeDetail(grpcStatus.New(codes.DeadlineExceeded, e.Error()), e.GRPCStatusDetails()...) +} + +func (e RequestTimeout) GRPCStatusDetails() []protov1.Message { + return []protov1.Message{&errorxpb.ErrorDetails{ + Type: errorxpb.ErrorxType_REQUEST_TIMEOUT, + }} +} + func TryUnwrap(err error) error { if wrapped, ok := err.(interface{ Unwrap() error }); ok { return wrapped.Unwrap() diff --git a/pkg/errorx/errors_test.go b/pkg/errorx/errors_test.go index cf7b771..120a8c2 100644 --- a/pkg/errorx/errors_test.go +++ b/pkg/errorx/errors_test.go @@ -68,6 +68,11 @@ func TestGRPCStatusRoundTrip(t *testing.T) { err: TooManyRequests{Msg: "too much!"}, wantErr: TooManyRequests{Msg: "grpc ResourceExhausted: too much!"}, }, + { + name: "RequestTimeout", + err: RequestTimeout{Msg: "client timeout"}, + wantErr: RequestTimeout{Msg: "grpc DeadlineExceeded: client timeout"}, + }, } for _, tc := range tests { diff --git a/pkg/errorx/http_translator_test.go b/pkg/errorx/http_translator_test.go index de6c8db..8fa9ec7 100644 --- a/pkg/errorx/http_translator_test.go +++ b/pkg/errorx/http_translator_test.go @@ -63,6 +63,10 @@ func TestLogAndSetHttpError(t *testing.T) { expectedCode: http.StatusInternalServerError, expectedMessage: "unknown error", }, + "request timeout": { + err: RequestTimeout{}, + expectedCode: http.StatusRequestTimeout, + }, } { logger := log.NewNopLogger() recorder := httptest.NewRecorder() diff --git a/pkg/errorxpb/errors.pb.go b/pkg/errorxpb/errors.pb.go index ad79470..3160c70 100644 --- a/pkg/errorxpb/errors.pb.go +++ b/pkg/errorxpb/errors.pb.go @@ -1,6 +1,6 @@ // Code generated by protoc-gen-go. DO NOT EDIT. // versions: -// protoc-gen-go v1.30.0 +// protoc-gen-go v1.32.0 // protoc v3.21.12 // source: protos/errorx/v1/errors.proto @@ -36,6 +36,7 @@ const ( ErrorxType_CONFLICT ErrorxType = 8 ErrorxType_TOO_MANY_REQUESTS ErrorxType = 9 ErrorxType_UNSUPPORTED_MEDIA_TYPE ErrorxType = 10 + ErrorxType_REQUEST_TIMEOUT ErrorxType = 11 ) // Enum value maps for ErrorxType. @@ -52,6 +53,7 @@ var ( 8: "CONFLICT", 9: "TOO_MANY_REQUESTS", 10: "UNSUPPORTED_MEDIA_TYPE", + 11: "REQUEST_TIMEOUT", } ErrorxType_value = map[string]int32{ "UNKNOWN": 0, @@ -65,6 +67,7 @@ var ( "CONFLICT": 8, "TOO_MANY_REQUESTS": 9, "UNSUPPORTED_MEDIA_TYPE": 10, + "REQUEST_TIMEOUT": 11, } ) @@ -163,7 +166,7 @@ var file_protos_errorx_v1_errors_proto_rawDesc = []byte{ 0x01, 0x20, 0x01, 0x28, 0x0e, 0x32, 0x12, 0x2e, 0x65, 0x72, 0x72, 0x6f, 0x72, 0x78, 0x2e, 0x45, 0x72, 0x72, 0x6f, 0x72, 0x78, 0x54, 0x79, 0x70, 0x65, 0x52, 0x04, 0x74, 0x79, 0x70, 0x65, 0x12, 0x16, 0x0a, 0x06, 0x52, 0x65, 0x61, 0x73, 0x6f, 0x6e, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, - 0x06, 0x52, 0x65, 0x61, 0x73, 0x6f, 0x6e, 0x2a, 0xe2, 0x01, 0x0a, 0x0a, 0x45, 0x72, 0x72, 0x6f, + 0x06, 0x52, 0x65, 0x61, 0x73, 0x6f, 0x6e, 0x2a, 0xf7, 0x01, 0x0a, 0x0a, 0x45, 0x72, 0x72, 0x6f, 0x72, 0x78, 0x54, 0x79, 0x70, 0x65, 0x12, 0x0b, 0x0a, 0x07, 0x55, 0x4e, 0x4b, 0x4e, 0x4f, 0x57, 0x4e, 0x10, 0x00, 0x12, 0x0c, 0x0a, 0x08, 0x49, 0x4e, 0x54, 0x45, 0x52, 0x4e, 0x41, 0x4c, 0x10, 0x01, 0x12, 0x0f, 0x0a, 0x0b, 0x42, 0x41, 0x44, 0x5f, 0x52, 0x45, 0x51, 0x55, 0x45, 0x53, 0x54, @@ -177,9 +180,10 @@ var file_protos_errorx_v1_errors_proto_rawDesc = []byte{ 0x4f, 0x4e, 0x46, 0x4c, 0x49, 0x43, 0x54, 0x10, 0x08, 0x12, 0x15, 0x0a, 0x11, 0x54, 0x4f, 0x4f, 0x5f, 0x4d, 0x41, 0x4e, 0x59, 0x5f, 0x52, 0x45, 0x51, 0x55, 0x45, 0x53, 0x54, 0x53, 0x10, 0x09, 0x12, 0x1a, 0x0a, 0x16, 0x55, 0x4e, 0x53, 0x55, 0x50, 0x50, 0x4f, 0x52, 0x54, 0x45, 0x44, 0x5f, - 0x4d, 0x45, 0x44, 0x49, 0x41, 0x5f, 0x54, 0x59, 0x50, 0x45, 0x10, 0x0a, 0x42, 0x0e, 0x5a, 0x0c, - 0x70, 0x6b, 0x67, 0x2f, 0x65, 0x72, 0x72, 0x6f, 0x72, 0x78, 0x70, 0x62, 0x62, 0x06, 0x70, 0x72, - 0x6f, 0x74, 0x6f, 0x33, + 0x4d, 0x45, 0x44, 0x49, 0x41, 0x5f, 0x54, 0x59, 0x50, 0x45, 0x10, 0x0a, 0x12, 0x13, 0x0a, 0x0f, + 0x52, 0x45, 0x51, 0x55, 0x45, 0x53, 0x54, 0x5f, 0x54, 0x49, 0x4d, 0x45, 0x4f, 0x55, 0x54, 0x10, + 0x0b, 0x42, 0x0e, 0x5a, 0x0c, 0x70, 0x6b, 0x67, 0x2f, 0x65, 0x72, 0x72, 0x6f, 0x72, 0x78, 0x70, + 0x62, 0x62, 0x06, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x33, } var ( diff --git a/protos/errorx/v1/errors.proto b/protos/errorx/v1/errors.proto index 16816e2..8655e87 100644 --- a/protos/errorx/v1/errors.proto +++ b/protos/errorx/v1/errors.proto @@ -27,4 +27,5 @@ enum ErrorxType { CONFLICT = 8; TOO_MANY_REQUESTS = 9; UNSUPPORTED_MEDIA_TYPE = 10; + REQUEST_TIMEOUT = 11; }