remove retryFunc

It's now in the communicator package
This commit is contained in:
James Bardin 2018-02-14 18:21:26 -05:00
parent bc90eca19f
commit f5b8091e2c
2 changed files with 4 additions and 138 deletions

View File

@ -9,7 +9,6 @@ import (
"log" "log"
"os" "os"
"strings" "strings"
"sync/atomic"
"time" "time"
"github.com/hashicorp/terraform/communicator" "github.com/hashicorp/terraform/communicator"
@ -159,7 +158,7 @@ func runScripts(
scripts []io.ReadCloser) error { scripts []io.ReadCloser) error {
// Wrap out context in a cancelation function that we use to // Wrap out context in a cancelation function that we use to
// kill the connection. // kill the connection.
ctx, cancelFunc := context.WithCancel(ctx) ctx, cancelFunc := context.WithTimeout(ctx, comm.Timeout())
defer cancelFunc() defer cancelFunc()
// Wait for the context to end and then disconnect // Wait for the context to end and then disconnect
@ -169,7 +168,7 @@ func runScripts(
}() }()
// Wait and retry until we establish the connection // Wait and retry until we establish the connection
err := retryFunc(ctx, comm.Timeout(), func() error { err := communicator.Retry(ctx, func() error {
err := comm.Connect(o) err := comm.Connect(o)
return err return err
}) })
@ -187,7 +186,8 @@ func runScripts(
go copyOutput(o, errR, errDoneCh) go copyOutput(o, errR, errDoneCh)
remotePath := comm.ScriptPath() remotePath := comm.ScriptPath()
err = retryFunc(ctx, comm.Timeout(), func() error {
err = communicator.Retry(ctx, func() error {
if err := comm.UploadScript(remotePath, script); err != nil { if err := comm.UploadScript(remotePath, script); err != nil {
return fmt.Errorf("Failed to upload script: %v", err) return fmt.Errorf("Failed to upload script: %v", err)
} }
@ -248,75 +248,3 @@ func copyOutput(
o.Output(line) o.Output(line)
} }
} }
// retryFunc is used to retry a function for a given duration
func retryFunc(ctx context.Context, timeout time.Duration, f func() error) error {
// Build a new context with the timeout
ctx, done := context.WithTimeout(ctx, timeout)
defer done()
// container for atomic error value
type errWrap struct {
E error
}
// Try the function in a goroutine
var errVal atomic.Value
doneCh := make(chan struct{})
go func() {
defer close(doneCh)
delay := time.Duration(0)
for {
// If our context ended, we want to exit right away.
select {
case <-ctx.Done():
return
case <-time.After(delay):
}
// Try the function call
err := f()
errVal.Store(&errWrap{err})
if err == nil {
return
}
log.Printf("[WARN] retryable error: %v", err)
delay *= 2
if delay == 0 {
delay = initialBackoffDelay
}
if delay > maxBackoffDelay {
delay = maxBackoffDelay
}
log.Printf("[INFO] sleeping for %s", delay)
}
}()
// Wait for completion
select {
case <-ctx.Done():
case <-doneCh:
}
// Check if we have a context error to check if we're interrupted or timeout
switch ctx.Err() {
case context.Canceled:
return fmt.Errorf("interrupted")
case context.DeadlineExceeded:
return fmt.Errorf("timeout")
}
// Check if we got an error executing
if ev, ok := errVal.Load().(errWrap); ok {
return ev.E
}
return nil
}

View File

@ -2,12 +2,8 @@ package remoteexec
import ( import (
"bytes" "bytes"
"context"
"errors"
"io" "io"
"net"
"testing" "testing"
"time"
"strings" "strings"
@ -210,64 +206,6 @@ func TestResourceProvider_CollectScripts_scriptsEmpty(t *testing.T) {
} }
} }
func TestRetryFunc(t *testing.T) {
origMax := maxBackoffDelay
maxBackoffDelay = time.Second
origStart := initialBackoffDelay
initialBackoffDelay = 10 * time.Millisecond
defer func() {
maxBackoffDelay = origMax
initialBackoffDelay = origStart
}()
// succeed on the third try
errs := []error{io.EOF, &net.OpError{Err: errors.New("ERROR")}, nil}
count := 0
err := retryFunc(context.Background(), time.Second, func() error {
if count >= len(errs) {
return errors.New("failed to stop after nil error")
}
err := errs[count]
count++
return err
})
if count != 3 {
t.Fatal("retry func should have been called 3 times")
}
if err != nil {
t.Fatal(err)
}
}
func TestRetryFuncBackoff(t *testing.T) {
origMax := maxBackoffDelay
maxBackoffDelay = time.Second
origStart := initialBackoffDelay
initialBackoffDelay = 100 * time.Millisecond
defer func() {
maxBackoffDelay = origMax
initialBackoffDelay = origStart
}()
count := 0
retryFunc(context.Background(), time.Second, func() error {
count++
return io.EOF
})
if count > 4 {
t.Fatalf("retry func failed to backoff. called %d times", count)
}
}
func testConfig(t *testing.T, c map[string]interface{}) *terraform.ResourceConfig { func testConfig(t *testing.T, c map[string]interface{}) *terraform.ResourceConfig {
r, err := config.NewRawConfig(c) r, err := config.NewRawConfig(c)
if err != nil { if err != nil {