Junior — Senior
Adding retry mechanism in DistributiveGet
livecode
Task condition
It is necessary to improve the DistributiveGet function by implementing retries upon any error except ErrNotFound, until the value is obtained.
func DistributiveGet(ctx context.Context, addresses []string, key string) (string, error) {
if ctx.Err() != nil {
return "", ctx.Err()
}
var wg sync.WaitGroup
wg.Add(len(addresses))
valueCh := make(chan string, 1)
notFoundErrCh := make(chan error, 1)
go func() {
wg.Wait()
close(valueCh)
close(notFoundErrCh)
}()
for _, address := range addresses {
go func(address string) {
defer wg.Done()
for i := 0; i < 3; i++ {
value, err := Get(ctx, address, key)
if errors.Is(err, ErrNotFound) {
select {
case notFoundErrCh <- err:
default:
}
return
}
if err != nil {
select {
case <-valueCh:
return
default:
time.Sleep(100 * time.Millisecond)
continue
}
}
select {
case valueCh <- value:
default:
}
return
}
}(address)
}
select {
case v, ok := <-valueCh:
if !ok {
return "", ErrDistributedGetFailed
}
return v, nil
case err, ok := <-notFoundErrCh:
if !ok {
return "", ErrDistributedGetFailed
}
return "", err
}
}