Repository: algolia/algoliasearch-client-go
Pull request #726 (2023-04-11 19:41:56)

feat: allow to set a custom delay for the wait functions
| Q                 | A
| ----------------- | ----------
| Bug fix?          | no
| New feature?      | yes
| BC breaks?        | no     
| Need Doc update   | no


## Describe your change

Allow to set a custom delay for the wait functions using the options

## What problem is this fixing?

In case of low latency, the default 1s delay can be too high.



Patch:
diff --git a/algolia/internal/gen/options.go b/algolia/internal/gen/options.go
index 78982c37..983640e7 100644
--- a/algolia/internal/gen/options.go
+++ b/algolia/internal/gen/options.go
@@ -180,4 +180,5 @@ var options = []Option{
 	{"exposeIntermediateNetworkErrors", Other, false, ""},
 	{"language", Other, "", ""},
 	{"disableStandardEntries", Other, map[string]map[string]bool{}, ""},
+	{"waitConfiguration", Other, nil, ""},
 }
diff --git a/algolia/internal/opt/wait_configuration.go b/algolia/internal/opt/wait_configuration.go
new file mode 100644
index 00000000..9cfa5b84
--- /dev/null
+++ b/algolia/internal/opt/wait_configuration.go
@@ -0,0 +1,16 @@
+package opt
+
+import (
+	"github.com/algolia/algoliasearch-client-go/v3/algolia/opt"
+)
+
+// ExtractWaitConfiguration returns the first found wait configuration from....
+// given variadic arguments or nil otherwise.
+func ExtractWaitConfiguration(opts ...interface{}) *opt.WaitConfigurationOption {
+	for _, o := range opts {
+		if v, ok := o.(*opt.WaitConfigurationOption); ok {
+			return v
+		}
+	}
+	return opt.DefaultWaitConfiguration()
+}
diff --git a/algolia/opt/wait_configuration.go b/algolia/opt/wait_configuration.go
new file mode 100644
index 00000000..48ac90b3
--- /dev/null
+++ b/algolia/opt/wait_configuration.go
@@ -0,0 +1,36 @@
+package opt
+
+import (
+	"time"
+)
+
+const (
+	maxDurationBetweenWaits = 10 * time.Second
+)
+
+// WaitConfigurationOption stores the logic to change the delay between waits
+type WaitConfigurationOption struct {
+	DelayGrowth func(*time.Duration) time.Duration
+}
+
+// DefaultWaitConfiguration returns the new delay to apply between waits
+func DefaultWaitConfiguration() *WaitConfigurationOption {
+	return &WaitConfigurationOption{DelayGrowth: func(d *time.Duration) time.Duration {
+		if d == nil {
+			return time.Second
+		}
+		res := *d * 2
+		if res > maxDurationBetweenWaits {
+			return maxDurationBetweenWaits
+		}
+		return res
+	}}
+}
+
+// Get retrieves the actual value of the option parameter.
+func (w *WaitConfigurationOption) Get() func(*time.Duration) time.Duration {
+	if w == nil {
+		return DefaultWaitConfiguration().DelayGrowth
+	}
+	return w.DelayGrowth
+}
diff --git a/algolia/search/client.go b/algolia/search/client.go
index 27b4bae8..3bb8941a 100644
--- a/algolia/search/client.go
+++ b/algolia/search/client.go
@@ -145,5 +145,5 @@ func (c *Client) WaitTask(taskID int64, opts ...interface{}) error {
 			return true, err
 		}
 		return res.Status == "published", nil
-	})
+	}, iopt.ExtractWaitConfiguration(opts))
 }
diff --git a/algolia/search/client_keys.go b/algolia/search/client_keys.go
index dd5cf9b4..32e60acd 100644
--- a/algolia/search/client_keys.go
+++ b/algolia/search/client_keys.go
@@ -9,6 +9,7 @@ import (
 
 	"github.com/algolia/algoliasearch-client-go/v3/algolia/call"
 	"github.com/algolia/algoliasearch-client-go/v3/algolia/errs"
+	"github.com/algolia/algoliasearch-client-go/v3/algolia/opt"
 )
 
 // GetAPIKey retrieves the API key identified by the given keyID.
@@ -104,7 +105,7 @@ func (c *Client) waitKeyIsAvailable(keyID string) func() error {
 				return false, nil
 			}
 			return true, err
-		})
+		}, opt.DefaultWaitConfiguration())
 	}
 }
 
@@ -119,7 +120,7 @@ func (c *Client) waitKeyIsNotAvailable(keyID string) func() error {
 				return true, nil
 			}
 			return true, err
