Skip to content

Commit

Permalink
feat(pkg): add recovery middleware to retry non-business error
Browse files Browse the repository at this point in the history
  • Loading branch information
iyear committed Nov 20, 2023
1 parent f8d7fe5 commit 6993209
Showing 1 changed file with 62 additions and 0 deletions.
62 changes: 62 additions & 0 deletions pkg/recovery/recovery.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,62 @@
package recovery

import (
"context"
"time"

"github.com/cenkalti/backoff/v4"
"github.com/go-faster/errors"
"github.com/gotd/td/bin"
"github.com/gotd/td/telegram"
"github.com/gotd/td/tg"
"github.com/gotd/td/tgerr"
"go.uber.org/zap"

"github.com/iyear/tdl/pkg/logger"
)

type recovery struct {
ctx context.Context
backoff backoff.BackOff
}

func New(ctx context.Context, backoff backoff.BackOff) telegram.Middleware {
return &recovery{
ctx: ctx,
backoff: backoff,
}
}

func (r *recovery) Handle(next tg.Invoker) telegram.InvokeFunc {
return func(ctx context.Context, input bin.Encoder, output bin.Decoder) error {
log := logger.From(ctx)

return backoff.RetryNotify(func() error {
if err := next.Invoke(ctx, input, output); err != nil {
if r.shouldRecover(err) {
return errors.Wrap(err, "recover")
}

return backoff.Permanent(err)
}

return nil
}, r.backoff, func(err error, duration time.Duration) {
log.Debug("Wait for connection recovery", zap.Error(err), zap.Duration("duration", duration))
})
}
}

func (r *recovery) shouldRecover(err error) bool {
// context in recovery is used to stop recovery process by external os signal, otherwise we will wait till max retries when user press ctrl+c
select {
case <-r.ctx.Done():
return false
default:
}

// we try recover when encountered any error that is not telegram business error
_, ok := tgerr.As(err)

return !ok
}

0 comments on commit 6993209

Please sign in to comment.