mirror of
https://github.com/redis/go-redis.git
synced 2025-10-23 08:08:28 +03:00
feat: RESP3 notifications support & Hitless notifications handling [CAE-1088] & [CAE-1072] (#3418)
- Adds support for handling push notifications with RESP3. - Using this support adds handlers for hitless upgrades. --------- Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com> Co-authored-by: Hristo Temelski <hristo.temelski@redis.com>
This commit is contained in:
170
push/errors.go
Normal file
170
push/errors.go
Normal file
@@ -0,0 +1,170 @@
|
||||
package push
|
||||
|
||||
import (
|
||||
"errors"
|
||||
"fmt"
|
||||
)
|
||||
|
||||
// Push notification error definitions
|
||||
// This file contains all error types and messages used by the push notification system
|
||||
|
||||
// Error reason constants
|
||||
const (
|
||||
// HandlerReasons
|
||||
ReasonHandlerNil = "handler cannot be nil"
|
||||
ReasonHandlerExists = "cannot overwrite existing handler"
|
||||
ReasonHandlerProtected = "handler is protected"
|
||||
|
||||
// ProcessorReasons
|
||||
ReasonPushNotificationsDisabled = "push notifications are disabled"
|
||||
)
|
||||
|
||||
// ProcessorType represents the type of processor involved in the error
|
||||
// defined as a custom type for better readability and easier maintenance
|
||||
type ProcessorType string
|
||||
|
||||
const (
|
||||
// ProcessorTypes
|
||||
ProcessorTypeProcessor = ProcessorType("processor")
|
||||
ProcessorTypeVoidProcessor = ProcessorType("void_processor")
|
||||
ProcessorTypeCustom = ProcessorType("custom")
|
||||
)
|
||||
|
||||
// ProcessorOperation represents the operation being performed by the processor
|
||||
// defined as a custom type for better readability and easier maintenance
|
||||
type ProcessorOperation string
|
||||
|
||||
const (
|
||||
// ProcessorOperations
|
||||
ProcessorOperationProcess = ProcessorOperation("process")
|
||||
ProcessorOperationRegister = ProcessorOperation("register")
|
||||
ProcessorOperationUnregister = ProcessorOperation("unregister")
|
||||
ProcessorOperationUnknown = ProcessorOperation("unknown")
|
||||
)
|
||||
|
||||
// Common error variables for reuse
|
||||
var (
|
||||
// ErrHandlerNil is returned when attempting to register a nil handler
|
||||
ErrHandlerNil = errors.New(ReasonHandlerNil)
|
||||
)
|
||||
|
||||
// Registry errors
|
||||
|
||||
// ErrHandlerExists creates an error for when attempting to overwrite an existing handler
|
||||
func ErrHandlerExists(pushNotificationName string) error {
|
||||
return NewHandlerError(ProcessorOperationRegister, pushNotificationName, ReasonHandlerExists, nil)
|
||||
}
|
||||
|
||||
// ErrProtectedHandler creates an error for when attempting to unregister a protected handler
|
||||
func ErrProtectedHandler(pushNotificationName string) error {
|
||||
return NewHandlerError(ProcessorOperationUnregister, pushNotificationName, ReasonHandlerProtected, nil)
|
||||
}
|
||||
|
||||
// VoidProcessor errors
|
||||
|
||||
// ErrVoidProcessorRegister creates an error for when attempting to register a handler on void processor
|
||||
func ErrVoidProcessorRegister(pushNotificationName string) error {
|
||||
return NewProcessorError(ProcessorTypeVoidProcessor, ProcessorOperationRegister, pushNotificationName, ReasonPushNotificationsDisabled, nil)
|
||||
}
|
||||
|
||||
// ErrVoidProcessorUnregister creates an error for when attempting to unregister a handler on void processor
|
||||
func ErrVoidProcessorUnregister(pushNotificationName string) error {
|
||||
return NewProcessorError(ProcessorTypeVoidProcessor, ProcessorOperationUnregister, pushNotificationName, ReasonPushNotificationsDisabled, nil)
|
||||
}
|
||||
|
||||
// Error type definitions for advanced error handling
|
||||
|
||||
// HandlerError represents errors related to handler operations
|
||||
type HandlerError struct {
|
||||
Operation ProcessorOperation
|
||||
PushNotificationName string
|
||||
Reason string
|
||||
Err error
|
||||
}
|
||||
|
||||
func (e *HandlerError) Error() string {
|
||||
if e.Err != nil {
|
||||
return fmt.Sprintf("handler %s failed for '%s': %s (%v)", e.Operation, e.PushNotificationName, e.Reason, e.Err)
|
||||
}
|
||||
return fmt.Sprintf("handler %s failed for '%s': %s", e.Operation, e.PushNotificationName, e.Reason)
|
||||
}
|
||||
|
||||
func (e *HandlerError) Unwrap() error {
|
||||
return e.Err
|
||||
}
|
||||
|
||||
// NewHandlerError creates a new HandlerError
|
||||
func NewHandlerError(operation ProcessorOperation, pushNotificationName, reason string, err error) *HandlerError {
|
||||
return &HandlerError{
|
||||
Operation: operation,
|
||||
PushNotificationName: pushNotificationName,
|
||||
Reason: reason,
|
||||
Err: err,
|
||||
}
|
||||
}
|
||||
|
||||
// ProcessorError represents errors related to processor operations
|
||||
type ProcessorError struct {
|
||||
ProcessorType ProcessorType // "processor", "void_processor"
|
||||
Operation ProcessorOperation // "process", "register", "unregister"
|
||||
PushNotificationName string // Name of the push notification involved
|
||||
Reason string
|
||||
Err error
|
||||
}
|
||||
|
||||
func (e *ProcessorError) Error() string {
|
||||
notifInfo := ""
|
||||
if e.PushNotificationName != "" {
|
||||
notifInfo = fmt.Sprintf(" for '%s'", e.PushNotificationName)
|
||||
}
|
||||
if e.Err != nil {
|
||||
return fmt.Sprintf("%s %s failed%s: %s (%v)", e.ProcessorType, e.Operation, notifInfo, e.Reason, e.Err)
|
||||
}
|
||||
return fmt.Sprintf("%s %s failed%s: %s", e.ProcessorType, e.Operation, notifInfo, e.Reason)
|
||||
}
|
||||
|
||||
func (e *ProcessorError) Unwrap() error {
|
||||
return e.Err
|
||||
}
|
||||
|
||||
// NewProcessorError creates a new ProcessorError
|
||||
func NewProcessorError(processorType ProcessorType, operation ProcessorOperation, pushNotificationName, reason string, err error) *ProcessorError {
|
||||
return &ProcessorError{
|
||||
ProcessorType: processorType,
|
||||
Operation: operation,
|
||||
PushNotificationName: pushNotificationName,
|
||||
Reason: reason,
|
||||
Err: err,
|
||||
}
|
||||
}
|
||||
|
||||
// Helper functions for common error scenarios
|
||||
|
||||
// IsHandlerNilError checks if an error is due to a nil handler
|
||||
func IsHandlerNilError(err error) bool {
|
||||
return errors.Is(err, ErrHandlerNil)
|
||||
}
|
||||
|
||||
// IsHandlerExistsError checks if an error is due to attempting to overwrite an existing handler
|
||||
func IsHandlerExistsError(err error) bool {
|
||||
if handlerErr, ok := err.(*HandlerError); ok {
|
||||
return handlerErr.Operation == ProcessorOperationRegister && handlerErr.Reason == ReasonHandlerExists
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
||||
// IsProtectedHandlerError checks if an error is due to attempting to unregister a protected handler
|
||||
func IsProtectedHandlerError(err error) bool {
|
||||
if handlerErr, ok := err.(*HandlerError); ok {
|
||||
return handlerErr.Operation == ProcessorOperationUnregister && handlerErr.Reason == ReasonHandlerProtected
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
||||
// IsVoidProcessorError checks if an error is due to void processor operations
|
||||
func IsVoidProcessorError(err error) bool {
|
||||
if procErr, ok := err.(*ProcessorError); ok {
|
||||
return procErr.ProcessorType == ProcessorTypeVoidProcessor && procErr.Reason == ReasonPushNotificationsDisabled
|
||||
}
|
||||
return false
|
||||
}
|
Reference in New Issue
Block a user