-		})
+		}, opt.DefaultWaitConfiguration())
 	}
 }
 
@@ -131,6 +132,6 @@ func (c *Client) waitKeyHasChanged(expected Key) func() error {
 				return true, err
 			}
 			return expected.Equal(found), nil
-		})
+		}, opt.DefaultWaitConfiguration())
 	}
 }
diff --git a/algolia/search/index.go b/algolia/search/index.go
index 664881ca..ca3700da 100644
--- a/algolia/search/index.go
+++ b/algolia/search/index.go
@@ -46,7 +46,7 @@ func (i *Index) WaitTask(taskID int64, opts ...interface{}) error {
 			return true, err
 		}
 		return res.Status == "published", nil
-	})
+	}, iopt.ExtractWaitConfiguration(opts))
 }
 
 func (i *Index) operation(destination, op string, opts ...interface{}) (res UpdateTaskRes, err error) {
diff --git a/algolia/search/utils.go b/algolia/search/utils.go
index c3510869..42eb123e 100644
--- a/algolia/search/utils.go
+++ b/algolia/search/utils.go
@@ -8,12 +8,12 @@ import (
 	"time"
 
 	"github.com/algolia/algoliasearch-client-go/v3/algolia/call"
+	"github.com/algolia/algoliasearch-client-go/v3/algolia/opt"
 	"github.com/algolia/algoliasearch-client-go/v3/algolia/transport"
 )
 
 const (
-	jsonNull                = "null"
-	maxDurationBetweenRetry = 10 * time.Second
+	jsonNull = "null"
 )
 
 func defaultHosts(appID string) (hosts []*transport.StatefulHost) {
@@ -33,8 +33,8 @@ func noWait(_ int64, _ ...interface{}) error {
 	return nil
 }
 
-func waitWithRetry(f func() (bool, error)) error {
-	d := time.Second
+func waitWithRetry(f func() (bool, error), waitCfg *opt.WaitConfigurationOption) error {
+	d := waitCfg.DelayGrowth(nil)
 
 	for {
 		done, err := f()
@@ -44,12 +44,7 @@ func waitWithRetry(f func() (bool, error)) error {
 
 		time.Sleep(d)
 
-		if d < maxDurationBetweenRetry {
-			d *= 2
-		}
-		if d > maxDurationBetweenRetry {
-			d = maxDurationBetweenRetry
-		}
+		d = waitCfg.DelayGrowth(&d)
 	}
 }
 


Test patch:
diff --git a/algolia/internal/opt/wait_configuration_test.go b/algolia/internal/opt/wait_configuration_test.go
new file mode 100644
index 00000000..74129523
--- /dev/null
+++ b/algolia/internal/opt/wait_configuration_test.go
@@ -0,0 +1,34 @@
+package opt
+
+import (
+	"testing"
+	"time"
+
+	"github.com/algolia/algoliasearch-client-go/v3/algolia/opt"
+	"github.com/stretchr/testify/require"
+)
+
+func TestWaitConfiguration(t *testing.T) {
+	for _, c := range []struct {
+		name     string
+		opts     []interface{}
+		expected *opt.WaitConfigurationOption
+	}{
+		{
+			name:     "no conf",
+			opts:     []interface{}{},
+			expected: opt.DefaultWaitConfiguration(),
+		},
+		{
+			name:     "custom conf",
+			opts:     []interface{}{&opt.WaitConfigurationOption{DelayGrowth: func(*time.Duration) time.Duration { return 42 * time.Second }}},
+			expected: &opt.WaitConfigurationOption{DelayGrowth: func(*time.Duration) time.Duration { return 42 * time.Second }},
+		},
+	} {
+		t.Run(c.name, func(t *testing.T) {
+			in := ExtractWaitConfiguration(c.opts...)
+			// Lambda can't be compared, the first value is used as an identifier
+			require.Equal(t, c.expected.DelayGrowth(nil), in.DelayGrowth(nil))
+		})
+	}
+}
diff --git a/algolia/opt/option_getters_test.go b/algolia/opt/option_getters_test.go
index 7188f08b..800944bd 100644
--- a/algolia/opt/option_getters_test.go
+++ b/algolia/opt/option_getters_test.go
@@ -368,4 +368,7 @@ func TestOptionGetters(t *testing.T) {
 	var disableStandardEntries *DisableStandardEntriesOption = nil
 	disableStandardEntries.Get()
 
+	var waitConfiguration *WaitConfigurationOption = nil
+	waitConfiguration.Get()
+
 }