Skip to content

Commit

Permalink
Edge service retries (#55)
Browse files Browse the repository at this point in the history
* Adding retries for CreateOrUpdateEdgeDeploymentService

* Using for loop for the retries

The logging needs to be cleaned up

* Adding case statement for CreateOrUpdateEdgeDeploymentService

Created new function `sc.doRequestDetailed` to return the response object and err.

Needs some cleanup of the comments.

* Removed logging outputs and added case switch for 401 response code.

* Removing unused "err" variable to pass static checks

* matching Go style

Co-authored-by: shawnps <[email protected]>

* Renamed "sleepTime" var

* Refactored doRequest to utilize doRequestDetailed

* Change the sleeptime to be fixed 15 seconds instead of progressive. Look for Retry-After response header on 404 responses before restarting

* Revert calling doRequestDetailed to doRequest as it's unnecessary for this specific call

---------

Co-authored-by: shawnps <[email protected]>
Co-authored-by: Vladimir Vuksan <[email protected]>
  • Loading branch information
3 people authored Jul 7, 2023
1 parent ca07994 commit 973b55a
Showing 1 changed file with 65 additions and 29 deletions.
94 changes: 65 additions & 29 deletions api.go
Original file line number Diff line number Diff line change
Expand Up @@ -75,34 +75,7 @@ func (sc *Client) authenticate(email, password string) error {
}

func (sc *Client) doRequest(method, url, reqBody string) ([]byte, error) {
client := &http.Client{}

var b io.Reader
if reqBody != "" {
b = strings.NewReader(reqBody)
}

req, err := http.NewRequest(method, apiURL+url, b)
if err != nil {
return []byte{}, err
}

if sc.email != "" {
// token auth
req.Header.Set("X-API-User", sc.email)
req.Header.Set("X-API-Token", sc.token)
} else {
req.Header.Add("Authorization", fmt.Sprintf("Bearer %s", sc.token))
}

if sc.fastlyKey != "" {
req.Header.Set("Fastly-Key", sc.fastlyKey)
}

req.Header.Add("Content-Type", "application/json")
req.Header.Set("User-Agent", "go-sigsci")

resp, err := client.Do(req)
resp, err := sc.doRequestDetailed(method, url, reqBody)
if err != nil {
return []byte{}, err
}
Expand Down Expand Up @@ -2892,6 +2865,36 @@ func (sc *Client) GetSitePrimaryAgentKey(corpName, siteName string) (PrimaryAgen
return primaryKey, nil
}

func (sc *Client) doRequestDetailed(method, url, reqBody string) (*http.Response, error) {
client := &http.Client{}

var b io.Reader
if reqBody != "" {
b = strings.NewReader(reqBody)
}

req, _ := http.NewRequest(method, apiURL+url, b)

if sc.email != "" {
// token auth
req.Header.Set("X-API-User", sc.email)
req.Header.Set("X-API-Token", sc.token)
} else {
req.Header.Add("Authorization", fmt.Sprintf("Bearer %s", sc.token))
}

if sc.fastlyKey != "" {
req.Header.Set("Fastly-Key", sc.fastlyKey)
}

req.Header.Add("Content-Type", "application/json")
req.Header.Set("User-Agent", "go-sigsci")

resp, err := client.Do(req)

return resp, err
}

// CreateOrUpdateEdgeDeployment initializes the Next-Gen WAF deployment in Compute@Edge and configures the site for Edge Deployment.
func (sc *Client) CreateOrUpdateEdgeDeployment(corpName, siteName string) error {
_, err := sc.doRequest("PUT", fmt.Sprintf("/v0/corps/%s/sites/%s/edgeDeployment", corpName, siteName), "")
Expand Down Expand Up @@ -2923,7 +2926,40 @@ func (sc *Client) CreateOrUpdateEdgeDeploymentService(corpName, siteName, fastly
return err
}

_, err = sc.doRequest("PUT", fmt.Sprintf("/v0/corps/%s/sites/%s/edgeDeployment/%s", corpName, siteName, fastlySID), string(b))
var sleepTime = 15 * time.Second
for i := 0; i < 6; i++ {
resp, err := sc.doRequestDetailed("PUT", fmt.Sprintf("/v0/corps/%s/sites/%s/edgeDeployment/%s", corpName, siteName, fastlySID), string(b))

// Add case statements for the following
// 400 means that there is some sort of incorrect user input. Need to output the body of the response as the error
// 404 needs to retry because the NGWAF edge service is not ready yet.
switch resp.StatusCode {
case http.StatusOK: // 200
return err
case http.StatusBadRequest: // 400
fallthrough
case http.StatusUnauthorized: // 401
body, err := io.ReadAll(resp.Body)
if err != nil {
return err
}
return errMsg(body) // Typically incorrect user info
case http.StatusNotFound: // 404
// Only sleep if Retry-After response header is available
if resp.Header.Get("Retry-After") != "" {
time.Sleep(sleepTime)
} else {
body, err := io.ReadAll(resp.Body)
if err != nil {
return err
}
return errMsg(body) // 404 happened for some other reason
}
default: // Something else
// Wait and send another request
time.Sleep(sleepTime)
}
}

return err
}
Expand Down

0 comments on commit 973b55a

Please sign in to comment.