vmware-go-kcl-v2/src/clientlibrary/common/errors.go

148 lines
6.6 KiB
Go
Raw Normal View History

package common
import (
"fmt"
"net/http"
)
// ErrorCode is unified definition of numerical error codes
type ErrorCode int32
// pre-defined error codes
const (
// System Wide 41000 - 42000
KinesisClientLibError ErrorCode = 41000
// KinesisClientLibrary Retryable Errors 41001 - 41100
KinesisClientLibRetryableError ErrorCode = 41001
KinesisClientLibIOError ErrorCode = 41002
BlockedOnParentShardError ErrorCode = 41003
KinesisClientLibDependencyError ErrorCode = 41004
ThrottlingError ErrorCode = 41005
// KinesisClientLibrary NonRetryable Errors 41100 - 41200
KinesisClientLibNonRetryableException ErrorCode = 41100
InvalidStateError ErrorCode = 41101
ShutdownError ErrorCode = 41102
// Kinesis Lease Errors 41200 - 41300
LeasingError ErrorCode = 41200
LeasingInvalidStateError ErrorCode = 41201
LeasingDependencyError ErrorCode = 41202
LeasingProvisionedThroughputError ErrorCode = 41203
// Misc Errors 41300 - 41400
// NotImplemented
KinesisClientLibNotImplemented ErrorCode = 41301
// Error indicates passing illegal or inappropriate argument
IllegalArgumentError ErrorCode = 41302
)
var errorMap = map[ErrorCode]ClientLibraryError{
KinesisClientLibError: {ErrorCode: KinesisClientLibError, Retryable: true, Status: http.StatusServiceUnavailable, Msg: "Top level error of Kinesis Client Library"},
// Retryable
KinesisClientLibRetryableError: {ErrorCode: KinesisClientLibRetryableError, Retryable: true, Status: http.StatusServiceUnavailable, Msg: "Retryable exceptions (e.g. transient errors). The request/operation is expected to succeed upon (back off and) retry."},
KinesisClientLibIOError: {ErrorCode: KinesisClientLibIOError, Retryable: true, Status: http.StatusServiceUnavailable, Msg: "Error in reading/writing information (e.g. shard information from Kinesis may not be current/complete)."},
BlockedOnParentShardError: {ErrorCode: BlockedOnParentShardError, Retryable: true, Status: http.StatusServiceUnavailable, Msg: "Cannot start processing data for a shard because the data from the parent shard has not been completely processed (yet)."},
KinesisClientLibDependencyError: {ErrorCode: KinesisClientLibDependencyError, Retryable: true, Status: http.StatusServiceUnavailable, Msg: "Cannot talk to its dependencies (e.g. fetching data from Kinesis, DynamoDB table reads/writes, emitting metrics to CloudWatch)."},
ThrottlingError: {ErrorCode: ThrottlingError, Retryable: true, Status: http.StatusTooManyRequests, Msg: "Requests are throttled by a service (e.g. DynamoDB when storing a checkpoint)."},
// Non-Retryable
KinesisClientLibNonRetryableException: {ErrorCode: KinesisClientLibNonRetryableException, Retryable: false, Status: http.StatusServiceUnavailable, Msg: "Non-retryable exceptions. Simply retrying the same request/operation is not expected to succeed."},
InvalidStateError: {ErrorCode: InvalidStateError, Retryable: false, Status: http.StatusServiceUnavailable, Msg: "Kinesis Library has issues with internal state (e.g. DynamoDB table is not found)."},
ShutdownError: {ErrorCode: ShutdownError, Retryable: false, Status: http.StatusServiceUnavailable, Msg: "The RecordProcessor instance has been shutdown (e.g. and attempts a checkpiont)."},
// Leasing
LeasingError: {ErrorCode: LeasingError, Retryable: true, Status: http.StatusServiceUnavailable, Msg: "Top-level error type for the leasing code."},
LeasingInvalidStateError: {ErrorCode: LeasingInvalidStateError, Retryable: true, Status: http.StatusServiceUnavailable, Msg: "Error in a lease operation has failed because DynamoDB is an invalid state"},
LeasingDependencyError: {ErrorCode: LeasingDependencyError, Retryable: true, Status: http.StatusServiceUnavailable, Msg: "Error in a lease operation has failed because a dependency of the leasing system has failed."},
LeasingProvisionedThroughputError: {ErrorCode: LeasingProvisionedThroughputError, Retryable: false, Status: http.StatusServiceUnavailable, Msg: "Error in a lease operation has failed due to lack of provisioned throughput for a DynamoDB table."},
// IllegalArgumentError
IllegalArgumentError: {ErrorCode: IllegalArgumentError, Retryable: false, Status: http.StatusBadRequest, Msg: "Error indicates that a method has been passed an illegal or inappropriate argument."},
// Not Implemented
KinesisClientLibNotImplemented: {ErrorCode: KinesisClientLibNotImplemented, Retryable: false, Status: http.StatusNotImplemented, Msg: "Not Implemented"},
}
// Message returns the message of the error code
func (c ErrorCode) Message() string {
return errorMap[c].Msg
}
// MakeErr makes an error with default message
func (c ErrorCode) MakeErr() *ClientLibraryError {
e := errorMap[c]
return &e
}
// MakeError makes an error with message and data
func (c ErrorCode) MakeError(detail string) error {
e := errorMap[c]
return e.WithDetail(detail)
}
// ClientLibraryError is unified error
type ClientLibraryError struct {
// ErrorCode is the numerical error code.
ErrorCode `json:"code"`
// Retryable is a bool flag to indicate the whether the error is retryable or not.
Retryable bool `json:"tryable"`
// Status is the HTTP status code.
Status int `json:"status"`
// Msg provides a terse description of the error. Its value is defined in errorMap.
Msg string `json:"msg"`
// Detail provides a detailed description of the error. Its value is set using WithDetail.
Detail string `json:"detail"`
}
// Error implements error
func (e *ClientLibraryError) Error() string {
var prefix string
if e.Retryable {
prefix = "Retryable"
} else {
prefix = "NonRetryable"
}
msg := fmt.Sprintf("%v Error [%d]: %s", prefix, int32(e.ErrorCode), e.Msg)
if e.Detail != "" {
msg = fmt.Sprintf("%s, detail: %s", msg, e.Detail)
}
return msg
}
// WithMsg overwrites the default error message
func (e *ClientLibraryError) WithMsg(format string, v ...interface{}) *ClientLibraryError {
e.Msg = fmt.Sprintf(format, v...)
return e
}
// WithDetail adds a detailed message to error
func (e *ClientLibraryError) WithDetail(format string, v ...interface{}) *ClientLibraryError {
if len(e.Detail) == 0 {
e.Detail = fmt.Sprintf(format, v...)
} else {
e.Detail += ", " + fmt.Sprintf(format, v...)
}
return e
}
// WithCause adds CauseBy to error
func (e *ClientLibraryError) WithCause(err error) *ClientLibraryError {
if err != nil {
// Store error message in Detail, so the info can be preserved
// when CascadeError is marshaled to json.
if len(e.Detail) == 0 {
e.Detail = err.Error()
} else {
e.Detail += ", cause: " + err.Error()
}
}
return e
}