|
| 1 | +// httpclient_ping.go |
| 2 | +package httpclient |
| 3 | + |
| 4 | +import ( |
| 5 | + "fmt" |
| 6 | + "net/http" |
| 7 | + "time" |
| 8 | + |
| 9 | + "go.uber.org/zap" |
| 10 | +) |
| 11 | + |
| 12 | +// DoPing performs an HTTP "ping" to the specified endpoint using the given HTTP method, body, |
| 13 | +// and output variable. It attempts the request until a 200 OK response is received or the |
| 14 | +// maximum number of retry attempts is reached. The function uses a backoff strategy for retries |
| 15 | +// to manage load on the server and network. This function is useful for checking the availability |
| 16 | +// or health of an endpoint, particularly in environments where network reliability might be an issue. |
| 17 | + |
| 18 | +// Parameters: |
| 19 | +// - method: The HTTP method to be used for the request. This should typically be "GET" for a ping operation, but the function is designed to accommodate any HTTP method. |
| 20 | +// - endpoint: The target API endpoint for the ping request. This should be a relative path that will be appended to the base URL configured for the HTTP client. |
| 21 | +// - body: The payload for the request, if any. For a typical ping operation, this would be nil, but the function is designed to accommodate requests that might require a body. |
| 22 | +// - out: A pointer to an output variable where the response will be deserialized. This is included to maintain consistency with the signature of other request functions, but for a ping operation, it might not be used. |
| 23 | + |
| 24 | +// Returns: |
| 25 | +// - *http.Response: The HTTP response from the server. In case of a successful ping (200 OK), |
| 26 | +// this response contains the status code, headers, and body of the response. In case of errors |
| 27 | +// or if the maximum number of retries is reached without a successful response, this will be the |
| 28 | +// last received HTTP response. |
| 29 | +// |
| 30 | +// - error: An error object indicating failure during the execution of the ping operation. This |
| 31 | +// could be due to network issues, server errors, or reaching the maximum number of retry attempts |
| 32 | +// without receiving a 200 OK response. |
| 33 | + |
| 34 | +// Usage: |
| 35 | +// This function is intended for use in scenarios where it's necessary to confirm the availability |
| 36 | +// or health of an endpoint, with built-in retry logic to handle transient network or server issues. |
| 37 | +// The caller is responsible for handling the response and error according to their needs, including |
| 38 | +// closing the response body when applicable to avoid resource leaks. |
| 39 | + |
| 40 | +// Example: |
| 41 | +// var result MyResponseType |
| 42 | +// resp, err := client.DoPing("GET", "/api/health", nil, &result) |
| 43 | +// |
| 44 | +// if err != nil { |
| 45 | +// // Handle error |
| 46 | +// } |
| 47 | +// |
| 48 | +// // Process response |
| 49 | +func (c *Client) DoPing(method, endpoint string, body, out interface{}) (*http.Response, error) { |
| 50 | + log := c.Logger |
| 51 | + log.Debug("Starting Ping", zap.String("method", method), zap.String("endpoint", endpoint)) |
| 52 | + |
| 53 | + // Initialize retry count and define maximum retries |
| 54 | + var retryCount int |
| 55 | + maxRetries := c.clientConfig.ClientOptions.MaxRetryAttempts |
| 56 | + |
| 57 | + // Loop until a successful response is received or maximum retries are reached |
| 58 | + for retryCount <= maxRetries { |
| 59 | + // Use the existing 'do' function for sending the request |
| 60 | + resp, err := c.executeRequest(method, endpoint, body, out) |
| 61 | + |
| 62 | + // If request is successful and returns 200 status code, return the response |
| 63 | + if err == nil && resp.StatusCode == http.StatusOK { |
| 64 | + log.Debug("Ping successful", zap.String("method", method), zap.String("endpoint", endpoint)) |
| 65 | + return resp, nil |
| 66 | + } |
| 67 | + |
| 68 | + // Increment retry count and log the attempt |
| 69 | + retryCount++ |
| 70 | + log.Warn("Ping failed, retrying...", zap.String("method", method), zap.String("endpoint", endpoint), zap.Int("retryCount", retryCount)) |
| 71 | + |
| 72 | + // Calculate backoff duration and wait before retrying |
| 73 | + backoffDuration := calculateBackoff(retryCount) |
| 74 | + time.Sleep(backoffDuration) |
| 75 | + } |
| 76 | + |
| 77 | + // If maximum retries are reached without a successful response, return an error |
| 78 | + log.Error("Ping failed after maximum retries", zap.String("method", method), zap.String("endpoint", endpoint)) |
| 79 | + return nil, fmt.Errorf("ping failed after %d retries", maxRetries) |
| 80 | +} |
0 commit comments