cascade-kinesis-client will be used as a submodule of other projects, so it should not have "src/vmware.com/cascade-kinesis-client" in its path. To build this project locally, please manually create the parent folders. Change-Id: I8844e6a0e32aae65b28496915d8507e9fb1058c6
147 lines
6.6 KiB
Go
147 lines
6.6 KiB
Go
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
|
|
}
|