Closed kamilsk closed 5 years ago
The concept:
ctx := pipeline.Context()
err := retry.New().
Before(retry.Retry(ctx.Done(), action.Login, login.Strategies...)).
Try(action.DoSomething).
Try(action.DoSomethingElse).
Parallel().
Try(transaction.Commit).
Otherwise(transaction.Rollback).
Finally(connection.Close).
Do(ctx.Done())
type Retrier struct {
parallel []retry.Action
sequence []retry.Action
before, otherwise, finally func() error
}
func (r *Retrier) Parallel() *Retrier {
r.parallel = append(r.parallel, r.sequence...)
r.sequence = []retry.Action{}
return r
}
func (r *Retrier) Try(action retry.Action) *Retrier {
r.sequence = append(r.sequence, action)
return r
}
func (r *Retrier) Do(deadline <-chan struct{}, strategies ...strategy.Strategy) error {
ch := make(chan error, 1)
go func() {
err := <-ch
if r.finally != nil {
err := r.finally
...
}
close(...)
}()
if r.before != nil {
r.before()
}
for _, action := range r.parallel {
go func() {
ch <- retry.Retry(deadline, action, strategies...)
}()
}
...
return nil
}
Maybe is it better to use next semantic:
Try(action.DoSomething, retry.Parallel(action.DoSomethingElse, action.DoSomethingMore)).
good function approach: https://www.calhoun.io/using-functional-options-instead-of-method-chaining-in-go/
Retry(
Before(Do).Try(Action, Parallel(Action, ...), ...).With(Strategies...).Catch(Do).Finally(Do)
)
intestigate https://github.com/lazada/awg
Repeat(Action).Until(...).Success(callback).Failure(callback)
Retrier.Before.Try.Otherwise.Finally