81 lines
1.7 KiB
Go
81 lines
1.7 KiB
Go
package eventbus
|
|
|
|
import (
|
|
"context"
|
|
"time"
|
|
|
|
"lingniu-vehicle-ingest/go/vehicle-gateway/internal/envelope"
|
|
)
|
|
|
|
type RetryConfig struct {
|
|
Attempts int
|
|
Backoff time.Duration
|
|
AttemptTimeout time.Duration
|
|
}
|
|
|
|
type RetryingSink struct {
|
|
delegate Sink
|
|
cfg RetryConfig
|
|
}
|
|
|
|
func NewRetryingSink(delegate Sink, cfg RetryConfig) *RetryingSink {
|
|
if delegate == nil {
|
|
panic("retry delegate sink must not be nil")
|
|
}
|
|
if cfg.Attempts <= 0 {
|
|
cfg.Attempts = 1
|
|
}
|
|
return &RetryingSink{delegate: delegate, cfg: cfg}
|
|
}
|
|
|
|
func (s *RetryingSink) PublishRaw(ctx context.Context, env envelope.FrameEnvelope) error {
|
|
return s.withRetry(ctx, func(attemptCtx context.Context) error {
|
|
return s.delegate.PublishRaw(attemptCtx, env)
|
|
})
|
|
}
|
|
|
|
func (s *RetryingSink) PublishUnified(ctx context.Context, env envelope.FrameEnvelope) error {
|
|
return s.withRetry(ctx, func(attemptCtx context.Context) error {
|
|
return s.delegate.PublishUnified(attemptCtx, env)
|
|
})
|
|
}
|
|
|
|
func (s *RetryingSink) Close() error {
|
|
return s.delegate.Close()
|
|
}
|
|
|
|
func (s *RetryingSink) withRetry(ctx context.Context, publish func(context.Context) error) error {
|
|
var lastErr error
|
|
for attempt := 1; attempt <= s.cfg.Attempts; attempt++ {
|
|
attemptCtx := ctx
|
|
cancel := func() {}
|
|
if s.cfg.AttemptTimeout > 0 {
|
|
attemptCtx, cancel = context.WithTimeout(ctx, s.cfg.AttemptTimeout)
|
|
}
|
|
err := publish(attemptCtx)
|
|
cancel()
|
|
if err == nil {
|
|
return nil
|
|
}
|
|
lastErr = err
|
|
if ctx.Err() != nil {
|
|
return ctx.Err()
|
|
}
|
|
if attempt == s.cfg.Attempts {
|
|
break
|
|
}
|
|
if s.cfg.Backoff > 0 {
|
|
timer := time.NewTimer(s.cfg.Backoff)
|
|
select {
|
|
case <-ctx.Done():
|
|
if !timer.Stop() {
|
|
<-timer.C
|
|
}
|
|
return ctx.Err()
|
|
case <-timer.C:
|
|
}
|
|
}
|
|
}
|
|
return lastErr
|
|
}
|