Documentation
¶
Overview ¶
Package recovery provides automatic recovery for NATS JetStream streams and consumers.
The package uses JetStream Advisory Events as the primary detection mechanism for stream/consumer deletions and periodic health checks as a fallback.
Architecture ¶
The package consists of several components:
- Manager: Main orchestrator that composes all recovery components
- Registry: Thread-safe storage for stream configurations and subscription data
- Supervisor: Handles recovery logic with exponential backoff
- AdvisoryListener: Subscribes to JetStream advisory events for instant detection
- HealthMonitor: Fallback checks for missed events (scheduler-managed)
- RecoveryTimeoutMonitor: Clears stale "recovering" marks (scheduler-managed)
Integration with service/scheduler ¶
Background tasks (health checks, stale recovery cleanup) are designed to be run via an external scheduler (service/scheduler). This provides:
- Unified task management across the application
- Pause/resume/disable capabilities
- Execution history and monitoring
- Leader election for distributed deployments
Integration with natsprovider ¶
The recovery package integrates with the existing natsprovider package by accepting broker.SubscriberFactory for subscription configuration. This design:
- Eliminates duplicated message handling logic
- Reuses existing, tested subscription code
- Ensures consistent behavior with direct natsprovider usage
Recovery Strategies ¶
Three recovery strategies are supported via RecoveryStrategy:
- RecoveryStrategyAuto: Automatic recovery with exponential backoff (default)
- RecoveryStrategyManual: Notify via callback, no auto-recovery
- RecoveryStrategySkip: Ignore deletion events completely
Configuration Options ¶
The Manager accepts functional options:
- WithMaxRecoveryAttempts: Max recovery attempts before giving up (default: 3)
- WithRecoveryBackoff: Base backoff between attempts (default: 5s)
- WithStaleRecoveryTimeout: When to clear stale recovery marks (default: 20m)
- WithLogger: Logger for recovery operations
- WithOnRecoverySuccess: Callback on successful recovery
- WithOnRecoveryFailure: Callback on failed recovery
- WithOnManualRecoveryNeeded: Callback for manual strategy streams
- WithOnStaleRecoveryCleared: Callback when stale mark cleared
Usage ¶
// Create NATS provider
provider, _ := natsprovider.New(natsConn)
// Create recovery manager
manager, _ := recovery.New(provider,
recovery.WithMaxRecoveryAttempts(3),
recovery.WithLogger(logger),
)
// Start advisory listener for instant detection
manager.Start()
// Register background tasks with external scheduler
scheduler.Register(ctx, scheduler.TaskConfig{
ID: "recovery-health-check",
Schedule: "0 */5 * * * *", // every 5 minutes
Func: manager.RunHealthCheckCycle,
})
scheduler.Register(ctx, scheduler.TaskConfig{
ID: "recovery-stale-cleanup",
Schedule: "0 * * * * *", // every minute
Func: manager.RunStaleRecoveryCleanup,
})
// Register stream for recovery
manager.RegisterStream(jetstream.StreamConfig{
Name: "ORDERS",
Subjects: []string{"orders.>"},
}, recovery.WithRecoveryStrategy(recovery.RecoveryStrategyAuto))
// Subscribe using natsprovider factory - recovery is automatic
sub, err := manager.Subscribe(ctx, "ORDERS", "order-processor", handler,
natsprovider.SubscriberWithConsumer(&jetstream.ConsumerConfig{
Durable: "order-processor",
}),
)
// On shutdown
manager.Close()
Thread Safety ¶
All components are thread-safe for concurrent use. The Manager uses mutex-protected maps and atomic operations for state management.
Index ¶
- Constants
- Variables
- type AdvisoryListener
- type AdvisoryListenerConfig
- type ConsumerDeletedAdvisory
- type HealthMonitor
- type HealthMonitorConfig
- type ManagedSubscription
- type Manager
- func (m *Manager) Close()
- func (m *Manager) CreateStream(ctx context.Context, cfg jetstream.StreamConfig, opts ...StreamOption) (jetstream.Stream, error)
- func (m *Manager) GetRegistry() *Registry
- func (m *Manager) GetSupervisor() *Supervisor
- func (m *Manager) RegisterHealthCheckSchedulerFunc() func(context.Context) error
- func (m *Manager) RegisterStaleCleanupSchedulerFunc() func(context.Context) error
- func (m *Manager) RegisterStream(cfg jetstream.StreamConfig, opts ...StreamOption) error
- func (m *Manager) RunHealthCheckCycle(ctx context.Context) error
- func (m *Manager) RunStaleRecoveryCleanup(ctx context.Context) error
- func (m *Manager) Start() error
- func (m *Manager) Subscribe(ctx context.Context, stream string, consumerName string, ...) (*ManagedSubscription, error)
- func (m *Manager) UnregisterStream(name string)
- type ManualRecoveryCallback
- type Option
- func WithHealthCheckSchedule[T interface{ ... }](v T) Option
- func WithLogger(v *slog.Logger) Option
- func WithMaxRecoveryAttempts(v int) Option
- func WithOnManualRecoveryNeeded(cb ManualRecoveryCallback) Option
- func WithOnRecoveryFailure(cb RecoveryFailureCallback) Option
- func WithOnRecoverySuccess(cb RecoverySuccessCallback) Option
- func WithOnStaleRecoveryCleared(cb StaleRecoveryClearedCallback) Option
- func WithRecoveryBackoff(v time.Duration) Option
- func WithScheduler(v corescheduler.TaskRegistrar) Option
- func WithStaleRecoveryCleanupSchedule[T interface{ ... }](v T) Option
- func WithStaleRecoveryTimeout(v time.Duration) Option
- type RecoveryFailureCallback
- type RecoveryStrategy
- type RecoverySuccessCallback
- type RecoveryTimeoutMonitor
- type RecoveryTimeoutMonitorConfig
- type Registry
- func (r *Registry) Clear()
- func (r *Registry) ConsumerCount(stream string) int
- func (r *Registry) ConsumerNames(stream string) iter.Seq[string]
- func (r *Registry) GetRecoveryStrategy(name string) RecoveryStrategy
- func (r *Registry) GetResubscribeHandler(stream, consumer string) (func() error, bool)
- func (r *Registry) GetStreamConfig(name string) (jetstream.StreamConfig, bool)
- func (r *Registry) GetStreamSubscriptions(stream string) []subscriptionEntry
- func (r *Registry) HasConsumer(stream, consumer string) bool
- func (r *Registry) HasStream(name string) bool
- func (r *Registry) RegisterResubscribeHandler(stream, consumer string, handler func() error)
- func (r *Registry) RegisterStream(name string, cfg jetstream.StreamConfig, strategy RecoveryStrategy)
- func (r *Registry) RegisterSubscription(stream, consumer string, handler broker.SubscriberHandler, ...) error
- func (r *Registry) StreamCount() int
- func (r *Registry) StreamNames() iter.Seq[string]
- func (r *Registry) UnregisterStream(name string)
- func (r *Registry) UnregisterSubscription(stream, consumer string)
- type StaleRecoveryClearedCallback
- type StreamDeletedAdvisory
- type StreamOption
- type Supervisor
- type SupervisorConfig
Constants ¶
const ( // DefaultMaxRecoveryAttempts is the default maximum number of recovery attempts. DefaultMaxRecoveryAttempts = 3 // DefaultRecoveryBackoff is the default base backoff duration between recovery attempts. // Actual backoff is calculated as backoff * attemptNumber. DefaultRecoveryBackoff = 5 * time.Second // DefaultStaleRecoveryTimeout is the default timeout after which a recovery mark is // considered stale and will be cleared. DefaultStaleRecoveryTimeout = 20 * time.Minute )
Default configuration values for recovery manager.
Variables ¶
var ( // ErrStreamNotRegistered is returned by [Manager.Subscribe] and // [Registry.RegisterSubscription] when the stream has not been // registered via [Manager.RegisterStream]. ErrStreamNotRegistered = errors.New("stream not registered") // ErrConsumerNotRegistered is returned when attempting to operate on a // consumer that has not been registered with the [Manager]. ErrConsumerNotRegistered = errors.New("consumer not registered") // ErrStreamAlreadyRegistered is returned when attempting to register a // stream that is already registered. ErrStreamAlreadyRegistered = errors.New("stream already registered") // ErrRecoveryInProgress is returned when a recovery operation is already // in progress for the specified stream. ErrRecoveryInProgress = errors.New("recovery already in progress") // ErrMaxRecoveryAttemptsExceeded is returned when the maximum number of // recovery attempts (configured via [WithMaxRecoveryAttempts]) has been // exceeded. ErrMaxRecoveryAttemptsExceeded = errors.New("max recovery attempts exceeded") // ErrManagerClosed is returned by [Manager.Start], [Manager.Subscribe], // [Manager.RegisterStream], and [Manager.CreateStream] when the // [Manager] has been closed via [Manager.Close]. ErrManagerClosed = errors.New("manager is closed") // ErrNilJetStream is returned by [New] when a nil NATS provider is passed. ErrNilJetStream = errors.New("jetstream instance is required") // ErrNilNatsConn is returned when a nil NATS connection is provided. ErrNilNatsConn = errors.New("nats connection is required") // ErrInvalidStreamConfig is returned by [Manager.RegisterStream] and // [Manager.CreateStream] when the stream configuration has an empty name. ErrInvalidStreamConfig = errors.New("invalid stream configuration") // ErrInvalidConsumerConfig is returned by [Manager.Subscribe] and // [Registry.RegisterSubscription] when the consumer name is empty. ErrInvalidConsumerConfig = errors.New("invalid consumer configuration") )
Functions ¶
This section is empty.
Types ¶
type AdvisoryListener ¶
type AdvisoryListener struct {
// contains filtered or unexported fields
}
AdvisoryListener subscribes to JetStream advisory events for stream and consumer deletion. When a deletion event is received for a registered stream or consumer, it triggers recovery through the Supervisor.
All exported methods are safe for concurrent use.
func NewAdvisoryListener ¶
func NewAdvisoryListener(cfg AdvisoryListenerConfig) *AdvisoryListener
NewAdvisoryListener creates a new AdvisoryListener.
func (*AdvisoryListener) Start ¶
func (a *AdvisoryListener) Start() error
Start subscribes to JetStream advisory events. Call Stop to unsubscribe when done.
func (*AdvisoryListener) Stop ¶
func (a *AdvisoryListener) Stop() error
Stop unsubscribes from all advisory events and drains pending messages.
type AdvisoryListenerConfig ¶
type AdvisoryListenerConfig struct {
NatsConn *nats.Conn
Registry *Registry
Supervisor *Supervisor
Logger *slog.Logger
}
AdvisoryListenerConfig holds configuration for the AdvisoryListener.
type ConsumerDeletedAdvisory ¶
type ConsumerDeletedAdvisory struct {
Type string `json:"type"`
ID string `json:"id"`
Time string `json:"time"`
Stream string `json:"stream"`
Consumer string `json:"consumer"`
Domain string `json:"domain,omitempty"`
}
ConsumerDeletedAdvisory represents the JetStream advisory event for consumer deletion.
type HealthMonitor ¶
type HealthMonitor struct {
// contains filtered or unexported fields
}
HealthMonitor performs health checks on registered streams and consumers. It serves as a fallback mechanism to catch deletions that may have been missed by the AdvisoryListener (e.g., during NATS reconnection or network issues).
The monitor is designed to be used with an external scheduler. Call HealthMonitor.Run to perform a single health check cycle.
func NewHealthMonitor ¶
func NewHealthMonitor(cfg HealthMonitorConfig) *HealthMonitor
NewHealthMonitor creates a new HealthMonitor.
type HealthMonitorConfig ¶
type HealthMonitorConfig struct {
JetStream jetstream.JetStream
Registry *Registry
Supervisor *Supervisor
Logger *slog.Logger
}
HealthMonitorConfig holds configuration for the HealthMonitor.
type ManagedSubscription ¶
type ManagedSubscription struct {
// contains filtered or unexported fields
}
ManagedSubscription represents a subscription managed by the recovery Manager. It wraps a broker.Subscriber and enables automatic recovery when the underlying consumer or stream is deleted.
All exported methods are safe for concurrent use.
func (*ManagedSubscription) Closed ¶
func (s *ManagedSubscription) Closed() <-chan struct{}
Closed returns a channel that closes when the subscription has fully stopped.
func (*ManagedSubscription) Consumer ¶
func (s *ManagedSubscription) Consumer() string
Consumer returns the name of the consumer.
func (*ManagedSubscription) IsClosed ¶
func (s *ManagedSubscription) IsClosed() bool
IsClosed returns true if the subscription has been closed.
func (*ManagedSubscription) Stream ¶
func (s *ManagedSubscription) Stream() string
Stream returns the name of the stream this subscription is attached to.
func (*ManagedSubscription) Subject ¶
func (s *ManagedSubscription) Subject() string
Subject returns the subject/topic for this subscription.
func (*ManagedSubscription) Unsubscribe ¶
func (s *ManagedSubscription) Unsubscribe()
Unsubscribe stops the subscription and removes it from the manager. After calling Unsubscribe, the subscription will no longer be recovered if the consumer is deleted.
type Manager ¶
type Manager struct {
// contains filtered or unexported fields
}
Manager orchestrates automatic recovery for JetStream streams and consumers. It manages the lifecycle of streams, consumers, and subscriptions, automatically recovering them when deletion is detected via AdvisoryListener or HealthMonitor.
Background tasks (health checks, stale recovery cleanup) are designed to be run via an external scheduler. Use Manager.RunHealthCheckCycle and Manager.RunStaleRecoveryCleanup methods with a scheduler TaskConfig.
All exported methods are safe for concurrent use.
func New ¶
func New(provider *natsprovider.Nats, opts ...Option) (*Manager, error)
New creates a new Manager with the given NATS provider and options.
Example:
provider, _ := natsprovider.New(natsConn)
manager, _ := recovery.New(provider,
recovery.WithMaxRecoveryAttempts(3),
recovery.WithStaleRecoveryTimeout(20 * time.Minute),
)
func (*Manager) Close ¶
func (m *Manager) Close()
Close stops the manager and all its components. Active subscriptions are drained before closing.
func (*Manager) CreateStream ¶
func (m *Manager) CreateStream(ctx context.Context, cfg jetstream.StreamConfig, opts ...StreamOption) (jetstream.Stream, error)
CreateStream creates or updates a stream and registers it for recovery.
Example:
stream, err := manager.CreateStream(ctx, jetstream.StreamConfig{
Name: "ORDERS",
Subjects: []string{"orders.>"},
})
func (*Manager) GetRegistry ¶
GetRegistry returns the internal registry. Useful for testing and advanced use cases.
func (*Manager) GetSupervisor ¶
func (m *Manager) GetSupervisor() *Supervisor
GetSupervisor returns the internal supervisor. Useful for testing and advanced use cases.
func (*Manager) RegisterHealthCheckSchedulerFunc ¶
RegisterHealthCheckSchedulerFunc returns a function for use by a scheduler and marks health check as scheduler-managed. After calling this method, direct calls to RunHealthCheckCycle will return corescheduler.ErrSchedulerManaged.
func (*Manager) RegisterStaleCleanupSchedulerFunc ¶
RegisterStaleCleanupSchedulerFunc returns a function for use by a scheduler and marks stale cleanup as scheduler-managed. After calling this method, direct calls to RunStaleRecoveryCleanup will return corescheduler.ErrSchedulerManaged.
func (*Manager) RegisterStream ¶
func (m *Manager) RegisterStream(cfg jetstream.StreamConfig, opts ...StreamOption) error
RegisterStream registers a stream configuration for recovery. The stream will be automatically recovered if it is deleted.
Example:
manager.RegisterStream(jetstream.StreamConfig{
Name: "ORDERS",
Subjects: []string{"orders.>"},
}, recovery.WithRecoveryStrategy(recovery.RecoveryStrategyAuto))
func (*Manager) RunHealthCheckCycle ¶
RunHealthCheckCycle executes a single health check cycle. This method is designed to be called manually for one-time health check. If the function is registered with a scheduler, this method returns corescheduler.ErrSchedulerManaged.
func (*Manager) RunStaleRecoveryCleanup ¶
RunStaleRecoveryCleanup executes a single stale recovery cleanup cycle. This method is designed to be called manually for one-time cleanup. If the function is registered with a scheduler, this method returns corescheduler.ErrSchedulerManaged.
func (*Manager) Start ¶
Start begins the advisory listener for instant deletion detection. Background tasks (health checks, stale cleanup) should be registered with an external scheduler using RunHealthCheckCycle and RunStaleRecoveryCleanup.
Call Close to stop the manager.
func (*Manager) Subscribe ¶
func (m *Manager) Subscribe( ctx context.Context, stream string, consumerName string, handler broker.SubscriberHandler, factory broker.SubscriberFactory, ) (*ManagedSubscription, error)
Subscribe creates a managed subscription with automatic recovery. When the consumer is deleted, it will be automatically recreated and the subscription re-established.
The factory parameter should be created using natsprovider.SubscriberWithConsumer or similar factory functions. The consumerName is required for recovery tracking.
Example:
sub, err := manager.Subscribe(ctx, "ORDERS", "order-processor", handler,
natsprovider.SubscriberWithConsumer(&jetstream.ConsumerConfig{
Durable: "order-processor",
}),
)
func (*Manager) UnregisterStream ¶
UnregisterStream removes a stream from recovery management. The stream and its consumers will no longer be recovered if deleted.
type ManualRecoveryCallback ¶
ManualRecoveryCallback is invoked for streams configured with RecoveryStrategyManual. The event parameter carries the advisory payload (may be nil for health-check triggers).
type Option ¶
type Option func(o *options)
Option is a functional option for configuring options.
func WithHealthCheckSchedule ¶
WithHealthCheckSchedule sets the healthCheckSchedule option.
func WithMaxRecoveryAttempts ¶
WithMaxRecoveryAttempts sets the maxRecoveryAttempts option.
func WithOnManualRecoveryNeeded ¶
func WithOnManualRecoveryNeeded(cb ManualRecoveryCallback) Option
WithOnManualRecoveryNeeded sets the callback for manual recovery notification.
func WithOnRecoveryFailure ¶
func WithOnRecoveryFailure(cb RecoveryFailureCallback) Option
WithOnRecoveryFailure sets the callback for failed recovery.
func WithOnRecoverySuccess ¶
func WithOnRecoverySuccess(cb RecoverySuccessCallback) Option
WithOnRecoverySuccess sets the callback for successful recovery.
func WithOnStaleRecoveryCleared ¶
func WithOnStaleRecoveryCleared(cb StaleRecoveryClearedCallback) Option
WithOnStaleRecoveryCleared sets the callback for stale recovery cleanup.
func WithRecoveryBackoff ¶
WithRecoveryBackoff sets the recoveryBackoff option.
func WithScheduler ¶
func WithScheduler(v corescheduler.TaskRegistrar) Option
WithScheduler sets the scheduler option.
func WithStaleRecoveryCleanupSchedule ¶
WithStaleRecoveryCleanupSchedule sets the staleRecoveryCleanupSchedule option.
func WithStaleRecoveryTimeout ¶
WithStaleRecoveryTimeout sets the staleRecoveryTimeout option.
type RecoveryFailureCallback ¶
RecoveryFailureCallback is invoked when recovery fails after all retry attempts. The consumer parameter is empty for stream-level recovery.
type RecoveryStrategy ¶
type RecoveryStrategy int
RecoveryStrategy defines how the system responds when a stream or consumer is deleted.
const ( // RecoveryStrategyAuto enables automatic recovery with exponential backoff. // When deletion is detected, the system automatically recreates the stream // and consumers from saved configuration. This is the default strategy. // // Use for critical streams that must be restored automatically. RecoveryStrategyAuto RecoveryStrategy = iota // RecoveryStrategyManual notifies via the OnManualRecoveryNeeded callback // but does not attempt automatic recovery. Useful for streams that require // human review before restoration (e.g., streams with special configuration, // external dependencies, or compliance requirements). RecoveryStrategyManual // RecoveryStrategySkip ignores deletion events entirely. No recovery attempt // is made and no notification is sent. // // Use for: // - Ephemeral streams (temporary data, acceptable loss) // - Externally-managed streams (created/managed by another service) // - Streams that should not exist after deletion (intentional cleanup) RecoveryStrategySkip )
func (RecoveryStrategy) IsAuto ¶
func (s RecoveryStrategy) IsAuto() bool
IsAuto returns true if the strategy is automatic recovery.
func (RecoveryStrategy) IsManual ¶
func (s RecoveryStrategy) IsManual() bool
IsManual returns true if the strategy is manual recovery.
func (RecoveryStrategy) IsSkip ¶
func (s RecoveryStrategy) IsSkip() bool
IsSkip returns true if the strategy is to skip recovery.
func (RecoveryStrategy) String ¶
func (s RecoveryStrategy) String() string
String returns a string representation of the recovery strategy.
type RecoverySuccessCallback ¶
type RecoverySuccessCallback func(stream, consumer string)
RecoverySuccessCallback is invoked after a stream or consumer is successfully recovered. The consumer parameter is empty for stream-level recovery.
type RecoveryTimeoutMonitor ¶
type RecoveryTimeoutMonitor struct {
// contains filtered or unexported fields
}
RecoveryTimeoutMonitor checks for stale recovery marks and clears them via Supervisor.ClearStaleRecoveries. A recovery mark may become stale due to:
- Server restart during recovery process
- Code bug (panic, deadlock, etc.)
- Network issues preventing recovery completion
Without cleanup, stale marks would block stream recovery permanently.
The monitor is designed to be used with an external scheduler. Call RecoveryTimeoutMonitor.Run to perform a single cleanup cycle.
func NewRecoveryTimeoutMonitor ¶
func NewRecoveryTimeoutMonitor(cfg RecoveryTimeoutMonitorConfig) *RecoveryTimeoutMonitor
NewRecoveryTimeoutMonitor creates a new RecoveryTimeoutMonitor.
func (*RecoveryTimeoutMonitor) GetTimeout ¶
func (t *RecoveryTimeoutMonitor) GetTimeout() time.Duration
GetTimeout returns the configured timeout duration.
type RecoveryTimeoutMonitorConfig ¶
type RecoveryTimeoutMonitorConfig struct {
Supervisor *Supervisor
Logger *slog.Logger
Timeout time.Duration // How long before a recovery mark is considered stale
}
RecoveryTimeoutMonitorConfig holds configuration for the RecoveryTimeoutMonitor.
type Registry ¶
type Registry struct {
// contains filtered or unexported fields
}
Registry stores stream and subscription configurations for recovery. All exported methods are safe for concurrent use; internal state is protected by a sync.RWMutex.
func (*Registry) Clear ¶
func (r *Registry) Clear()
Clear removes all registered streams and subscriptions.
func (*Registry) ConsumerCount ¶
ConsumerCount returns the number of registered consumers for a stream.
func (*Registry) ConsumerNames ¶
ConsumerNames returns an iterator over all consumer names for a stream.
func (*Registry) GetRecoveryStrategy ¶
func (r *Registry) GetRecoveryStrategy(name string) RecoveryStrategy
GetRecoveryStrategy returns the recovery strategy for a stream. Returns RecoveryStrategyAuto if the stream is not registered.
func (*Registry) GetResubscribeHandler ¶
GetResubscribeHandler returns the resubscribe handler for a consumer.
func (*Registry) GetStreamConfig ¶
func (r *Registry) GetStreamConfig(name string) (jetstream.StreamConfig, bool)
GetStreamConfig returns the stream configuration if registered.
func (*Registry) GetStreamSubscriptions ¶
GetStreamSubscriptions returns all subscription entries for a stream. Returns a copy to avoid holding the lock during iteration.
func (*Registry) HasConsumer ¶
HasConsumer returns true if the consumer is registered for the stream.
func (*Registry) RegisterResubscribeHandler ¶
RegisterResubscribeHandler registers a function to recreate a subscription. This function is called during recovery to restore the subscription.
func (*Registry) RegisterStream ¶
func (r *Registry) RegisterStream(name string, cfg jetstream.StreamConfig, strategy RecoveryStrategy)
RegisterStream adds a stream configuration to the registry. If a stream with the same name already exists, it will be updated.
func (*Registry) RegisterSubscription ¶
func (r *Registry) RegisterSubscription(stream, consumer string, handler broker.SubscriberHandler, factory broker.SubscriberFactory) error
RegisterSubscription adds a subscription to the registry for recovery. The stream must be registered before registering subscriptions.
func (*Registry) StreamCount ¶
StreamCount returns the number of registered streams.
func (*Registry) StreamNames ¶
StreamNames returns an iterator over all registered stream names.
func (*Registry) UnregisterStream ¶
UnregisterStream removes a stream and all its subscriptions from the registry.
func (*Registry) UnregisterSubscription ¶
UnregisterSubscription removes a subscription from the registry.
type StaleRecoveryClearedCallback ¶
type StaleRecoveryClearedCallback func(stream string)
StaleRecoveryClearedCallback is invoked when a recovery mark exceeds the stale timeout and is cleared to allow future recovery attempts.
type StreamDeletedAdvisory ¶
type StreamDeletedAdvisory struct {
Type string `json:"type"`
ID string `json:"id"`
Time string `json:"time"`
Stream string `json:"stream"`
Domain string `json:"domain,omitempty"`
}
StreamDeletedAdvisory represents the JetStream advisory event for stream deletion.
type StreamOption ¶
type StreamOption func(*streamOptions)
StreamOption configures stream registration.
func WithRecoveryStrategy ¶
func WithRecoveryStrategy(strategy RecoveryStrategy) StreamOption
WithRecoveryStrategy sets the recovery strategy for a stream.
type Supervisor ¶
type Supervisor struct {
// contains filtered or unexported fields
}
Supervisor handles stream and consumer recovery with linear backoff (backoff * attempt). It coordinates recovery operations and prevents concurrent recovery of the same stream using an internal recovering-state map protected by a mutex.
All exported methods are safe for concurrent use.
func NewSupervisor ¶
func NewSupervisor(cfg SupervisorConfig) *Supervisor
NewSupervisor creates a new Supervisor with the given configuration. The supervisor owns a detached background context (canceled by [Supervisor.Stop]) because its watcher goroutines must outlive any request-scoped context the caller might have. Termination is honest: Stop() invokes the stored cancel — no goroutine leaks once the supervisor is asked to stop.
func (*Supervisor) ClearStaleRecoveries ¶
func (s *Supervisor) ClearStaleRecoveries(timeout time.Duration) []string
ClearStaleRecoveries removes recovery marks older than timeout, unblocking future recovery attempts for those streams. Returns the names of cleared streams. Invokes OnStaleCleared callback for each cleared stream.
func (*Supervisor) Close ¶
func (s *Supervisor) Close()
Close stops the supervisor and waits for every in-flight recovery goroutine to unwind. Cancel happens first so the recovery loops see their context die and bail out of any in-progress retry; the Wait then blocks until each runStreamRecovery / runConsumerRecovery returns. This makes shutdown observable — callers can rely on Close returning ⇒ no recovery goroutines are still touching state.
func (*Supervisor) GetRecoveringStreams ¶
func (s *Supervisor) GetRecoveringStreams() []string
GetRecoveringStreams returns a list of streams currently being recovered.
func (*Supervisor) RecoverConsumer ¶
func (s *Supervisor) RecoverConsumer(stream, consumer string, event any)
RecoverConsumer initiates recovery of a deleted consumer according to its stream's RecoveryStrategy. For RecoveryStrategyAuto, recovery runs asynchronously in a new goroutine with retries. The event parameter carries the advisory payload (may be nil for health-check triggers).
func (*Supervisor) RecoverStream ¶
func (s *Supervisor) RecoverStream(streamName string, event any)
RecoverStream initiates recovery of a deleted stream according to its RecoveryStrategy. For RecoveryStrategyAuto, recovery runs asynchronously in a new goroutine with retries. The event parameter carries the advisory payload (may be nil for health-check triggers). If recovery is already in progress for this stream, the call is a no-op.
type SupervisorConfig ¶
type SupervisorConfig struct {
JetStream jetstream.JetStream
Registry *Registry
Logger *slog.Logger
MaxAttempts int
Backoff time.Duration
OnRecoverySuccess func(stream, consumer string)
OnRecoveryFailure func(stream, consumer string, err error)
OnManualNeeded func(stream string, event any)
OnStaleCleared func(stream string)
}
SupervisorConfig holds configuration for the Supervisor.