@@ -29,10 +29,91 @@ func (c *Client) DoRequestV2(method, endpoint string, body, out interface{}, log
2929// GET / PUT / DELETE
3030func (c * Client ) executeRequestWithRetries (method , endpoint string , body , out interface {}, log logger.Logger ) (* http.Response , error ) {
3131 // 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 ))
32+ log .Debug ("Executing request with retries" , zap .String ("method" , method ), zap .String ("endpoint" , endpoint ))
3333
34- // Placeholder for actual implementation
35- return nil , log .Error ("executeRequestWithRetries function is not implemented yet" )
34+ // Auth Token validation check
35+ valid , err := c .ValidAuthTokenCheck (log )
36+ if err != nil || ! valid {
37+ return nil , err
38+ }
39+
40+ // Acquire a token for concurrency management
41+ ctx , err := c .AcquireConcurrencyToken (context .Background (), log )
42+ if err != nil {
43+ return nil , err
44+ }
45+ defer func () {
46+ // Extract the requestID from the context and release the concurrency token
47+ if requestID , ok := ctx .Value (requestIDKey {}).(uuid.UUID ); ok {
48+ c .ConcurrencyMgr .Release (requestID )
49+ }
50+ }()
51+
52+ // Determine which set of encoding and content-type request rules to use
53+ apiHandler := c .APIHandler
54+
55+ // Marshal Request with correct encoding
56+ requestData , err := apiHandler .MarshalRequest (body , method , endpoint , log )
57+ if err != nil {
58+ return nil , err
59+ }
60+
61+ // Construct URL using the ConstructAPIResourceEndpoint function
62+ url := c .APIHandler .ConstructAPIResourceEndpoint (c .InstanceName , endpoint , log )
63+
64+ // Initialize total request counter
65+ c .PerfMetrics .lock .Lock ()
66+ c .PerfMetrics .TotalRequests ++
67+ c .PerfMetrics .lock .Unlock ()
68+
69+ // Perform Request
70+ req , err := http .NewRequest (method , url , bytes .NewBuffer (requestData ))
71+ if err != nil {
72+ return nil , err
73+ }
74+
75+ // Set request headers
76+ headerManager := NewHeaderManager (req , log , c .APIHandler , c .Token )
77+ headerManager .SetRequestHeaders (endpoint )
78+ headerManager .LogHeaders (c )
79+
80+ // Define a retry deadline based on the client's total retry duration configuration
81+ totalRetryDeadline := time .Now ().Add (c .clientConfig .ClientOptions .TotalRetryDuration )
82+
83+ var resp * http.Response
84+ retryCount := 0
85+ for time .Now ().Before (totalRetryDeadline ) { // Check if the current time is before the total retry deadline
86+ req = req .WithContext (ctx )
87+ resp , err = c .executeHTTPRequest (req , log , method , endpoint )
88+ if err == nil && resp .StatusCode >= 200 && resp .StatusCode < 300 {
89+ return resp , c .handleSuccessResponse (resp , out , log , method , endpoint )
90+ }
91+
92+ if errors .IsRateLimitError (resp ) || errors .IsTransientError (resp ) {
93+ retryCount ++
94+ if retryCount > c .clientConfig .ClientOptions .MaxRetryAttempts {
95+ log .Warn ("Max retry attempts reached" , zap .String ("method" , method ), zap .String ("endpoint" , endpoint ))
96+ break
97+ }
98+ waitDuration := calculateBackoff (retryCount )
99+ log .Warn ("Retrying request due to error" , zap .String ("method" , method ), zap .String ("endpoint" , endpoint ), zap .Int ("retryCount" , retryCount ), zap .Duration ("waitDuration" , waitDuration ), zap .Error (err ))
100+ time .Sleep (waitDuration )
101+ continue
102+ }
103+
104+ if err != nil || ! errors .IsRetryableStatusCode (resp .StatusCode ) {
105+ if apiErr := errors .HandleAPIError (resp , log ); apiErr != nil {
106+ err = apiErr
107+ }
108+ break
109+ }
110+ }
111+
112+ if err != nil {
113+ return nil , err
114+ }
115+
116+ return resp , errors .HandleAPIError (resp , log )
36117}
37118
38119// executeRequest handles the execution of idempotent HTTP requests without retry logic.
0 commit comments