Skip to content

Commit

Permalink
Add option to modify wait time for async ops
Browse files Browse the repository at this point in the history
  • Loading branch information
danischm committed Jan 9, 2024
1 parent eb53e01 commit 9925ab8
Show file tree
Hide file tree
Showing 4 changed files with 48 additions and 22 deletions.
4 changes: 4 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,3 +1,7 @@
## 0.1.1 (unreleased)

- Add option to set default maximum waiting time for async operations and override ip per request

## 0.1.0

- Initial release
48 changes: 30 additions & 18 deletions client.go
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,7 @@ const DefaultMaxRetries int = 3
const DefaultBackoffMinDelay int = 2
const DefaultBackoffMaxDelay int = 60
const DefaultBackoffDelayFactor float64 = 3
const MaxTaskWaitAttempts int = 10
const DefaultDefaultMaxAsyncWaitTime int = 30

var SynchronousApiEndpoints = [...]string{
"/dna/intent/api/v1/site",
Expand Down Expand Up @@ -52,6 +52,8 @@ type Client struct {
BackoffMaxDelay int
// Backoff delay factor
BackoffDelayFactor float64
// Maximum async operations wait time
DefaultMaxAsyncWaitTime int
// Authentication mutex
AuthenticationMutex *sync.Mutex
}
Expand All @@ -73,15 +75,16 @@ func NewClient(url, usr, pwd string, mods ...func(*Client)) (Client, error) {
}

client := Client{
HttpClient: &httpClient,
Url: url,
Usr: usr,
Pwd: pwd,
MaxRetries: DefaultMaxRetries,
BackoffMinDelay: DefaultBackoffMinDelay,
BackoffMaxDelay: DefaultBackoffMaxDelay,
BackoffDelayFactor: DefaultBackoffDelayFactor,
AuthenticationMutex: &sync.Mutex{},
HttpClient: &httpClient,
Url: url,
Usr: usr,
Pwd: pwd,
MaxRetries: DefaultMaxRetries,
BackoffMinDelay: DefaultBackoffMinDelay,
BackoffMaxDelay: DefaultBackoffMaxDelay,
BackoffDelayFactor: DefaultBackoffDelayFactor,
DefaultMaxAsyncWaitTime: DefaultDefaultMaxAsyncWaitTime,
AuthenticationMutex: &sync.Mutex{},
}

for _, mod := range mods {
Expand Down Expand Up @@ -132,13 +135,21 @@ func BackoffDelayFactor(x float64) func(*Client) {
}
}

// DefaultMaxAsyncWaitTime modifies the maximum wait time for async operations from the default of 30 seconds.
func DefaultMaxAsyncWaitTime(x int) func(*Client) {
return func(client *Client) {
client.DefaultMaxAsyncWaitTime = x
}
}

// NewReq creates a new Req request for this client.
func (client Client) NewReq(method, uri string, body io.Reader, mods ...func(*Req)) Req {
httpReq, _ := http.NewRequest(method, client.Url+uri, body)
req := Req{
HttpReq: httpReq,
LogPayload: true,
Synchronous: true,
HttpReq: httpReq,
LogPayload: true,
Synchronous: true,
MaxAsyncWaitTime: client.DefaultMaxAsyncWaitTime,
}
for _, mod := range mods {
mod(&req)
Expand Down Expand Up @@ -223,14 +234,14 @@ func (client *Client) Do(req Req) (Res, error) {
}

if req.Synchronous {
return client.WaitTask(res)
return client.WaitTask(&req, &res)
}

return res, nil
}

// WaitTask waits for an asynchronous task to complete.
func (client *Client) WaitTask(res Res) (Res, error) {
func (client *Client) WaitTask(req *Req, res *Res) (Res, error) {
var asyncOp, id string
if res.Get("response.taskId").Exists() {
asyncOp = "task"
Expand All @@ -240,6 +251,7 @@ func (client *Client) WaitTask(res Res) (Res, error) {
id = res.Get("executionId").String()
}
if asyncOp != "" {
startTime := time.Now()
for attempts := 0; ; attempts++ {
sleep := 0.5 * float64(attempts)
if sleep > 2 {
Expand Down Expand Up @@ -285,13 +297,13 @@ func (client *Client) WaitTask(res Res) (Res, error) {
return taskRes, nil
}
log.Printf("[DEBUG] Waiting for task '%s' to complete.", id)
if attempts > MaxTaskWaitAttempts {
log.Printf("[DEBUG] Maximum number of attempts reached for task '%s'.", id)
if time.Since(startTime) > time.Duration(req.MaxAsyncWaitTime)*time.Second {
log.Printf("[DEBUG] Maximum waiting time reached for task '%s'.", id)
return taskRes, fmt.Errorf("maximum waiting time for task '%s' reached", id)
}
}
}
return res, nil
return *res, nil
}

// Get makes a GET request and returns a GJSON result.
Expand Down
8 changes: 4 additions & 4 deletions client_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -189,21 +189,21 @@ func TestClientWaitTask(t *testing.T) {

// Task
gock.New(testURL).Get("/api/v1/task/123").Reply(200).BodyString(`{"response": {"endTime": "1", "isError": false}}`)
_, err = client.WaitTask(Res{Raw: `{"response": {"taskId": "123"}}`})
_, err = client.WaitTask(&Req{}, &Res{Raw: `{"response": {"taskId": "123"}}`})
assert.NoError(t, err)

// Task error
gock.New(testURL).Get("/api/v1/task/123").Reply(200).BodyString(`{"response": {"endTime": "1", "isError": true}}`)
_, err = client.WaitTask(Res{Raw: `{"response": {"taskId": "123"}}`})
_, err = client.WaitTask(&Req{}, &Res{Raw: `{"response": {"taskId": "123"}}`})
assert.Error(t, err)

// Execution
gock.New(testURL).Get("/dna/platform/management/business-api/v1/execution-status/123").Reply(200).BodyString(`{"status": "SUCCESS"}`)
_, err = client.WaitTask(Res{Raw: `{"executionId": "123"}`})
_, err = client.WaitTask(&Req{}, &Res{Raw: `{"executionId": "123"}`})
assert.NoError(t, err)

// Execution error
gock.New(testURL).Get("/dna/platform/management/business-api/v1/execution-status/123").Reply(200).BodyString(`{"status": "FAILURE"}`)
_, err = client.WaitTask(Res{Raw: `{"executionId": "123"}`})
_, err = client.WaitTask(&Req{}, &Res{Raw: `{"executionId": "123"}`})
assert.Error(t, err)
}
10 changes: 10 additions & 0 deletions req.go
Original file line number Diff line number Diff line change
Expand Up @@ -52,6 +52,8 @@ type Req struct {
LogPayload bool
// Synchronous indicates whether the request should be performed synchronously.
Synchronous bool
// MaxAsyncWaitTime is the maximum time to wait for an asynchronous operation.
MaxAsyncWaitTime int
}

// NoLogPayload prevents logging of payloads.
Expand All @@ -65,3 +67,11 @@ func NoLogPayload(req *Req) {
func Asynchronous(req *Req) {
req.Synchronous = false
}

// Maximum Asynchronous operation wait time.
// This is only relevant for POST, PUT or DELETE requests.
func MaxAsyncWaitTime(seconds int) func(*Req) {
return func(req *Req) {
req.MaxAsyncWaitTime = seconds
}
}

0 comments on commit 9925ab8

Please sign in to comment.