Skip to content

Commit a796274

Browse files
committed
Add support for executing HTTP requests with retries
1 parent f4f2bbd commit a796274

File tree

1 file changed

+106
-0
lines changed

1 file changed

+106
-0
lines changed

httpclient/httpclient_request.go

Lines changed: 106 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,112 @@ import (
1414
"go.uber.org/zap"
1515
)
1616

17+
// DoRequestV2 constructs and executes an HTTP request, choosing the execution path based on the idempotency of the HTTP method.
18+
func (c *Client) DoRequestV2(method, endpoint string, body, out interface{}, log logger.Logger) (*http.Response, error) {
19+
if IsIdempotentHTTPMethod(method) {
20+
return c.executeRequestWithRetries(method, endpoint, body, out, log)
21+
} else if IsNonIdempotentHTTPMethod(method) {
22+
return c.executeRequest(method, endpoint, body, out, log)
23+
} else {
24+
return nil, log.Error("HTTP method not supported", zap.String("method", method))
25+
}
26+
}
27+
28+
// executeRequestWithRetries handles the execution of non-idempotent HTTP requests with appropriate retry logic.
29+
// GET / PUT / DELETE
30+
func (c *Client) executeRequestWithRetries(method, endpoint string, body, out interface{}, log logger.Logger) (*http.Response, error) {
31+
// Include the core logic for handling non-idempotent requests with retries here.
32+
log.Debug("Executing non-idempotent request with retries", zap.String("method", method), zap.String("endpoint", endpoint))
33+
34+
// Placeholder for actual implementation
35+
return nil, log.Error("executeRequestWithRetries function is not implemented yet")
36+
}
37+
38+
// executeRequest handles the execution of idempotent HTTP requests without retry logic.
39+
// POST / PATCH
40+
func (c *Client) executeRequest(method, endpoint string, body, out interface{}, log logger.Logger) (*http.Response, error) {
41+
// Include the core logic for handling idempotent requests here.
42+
log.Debug("Executing idempotent request", zap.String("method", method), zap.String("endpoint", endpoint))
43+
44+
// Auth Token validation check
45+
valid, err := c.ValidAuthTokenCheck(log)
46+
if err != nil || !valid {
47+
return nil, err
48+
}
49+
50+
// Acquire a token for concurrency management
51+
ctx, err := c.AcquireConcurrencyToken(context.Background(), log)
52+
if err != nil {
53+
return nil, err
54+
}
55+
defer func() {
56+
// Extract the requestID from the context and release the concurrency token
57+
if requestID, ok := ctx.Value(requestIDKey{}).(uuid.UUID); ok {
58+
c.ConcurrencyMgr.Release(requestID)
59+
}
60+
}()
61+
62+
// Determine which set of encoding and content-type request rules to use
63+
apiHandler := c.APIHandler
64+
65+
// Marshal Request with correct encoding
66+
requestData, err := apiHandler.MarshalRequest(body, method, endpoint, log)
67+
if err != nil {
68+
return nil, err
69+
}
70+
71+
// Construct URL using the ConstructAPIResourceEndpoint function
72+
url := c.APIHandler.ConstructAPIResourceEndpoint(c.InstanceName, endpoint, log)
73+
74+
// Initialize total request counter
75+
c.PerfMetrics.lock.Lock()
76+
c.PerfMetrics.TotalRequests++
77+
c.PerfMetrics.lock.Unlock()
78+
79+
// Perform Request
80+
req, err := http.NewRequest(method, url, bytes.NewBuffer(requestData))
81+
if err != nil {
82+
return nil, err
83+
}
84+
85+
// Set request headers
86+
headerManager := NewHeaderManager(req, log, c.APIHandler, c.Token)
87+
headerManager.SetRequestHeaders(endpoint)
88+
headerManager.LogHeaders(c)
89+
90+
// Start response time measurement
91+
responseTimeStart := time.Now()
92+
// For non-retryable HTTP Methods (POST - Create)
93+
req = req.WithContext(ctx)
94+
95+
// Execute the HTTP request
96+
resp, err := c.executeHTTPRequest(req, log, method, endpoint)
97+
if err != nil {
98+
return nil, err
99+
}
100+
101+
// After each request, compute and update response time
102+
responseDuration := time.Since(responseTimeStart)
103+
c.updatePerformanceMetrics(responseDuration)
104+
105+
// Checks for the presence of a deprecation header in the HTTP response and logs if found.
106+
CheckDeprecationHeader(resp, log)
107+
108+
// Handle the response
109+
if err := c.APIHandler.UnmarshalResponse(resp, out, log); err != nil {
110+
// Error handling, including logging and type assertion for APIError
111+
return resp, err // Error is already logged in UnmarshalResponse
112+
}
113+
114+
// Successful execution and response handling
115+
log.Info("HTTP request executed successfully",
116+
zap.String("method", method),
117+
zap.String("endpoint", endpoint),
118+
zap.Int("status_code", resp.StatusCode))
119+
120+
return resp, nil
121+
}
122+
17123
// executeHTTPRequest sends an HTTP request using the client's HTTP client. It logs the request and error details, if any, using structured logging with zap fields.
18124
//
19125
// Parameters:

0 commit comments

Comments
 (0)