-
Notifications
You must be signed in to change notification settings - Fork 1
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
feat: add batch middleware for logging and error handling in batched …
…jetconsumer
- Loading branch information
Showing
1 changed file
with
77 additions
and
0 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,77 @@ | ||
package jetconsumer | ||
|
||
import ( | ||
"context" | ||
"log/slog" | ||
|
||
"github.com/nats-io/nats.go/jetstream" | ||
) | ||
|
||
type BatchMiddleware func(handler BatchHandler) BatchHandler | ||
|
||
func ChainBatchMiddleware(h BatchHandler, mws ...BatchMiddleware) BatchHandler { | ||
for i := 0; i < len(mws); i++ { | ||
h = mws[i](h) | ||
} | ||
return h | ||
} | ||
|
||
// WithBatchAccessLog returns a middleware that logs access using the provided slog.Logger. | ||
func WithBatchAccessLog(logger *slog.Logger, opts ...AccessLogOption) BatchMiddleware { | ||
params := &accessLogParams{ | ||
level: slog.LevelInfo, | ||
message: "", | ||
} | ||
for _, opt := range opts { | ||
opt(params) | ||
} | ||
return func(next BatchHandler) BatchHandler { | ||
return BatchHandlerFunc(func(ctx context.Context, batch jetstream.MessageBatch) error { | ||
b := accessLogBatch{MessageBatch: batch, ch: make(chan jetstream.Msg)} | ||
var ( | ||
log *slog.Logger | ||
seq uint | ||
) | ||
go func() { | ||
for msg := range b.Messages() { | ||
if seq == 0 { | ||
log = logger.With("subject", msg.Subject()) | ||
log.Info("batch started") | ||
} | ||
log.Debug("batch message", "subject", msg.Subject(), "headers", msg.Headers(), "sequence", seq) | ||
b.ch <- msg | ||
} | ||
log.Info("batch finished", "messages", seq) | ||
}() | ||
return next.Serve(ctx, &b) | ||
}) | ||
} | ||
} | ||
|
||
var _ jetstream.MessageBatch = (*accessLogBatch)(nil) | ||
|
||
type accessLogBatch struct { | ||
jetstream.MessageBatch | ||
ch chan jetstream.Msg | ||
} | ||
|
||
func (b *accessLogBatch) Messages() <-chan jetstream.Msg { | ||
return b.ch | ||
} | ||
|
||
// WithBatchErrorLog returns a middleware that logs errors using the provided logger. | ||
// If propagate is true, the error is propagated to the outer handler. | ||
func WithBatchErrorLog(logger *slog.Logger, propagate bool) BatchMiddleware { | ||
return func(next BatchHandler) BatchHandler { | ||
return BatchHandlerFunc(func(ctx context.Context, batch jetstream.MessageBatch) error { | ||
err := next.Serve(ctx, batch) | ||
if err != nil { | ||
logger.ErrorContext(ctx, "error", "err", err) | ||
if propagate { | ||
return err | ||
} | ||
} | ||
return nil | ||
}) | ||
} | ||
} |