Files
nats.go/jetstream/options.go
Piotr Piotrowski e7ab93ecb8 Add ordered consumer, FetchBytes and Next, rework options
Signed-off-by: Piotr Piotrowski <piotr@synadia.com>
2023-05-23 12:03:02 +02:00

310 lines
9.4 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 (
"fmt"
"time"
)
type pullOptFunc func(*consumeOpts) error
func (fn pullOptFunc) configureConsume(opts *consumeOpts) error {
return fn(opts)
}
func (fn pullOptFunc) configureMessages(opts *consumeOpts) error {
return fn(opts)
}
// WithClientTrace enables request/response API calls tracing
// ClientTrace is used to provide handlers for each event
func WithClientTrace(ct *ClientTrace) JetStreamOpt {
return func(opts *jsOpts) error {
opts.clientTrace = ct
return nil
}
}
// WithPublishAsyncErrHandler sets error handler for async message publish
func WithPublishAsyncErrHandler(cb MsgErrHandler) JetStreamOpt {
return func(opts *jsOpts) error {
opts.publisherOpts.aecb = cb
return nil
}
}
// WithPublishAsyncMaxPending sets the maximum outstanding async publishes that can be inflight at one time.
func WithPublishAsyncMaxPending(max int) JetStreamOpt {
return func(opts *jsOpts) error {
if max < 1 {
return fmt.Errorf("%w: max ack pending should be >= 1", ErrInvalidOption)
}
opts.publisherOpts.maxpa = max
return nil
}
}
// WithPurgeSubject sets a sprecific subject for which messages on a stream will be purged
func WithPurgeSubject(subject string) StreamPurgeOpt {
return func(req *StreamPurgeRequest) error {
req.Subject = subject
return nil
}
}
// WithPurgeSequence is used to set a sprecific sequence number up to which (but not including) messages will be purged from a stream
// Can be combined with [WithPurgeSubject] option, but not with [WithPurgeKeep]
func WithPurgeSequence(sequence uint64) StreamPurgeOpt {
return func(req *StreamPurgeRequest) error {
if req.Keep != 0 {
return fmt.Errorf("%w: both 'keep' and 'sequence' cannot be provided in purge request", ErrInvalidOption)
}
req.Sequence = sequence
return nil
}
}
// WithPurgeKeep sets the number of messages to be kept in the stream after purge.
// Can be combined with [WithPurgeSubject] option, but not with [WithPurgeSequence]
func WithPurgeKeep(keep uint64) StreamPurgeOpt {
return func(req *StreamPurgeRequest) error {
if req.Sequence != 0 {
return fmt.Errorf("%w: both 'keep' and 'sequence' cannot be provided in purge request", ErrInvalidOption)
}
req.Keep = keep
return nil
}
}
// PullMaxMessages limits the number of messages to be fetched from the stream in one request
// If not provided, a default of 100 messages will be used
type PullMaxMessages int
func (max PullMaxMessages) configureConsume(opts *consumeOpts) error {
if max <= 0 {
return fmt.Errorf("%w: maxMessages size must be at least 1", ErrInvalidOption)
}
opts.MaxMessages = int(max)
return nil
}
func (max PullMaxMessages) configureMessages(opts *consumeOpts) error {
if max <= 0 {
return fmt.Errorf("%w: maxMessages size must be at least 1", ErrInvalidOption)
}
opts.MaxMessages = int(max)
return nil
}
// PullExpiry sets timeout on a single batch request, waiting until at least one message is available
type PullExpiry time.Duration
func (exp PullExpiry) configureConsume(opts *consumeOpts) error {
if exp < 0 {
return fmt.Errorf("%w: expires value must be positive", ErrInvalidOption)
}
opts.Expires = time.Duration(exp)
return nil
}
func (exp PullExpiry) configureMessages(opts *consumeOpts) error {
if exp < 0 {
return fmt.Errorf("%w: expires value must be positive", ErrInvalidOption)
}
opts.Expires = time.Duration(exp)
return nil
}
// PullMaxBytes sets max_bytes limit on a fetch request
type PullMaxBytes int
func (max PullMaxBytes) configureConsume(opts *consumeOpts) error {
if max <= 0 {
return fmt.Errorf("%w: max bytes must be greater then 0", ErrInvalidOption)
}
opts.MaxBytes = int(max)
return nil
}
func (max PullMaxBytes) configureMessages(opts *consumeOpts) error {
if max <= 0 {
return fmt.Errorf("%w: max bytes must be greater then 0", ErrInvalidOption)
}
opts.MaxBytes = int(max)
return nil
}
// PullThresholdMessages sets the message count on which Consume will trigger
// new pull request to the server. Defaults to 50% of MaxMessages.
type PullThresholdMessages int
func (t PullThresholdMessages) configureConsume(opts *consumeOpts) error {
opts.ThresholdMessages = int(t)
return nil
}
// PullThresholdBytes sets the byte count on which Consume will trigger
// new pull request to the server. Defaults to 50% of MaxBytes (if set).
type PullThresholBytes int
func (t PullThresholBytes) configureConsume(opts *consumeOpts) error {
opts.ThresholdBytes = int(t)
return nil
}
// PullHeartbeat sets the idle heartbeat duration for a pull subscription
// If a client does not receive a heartbeat message from a stream for more
// than the idle heartbeat setting, the subscription will be removed
// and error will be passed to the message handler
type PullHeartbeat time.Duration
func (hb PullHeartbeat) configureConsume(opts *consumeOpts) error {
hbTime := time.Duration(hb)
if hbTime < 1*time.Second || hbTime > 30*time.Second {
return fmt.Errorf("%w: idle_heartbeat value must be within 1s-30s range", ErrInvalidOption)
}
opts.Heartbeat = hbTime
return nil
}
func (hb PullHeartbeat) configureMessages(opts *consumeOpts) error {
hbTime := time.Duration(hb)
if hbTime < 1*time.Second || hbTime > 30*time.Second {
return fmt.Errorf("%w: idle_heartbeat value must be within 1s-30s range", ErrInvalidOption)
}
opts.Heartbeat = hbTime
return nil
}
// ConsumeErrHandler sets custom error handler invoked when an error was encountered while consuming messages
// It will be invoked for both terminal (Consumer Deleted, invalid request body) and non-terminal (e.g. missing heartbeats) errors
func ConsumeErrHandler(cb ConsumeErrHandlerFunc) PullConsumeOpt {
return pullOptFunc(func(cfg *consumeOpts) error {
cfg.ErrHandler = cb
return nil
})
}
// ConsumeErrHandler sets custom error handler invoked when an error was encountered while consuming messages
// It will be invoked for both terminal (Consumer Deleted, invalid request body) and non-terminal (e.g. missing heartbeats) errors
func WithMessagesErrOnMissingHeartbeat(hbErr bool) PullMessagesOpt {
return pullOptFunc(func(cfg *consumeOpts) error {
cfg.ReportMissingHeartbeats = hbErr
return nil
})
}
// FetchMaxWait sets custom timeout fir fetching predefined batch of messages
func FetchMaxWait(timeout time.Duration) FetchOpt {
return func(req *pullRequest) error {
if timeout <= 0 {
return fmt.Errorf("%w: timeout value must be greater than 0", ErrInvalidOption)
}
req.Expires = timeout
return nil
}
}
// WithDeletedDetails can be used to display the information about messages deleted from a stream on a stream info request
func WithDeletedDetails(deletedDetails bool) StreamInfoOpt {
return func(req *streamInfoRequest) error {
req.DeletedDetails = deletedDetails
return nil
}
}
// WithSubjectFilter can be used to display the information about messages stored on given subjects
func WithSubjectFilter(subject string) StreamInfoOpt {
return func(req *streamInfoRequest) error {
req.SubjectFilter = subject
return nil
}
}
// WithNakDelay can be used to specify the duration after which the message should be redelivered
func WithNakDelay(delay time.Duration) NakOpt {
return func(opts *ackOpts) error {
opts.nakDelay = delay
return nil
}
}
// WithMsgID sets the message ID used for deduplication.
func WithMsgID(id string) PublishOpt {
return func(opts *pubOpts) error {
opts.id = id
return nil
}
}
// WithExpectStream sets the expected stream to respond from the publish.
func WithExpectStream(stream string) PublishOpt {
return func(opts *pubOpts) error {
opts.stream = stream
return nil
}
}
// WithExpectLastSequence sets the expected sequence in the response from the publish.
func WithExpectLastSequence(seq uint64) PublishOpt {
return func(opts *pubOpts) error {
opts.lastSeq = &seq
return nil
}
}
// WithExpectLastSequencePerSubject sets the expected sequence per subject in the response from the publish.
func WithExpectLastSequencePerSubject(seq uint64) PublishOpt {
return func(opts *pubOpts) error {
opts.lastSubjectSeq = &seq
return nil
}
}
// ExpectLastMsgId sets the expected last msgId in the response from the publish.
func WithExpectLastMsgID(id string) PublishOpt {
return func(opts *pubOpts) error {
opts.lastMsgID = id
return nil
}
}
// WithRetryWait sets the retry wait time when ErrNoResponders is encountered.
func WithRetryWait(dur time.Duration) PublishOpt {
return func(opts *pubOpts) error {
opts.retryWait = dur
return nil
}
}
// WithRetryAttempts sets the retry number of attempts when ErrNoResponders is encountered.
func WithRetryAttempts(num int) PublishOpt {
return func(opts *pubOpts) error {
opts.retryAttempts = num
return nil
}
}
// WithStallWait sets the max wait when the producer becomes stall producing messages.
func WithStallWait(ttl time.Duration) PublishOpt {
return func(opts *pubOpts) error {
if ttl <= 0 {
return fmt.Errorf("%w: stall wait should be more than 0", ErrInvalidOption)
}
opts.stallWait = ttl
return nil
}
}