mirror of
https://github.com/nats-io/nats.go.git
synced 2025-10-28 02:42:14 +08:00
209 lines
8.8 KiB
Go
209 lines
8.8 KiB
Go
// Copyright 2020-2023 The NATS Authors
|
|
// Licensed under the Apache License, Version 2.0 (the "License");
|
|
// you may not use this file except in compliance with the License.
|
|
// You may obtain a copy of the License at
|
|
//
|
|
// http://www.apache.org/licenses/LICENSE-2.0
|
|
//
|
|
// Unless required by applicable law or agreed to in writing, software
|
|
// distributed under the License is distributed on an "AS IS" BASIS,
|
|
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
// See the License for the specific language governing permissions and
|
|
// limitations under the License.
|
|
|
|
package jetstream
|
|
|
|
import (
|
|
"errors"
|
|
"fmt"
|
|
)
|
|
|
|
type (
|
|
// JetStreamError is an error result that happens when using JetStream.
|
|
// In case of client-side error, [APIError] returns nil
|
|
JetStreamError interface {
|
|
APIError() *APIError
|
|
error
|
|
}
|
|
|
|
jsError struct {
|
|
apiErr *APIError
|
|
message string
|
|
}
|
|
|
|
// APIError is included in all API responses if there was an error.
|
|
APIError struct {
|
|
Code int `json:"code"`
|
|
ErrorCode ErrorCode `json:"err_code"`
|
|
Description string `json:"description,omitempty"`
|
|
}
|
|
|
|
// ErrorCode represents error_code returned in response from JetStream API
|
|
ErrorCode uint16
|
|
)
|
|
|
|
const (
|
|
JSErrCodeJetStreamNotEnabledForAccount ErrorCode = 10039
|
|
JSErrCodeJetStreamNotEnabled ErrorCode = 10076
|
|
|
|
JSErrCodeStreamNotFound ErrorCode = 10059
|
|
JSErrCodeStreamNameInUse ErrorCode = 10058
|
|
|
|
JSErrCodeConsumerCreate ErrorCode = 10012
|
|
JSErrCodeConsumerNotFound ErrorCode = 10014
|
|
JSErrCodeConsumerNameExists ErrorCode = 10013
|
|
JSErrCodeConsumerAlreadyExists ErrorCode = 10105
|
|
|
|
JSErrCodeMessageNotFound ErrorCode = 10037
|
|
|
|
JSErrCodeBadRequest ErrorCode = 10003
|
|
)
|
|
|
|
var (
|
|
// API errors
|
|
|
|
// ErrJetStreamNotEnabled is an error returned when JetStream is not enabled for an account.
|
|
ErrJetStreamNotEnabled JetStreamError = &jsError{apiErr: &APIError{ErrorCode: JSErrCodeJetStreamNotEnabled, Description: "jetstream not enabled", Code: 503}}
|
|
|
|
// ErrJetStreamNotEnabledForAccount is an error returned when JetStream is not enabled for an account.
|
|
ErrJetStreamNotEnabledForAccount JetStreamError = &jsError{apiErr: &APIError{ErrorCode: JSErrCodeJetStreamNotEnabledForAccount, Description: "jetstream not enabled for account", Code: 503}}
|
|
|
|
// ErrStreamNotFound is an error returned when stream with given name does not exist.
|
|
ErrStreamNotFound JetStreamError = &jsError{apiErr: &APIError{ErrorCode: JSErrCodeStreamNotFound, Description: "stream not found", Code: 404}}
|
|
|
|
// ErrStreamNameAlreadyInUse is returned when a stream with given name already exists and has a different configuration
|
|
ErrStreamNameAlreadyInUse JetStreamError = &jsError{apiErr: &APIError{ErrorCode: JSErrCodeStreamNameInUse, Description: "stream name already in use", Code: 400}}
|
|
|
|
// ErrConsumerNotFound is an error returned when consumer with given name does not exist.
|
|
ErrConsumerNotFound JetStreamError = &jsError{apiErr: &APIError{ErrorCode: JSErrCodeConsumerNotFound, Description: "consumer not found", Code: 404}}
|
|
|
|
// ErrMsgNotFound is returned when message with provided sequence number does npt exist.
|
|
ErrMsgNotFound JetStreamError = &jsError{apiErr: &APIError{ErrorCode: JSErrCodeMessageNotFound, Description: "message not found", Code: 404}}
|
|
|
|
// ErrBadRequest is returned when invalid request is sent to JetStream API.
|
|
ErrBadRequest JetStreamError = &jsError{apiErr: &APIError{ErrorCode: JSErrCodeBadRequest, Description: "bad request", Code: 400}}
|
|
|
|
// ErrConsumerCreate is returned when nats-server reports error when creating consumer (e.g. illegal update).
|
|
ErrConsumerCreate JetStreamError = &jsError{apiErr: &APIError{ErrorCode: JSErrCodeConsumerCreate, Description: "could not create consumer", Code: 500}}
|
|
|
|
// Client errors
|
|
|
|
// ErrConsumerNotFound is an error returned when consumer with given name does not exist.
|
|
ErrConsumerNameAlreadyInUse JetStreamError = &jsError{message: "consumer name already in use"}
|
|
|
|
// ErrInvalidJSAck is returned when JetStream ack from message publish is invalid.
|
|
ErrInvalidJSAck JetStreamError = &jsError{message: "invalid jetstream publish response"}
|
|
|
|
// ErrStreamNameRequired is returned when the provided stream name is empty.
|
|
ErrStreamNameRequired JetStreamError = &jsError{message: "stream name is required"}
|
|
|
|
// ErrConsumerNameRequired is returned when the provided consumer durable name is empty,
|
|
ErrConsumerNameRequired JetStreamError = &jsError{message: "consumer name is required"}
|
|
|
|
// ErrMsgAlreadyAckd is returned when attempting to acknowledge message more than once.
|
|
ErrMsgAlreadyAckd JetStreamError = &jsError{message: "message was already acknowledged"}
|
|
|
|
// ErrNoStreamResponse is returned when there is no response from stream (e.g. no responders error).
|
|
ErrNoStreamResponse JetStreamError = &jsError{message: "no response from stream"}
|
|
|
|
// ErrNotJSMessage is returned when attempting to get metadata from non JetStream message .
|
|
ErrNotJSMessage JetStreamError = &jsError{message: "not a jetstream message"}
|
|
|
|
// ErrInvalidStreamName is returned when the provided stream name is invalid (contains '.').
|
|
ErrInvalidStreamName JetStreamError = &jsError{message: "invalid stream name"}
|
|
|
|
// ErrInvalidConsumerName is returned when the provided consumer name is invalid (contains '.').
|
|
ErrInvalidConsumerName JetStreamError = &jsError{message: "invalid consumer name"}
|
|
|
|
// ErrNoMessages is returned when no messages are currently available for a consumer.
|
|
ErrNoMessages = &jsError{message: "no messages"}
|
|
|
|
// ErrMaxBytesExceeded is returned when a message would exceed MaxBytes set on a pull request.
|
|
ErrMaxBytesExceeded = &jsError{message: "message size exceeds max bytes"}
|
|
|
|
// ErrConsumerDeleted is returned when attempting to send pull request to a consumer which does not exist
|
|
ErrConsumerDeleted JetStreamError = &jsError{message: "consumer deleted"}
|
|
|
|
// ErrConsumerLeadershipChanged is returned when pending requests are no longer valid after leadership has changed
|
|
ErrConsumerLeadershipChanged JetStreamError = &jsError{message: "leadership change"}
|
|
|
|
// ErrHandlerRequired is returned when no handler func is provided in Stream()
|
|
ErrHandlerRequired = &jsError{message: "handler cannot be empty"}
|
|
|
|
// ErrEndOfData is returned when iterating over paged API from JetStream reaches end of data
|
|
ErrEndOfData = errors.New("nats: end of data reached")
|
|
|
|
// ErrNoHeartbeat is received when no message is received in IdleHeartbeat time (if set)
|
|
ErrNoHeartbeat = &jsError{message: "no heartbeat received"}
|
|
|
|
// ErrConsumerHasActiveSubscription is returned when a consumer is already subscribed to a stream
|
|
ErrConsumerHasActiveSubscription = &jsError{message: "consumer has active subscription"}
|
|
|
|
// ErrMsgNotBound is returned when given message is not bound to any subscription
|
|
ErrMsgNotBound = &jsError{message: "message is not bound to subscription/connection"}
|
|
|
|
// ErrMsgNoReply is returned when attempting to reply to a message without a reply subject
|
|
ErrMsgNoReply = &jsError{message: "message does not have a reply"}
|
|
|
|
// ErrMsgDeleteUnsuccessful is returned when an attempt to delete a message is unsuccessful
|
|
ErrMsgDeleteUnsuccessful = &jsError{message: "message deletion unsuccessful"}
|
|
|
|
// ErrAsyncPublishReplySubjectSet is returned when reply subject is set on async message publish
|
|
ErrAsyncPublishReplySubjectSet = &jsError{message: "reply subject should be empty"}
|
|
|
|
// ErrTooManyStalledMsgs is returned when too many outstanding async messages are waiting for ack
|
|
ErrTooManyStalledMsgs = &jsError{message: "stalled with too many outstanding async published messages"}
|
|
|
|
// ErrInvalidOption is returned when there is a collision between options
|
|
ErrInvalidOption = &jsError{message: "invalid jetstream option"}
|
|
|
|
// ErrMsgIteratorClosed is returned when attempting to get message from a closed iterator
|
|
ErrMsgIteratorClosed = &jsError{message: "messages iterator closed"}
|
|
|
|
ErrOrderedConsumerReset = &jsError{message: "recreating ordered consumer"}
|
|
ErrOrderedSequenceMismatch = &jsError{message: "sequence mismatch"}
|
|
)
|
|
|
|
// Error prints the JetStream API error code and description
|
|
func (e *APIError) Error() string {
|
|
return fmt.Sprintf("nats: API error: code=%d err_code=%d description=%s", e.Code, e.ErrorCode, e.Description)
|
|
}
|
|
|
|
// APIError implements the JetStreamError interface.
|
|
func (e *APIError) APIError() *APIError {
|
|
return e
|
|
}
|
|
|
|
// Is matches against an APIError.
|
|
func (e *APIError) Is(err error) bool {
|
|
if e == nil {
|
|
return false
|
|
}
|
|
// Extract internal APIError to match against.
|
|
var aerr *APIError
|
|
ok := errors.As(err, &aerr)
|
|
if !ok {
|
|
return ok
|
|
}
|
|
return e.ErrorCode == aerr.ErrorCode
|
|
}
|
|
|
|
func (err *jsError) APIError() *APIError {
|
|
return err.apiErr
|
|
}
|
|
|
|
func (err *jsError) Error() string {
|
|
if err.apiErr != nil && err.apiErr.Description != "" {
|
|
return err.apiErr.Error()
|
|
}
|
|
return fmt.Sprintf("nats: %s", err.message)
|
|
}
|
|
|
|
func (err *jsError) Unwrap() error {
|
|
// Allow matching to embedded APIError in case there is one.
|
|
if err.apiErr == nil {
|
|
return nil
|
|
}
|
|
return err.apiErr
|
|
}
|