Merge pull request #11761 from hashicorp/jbardin/GH-11746
Cannot store multiple types in atomic.Value
This commit is contained in:
commit
6a626a2215
|
@ -234,11 +234,17 @@ func copyOutput(
|
||||||
}
|
}
|
||||||
|
|
||||||
// retryFunc is used to retry a function for a given duration
|
// retryFunc is used to retry a function for a given duration
|
||||||
|
// TODO: this should probably backoff too
|
||||||
func retryFunc(ctx context.Context, timeout time.Duration, f func() error) error {
|
func retryFunc(ctx context.Context, timeout time.Duration, f func() error) error {
|
||||||
// Build a new context with the timeout
|
// Build a new context with the timeout
|
||||||
ctx, done := context.WithTimeout(ctx, timeout)
|
ctx, done := context.WithTimeout(ctx, timeout)
|
||||||
defer done()
|
defer done()
|
||||||
|
|
||||||
|
// container for atomic error value
|
||||||
|
type errWrap struct {
|
||||||
|
E error
|
||||||
|
}
|
||||||
|
|
||||||
// Try the function in a goroutine
|
// Try the function in a goroutine
|
||||||
var errVal atomic.Value
|
var errVal atomic.Value
|
||||||
doneCh := make(chan struct{})
|
doneCh := make(chan struct{})
|
||||||
|
@ -255,19 +261,20 @@ func retryFunc(ctx context.Context, timeout time.Duration, f func() error) error
|
||||||
|
|
||||||
// Try the function call
|
// Try the function call
|
||||||
err := f()
|
err := f()
|
||||||
|
errVal.Store(&errWrap{err})
|
||||||
|
|
||||||
if err == nil {
|
if err == nil {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
log.Printf("Retryable error: %v", err)
|
log.Printf("Retryable error: %v", err)
|
||||||
errVal.Store(err)
|
|
||||||
}
|
}
|
||||||
}()
|
}()
|
||||||
|
|
||||||
// Wait for completion
|
// Wait for completion
|
||||||
select {
|
select {
|
||||||
case <-doneCh:
|
|
||||||
case <-ctx.Done():
|
case <-ctx.Done():
|
||||||
|
case <-doneCh:
|
||||||
}
|
}
|
||||||
|
|
||||||
// Check if we have a context error to check if we're interrupted or timeout
|
// Check if we have a context error to check if we're interrupted or timeout
|
||||||
|
@ -279,8 +286,8 @@ func retryFunc(ctx context.Context, timeout time.Duration, f func() error) error
|
||||||
}
|
}
|
||||||
|
|
||||||
// Check if we got an error executing
|
// Check if we got an error executing
|
||||||
if err, ok := errVal.Load().(error); ok {
|
if ev, ok := errVal.Load().(errWrap); ok {
|
||||||
return err
|
return ev.E
|
||||||
}
|
}
|
||||||
|
|
||||||
return nil
|
return nil
|
||||||
|
|
|
@ -2,8 +2,12 @@ package remoteexec
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"bytes"
|
"bytes"
|
||||||
|
"context"
|
||||||
|
"errors"
|
||||||
"io"
|
"io"
|
||||||
|
"net"
|
||||||
"testing"
|
"testing"
|
||||||
|
"time"
|
||||||
|
|
||||||
"github.com/hashicorp/terraform/config"
|
"github.com/hashicorp/terraform/config"
|
||||||
"github.com/hashicorp/terraform/helper/schema"
|
"github.com/hashicorp/terraform/helper/schema"
|
||||||
|
@ -158,6 +162,31 @@ func TestResourceProvider_CollectScripts_scripts(t *testing.T) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func TestRetryFunc(t *testing.T) {
|
||||||
|
// 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 testConfig(
|
func testConfig(
|
||||||
t *testing.T,
|
t *testing.T,
|
||||||
c map[string]interface{}) *terraform.ResourceConfig {
|
c map[string]interface{}) *terraform.ResourceConfig {
|
||||||
|
|
Loading…
Reference in New Issue