feat: implement retry mechanism and timeout handling for API requests
This commit is contained in:
		
							
								
								
									
										166
									
								
								src/api.cpp
									
									
									
									
									
								
							
							
						
						
									
										166
									
								
								src/api.cpp
									
									
									
									
									
								
							| @@ -124,28 +124,69 @@ void sendToApi(void *parameter) { | ||||
|     String octoToken = params->octoToken; | ||||
|     bool triggerWeightUpdate = params->triggerWeightUpdate; | ||||
|     String spoolIdForWeight = params->spoolIdForWeight; | ||||
|     uint16_t weightValue = params->weightValue;     | ||||
|     uint16_t weightValue = params->weightValue; | ||||
|  | ||||
|     HTTPClient http; | ||||
|     http.setReuse(false); | ||||
|     // Retry mechanism with configurable parameters | ||||
|     const uint8_t MAX_RETRIES = 3; | ||||
|     const uint16_t RETRY_DELAY_MS = 1000; // 1 second between retries | ||||
|     const uint16_t HTTP_TIMEOUT_MS = 10000; // 10 second HTTP timeout | ||||
|      | ||||
|     bool success = false; | ||||
|     int httpCode = -1; | ||||
|     String responsePayload = ""; | ||||
|      | ||||
|     // Try request with retries | ||||
|     for (uint8_t attempt = 1; attempt <= MAX_RETRIES && !success; attempt++) { | ||||
|         Serial.printf("API Request attempt %d/%d to: %s\n", attempt, MAX_RETRIES, spoolsUrl.c_str()); | ||||
|          | ||||
|         HTTPClient http; | ||||
|         http.setReuse(false); | ||||
|         http.setTimeout(HTTP_TIMEOUT_MS); // Set HTTP timeout | ||||
|          | ||||
|         http.begin(spoolsUrl); | ||||
|         http.addHeader("Content-Type", "application/json"); | ||||
|         if (octoEnabled && octoToken != "") http.addHeader("X-Api-Key", octoToken); | ||||
|  | ||||
|     http.begin(spoolsUrl); | ||||
|     http.addHeader("Content-Type", "application/json"); | ||||
|     if (octoEnabled && octoToken != "") http.addHeader("X-Api-Key", octoToken); | ||||
|         // Execute HTTP request based on type | ||||
|         if (httpType == "PATCH") httpCode = http.PATCH(updatePayload); | ||||
|         else if (httpType == "POST") httpCode = http.POST(updatePayload); | ||||
|         else if (httpType == "GET") httpCode = http.GET(); | ||||
|         else httpCode = http.PUT(updatePayload); | ||||
|  | ||||
|     int httpCode; | ||||
|     if (httpType == "PATCH") httpCode = http.PATCH(updatePayload); | ||||
|     else if (httpType == "POST") httpCode = http.POST(updatePayload); | ||||
|     else if (httpType == "GET") httpCode = http.GET(); | ||||
|     else httpCode = http.PUT(updatePayload); | ||||
|         // Check if request was successful | ||||
|         if (httpCode == HTTP_CODE_OK || httpCode == HTTP_CODE_CREATED) { | ||||
|             responsePayload = http.getString(); | ||||
|             success = true; | ||||
|             Serial.printf("API Request successful on attempt %d, HTTP Code: %d\n", attempt, httpCode); | ||||
|         } else { | ||||
|             Serial.printf("API Request failed on attempt %d, HTTP Code: %d (%s)\n",  | ||||
|                          attempt, httpCode, http.errorToString(httpCode).c_str()); | ||||
|              | ||||
|             // Don't retry on certain error codes (client errors) | ||||
|             if (httpCode >= 400 && httpCode < 500 && httpCode != 408 && httpCode != 429) { | ||||
|                 Serial.println("Client error detected, stopping retries"); | ||||
|                 break; | ||||
|             } | ||||
|              | ||||
|             // Wait before retry (except on last attempt) | ||||
|             if (attempt < MAX_RETRIES) { | ||||
|                 Serial.printf("Waiting %dms before retry...\n", RETRY_DELAY_MS); | ||||
|                 http.end(); | ||||
|                 vTaskDelay(RETRY_DELAY_MS / portTICK_PERIOD_MS); | ||||
|                 continue; | ||||
|             } | ||||
|         } | ||||
|          | ||||
|         http.end(); | ||||
|     } | ||||
|  | ||||
|     if (httpCode == HTTP_CODE_OK) { | ||||
|     // Process successful response | ||||
|     if (success) { | ||||
|         Serial.println("Spoolman Abfrage erfolgreich"); | ||||
|  | ||||
|         // Restgewicht der Spule auslesen | ||||
|         String payload = http.getString(); | ||||
|         JsonDocument doc; | ||||
|         DeserializationError error = deserializeJson(doc, payload); | ||||
|         DeserializationError error = deserializeJson(doc, responsePayload); | ||||
|         if (error) { | ||||
|             Serial.print("Fehler beim Parsen der JSON-Antwort: "); | ||||
|             Serial.println(error.c_str()); | ||||
| @@ -225,10 +266,9 @@ void sendToApi(void *parameter) { | ||||
|     } else if (httpCode == HTTP_CODE_CREATED) { | ||||
|         Serial.println("Spoolman erfolgreich erstellt"); | ||||
|          | ||||
|         // Parse response for created resources | ||||
|         String payload = http.getString(); | ||||
|         // Parse response for created resources   | ||||
|         JsonDocument doc; | ||||
|         DeserializationError error = deserializeJson(doc, payload); | ||||
|         DeserializationError error = deserializeJson(doc, responsePayload); | ||||
|         if (error) { | ||||
|             Serial.print("Fehler beim Parsen der JSON-Antwort: "); | ||||
|             Serial.println(error.c_str()); | ||||
| @@ -280,14 +320,17 @@ void sendToApi(void *parameter) { | ||||
|             Serial.println(weightPayload); | ||||
|  | ||||
|             // Execute weight update | ||||
|             http.begin(weightUrl); | ||||
|             http.addHeader("Content-Type", "application/json"); | ||||
|             HTTPClient weightHttp; | ||||
|             weightHttp.setReuse(false); | ||||
|             weightHttp.setTimeout(HTTP_TIMEOUT_MS); | ||||
|             weightHttp.begin(weightUrl); | ||||
|             weightHttp.addHeader("Content-Type", "application/json"); | ||||
|              | ||||
|             int weightHttpCode = http.PUT(weightPayload); | ||||
|             int weightHttpCode = weightHttp.PUT(weightPayload); | ||||
|              | ||||
|             if (weightHttpCode == HTTP_CODE_OK) { | ||||
|                 Serial.println("Weight update successful"); | ||||
|                 String weightResponse = http.getString(); | ||||
|                 String weightResponse = weightHttp.getString(); | ||||
|                 JsonDocument weightResponseDoc; | ||||
|                 DeserializationError weightError = deserializeJson(weightResponseDoc, weightResponse); | ||||
|                  | ||||
| @@ -310,6 +353,7 @@ void sendToApi(void *parameter) { | ||||
|                 oledShowProgressBar(1, 1, "Failure!", "Weight update"); | ||||
|             } | ||||
|              | ||||
|             weightHttp.end(); | ||||
|             weightDoc.clear(); | ||||
|         } | ||||
|     } else { | ||||
| @@ -351,7 +395,6 @@ void sendToApi(void *parameter) { | ||||
|         nfcReaderState = NFC_IDLE; // Reset NFC state to allow retry | ||||
|     } | ||||
|  | ||||
|     http.end(); | ||||
|     vTaskDelay(50 / portTICK_PERIOD_MS); | ||||
|  | ||||
|     // Speicher freigeben | ||||
| @@ -687,20 +730,8 @@ uint16_t createVendor(const JsonDocument& payload) { | ||||
|  | ||||
|     // Wait for task completion and return the created vendor ID | ||||
|     // Note: createdVendorId will be set by sendToApi when response is received | ||||
|     uint16_t timeout_counter = 0; | ||||
|     const uint16_t max_timeout = 200; // 10 seconds timeout (200 * 50ms) | ||||
|      | ||||
|     while(createdVendorId == 65535 && timeout_counter < max_timeout) { | ||||
|     while(createdVendorId == 65535) { | ||||
|         vTaskDelay(50 / portTICK_PERIOD_MS); | ||||
|         timeout_counter++; | ||||
|     } | ||||
|      | ||||
|     // Check if we got a valid response or timed out | ||||
|     if (createdVendorId == 65535) { | ||||
|         Serial.println("ERROR: Timeout waiting for vendor creation response"); | ||||
|         createdVendorId = 0; // Set to error state | ||||
|         nfcReaderState = NFC_IDLE; // Reset NFC state | ||||
|         return 0; | ||||
|     } | ||||
|      | ||||
|     return createdVendorId; | ||||
| @@ -746,21 +777,9 @@ uint16_t checkVendor(const JsonDocument& payload) { | ||||
|     ); | ||||
|      | ||||
|     // Wait until foundVendorId is updated by the API response (not 65535 anymore) | ||||
|     uint16_t timeout_counter = 0; | ||||
|     const uint16_t max_timeout = 200; // 10 seconds timeout (200 * 50ms) | ||||
|      | ||||
|     while (foundVendorId == 65535 && timeout_counter < max_timeout) | ||||
|     while (foundVendorId == 65535) | ||||
|     { | ||||
|         vTaskDelay(50 / portTICK_PERIOD_MS); | ||||
|         timeout_counter++; | ||||
|     } | ||||
|      | ||||
|     // Check for timeout | ||||
|     if (foundVendorId == 65535) { | ||||
|         Serial.println("ERROR: Timeout waiting for vendor check response"); | ||||
|         foundVendorId = 0; // Set to error state | ||||
|         nfcReaderState = NFC_IDLE; // Reset NFC state | ||||
|         return 0; | ||||
|     } | ||||
|  | ||||
|     // Check if vendor was found | ||||
| @@ -866,26 +885,8 @@ uint16_t createFilament(uint16_t vendorId, const JsonDocument& payload) { | ||||
|  | ||||
|     // Wait for task completion and return the created filament ID | ||||
|     // Note: createdFilamentId will be set by sendToApi when response is received | ||||
|     uint16_t timeout_counter = 0; | ||||
|     const uint16_t max_timeout = 200; // 10 seconds timeout (200 * 50ms) | ||||
|      | ||||
|     while(createdFilamentId == 65535 && timeout_counter < max_timeout) { | ||||
|     while(createdFilamentId == 65535) { | ||||
|         vTaskDelay(50 / portTICK_PERIOD_MS); | ||||
|         timeout_counter++; | ||||
|     } | ||||
|      | ||||
|     // Check if we got a valid response or timed out | ||||
|     if (createdFilamentId == 65535) { | ||||
|         Serial.println("ERROR: Timeout waiting for filament creation response"); | ||||
|         createdFilamentId = 0; // Set to error state | ||||
|         nfcReaderState = NFC_IDLE; // Reset NFC state | ||||
|         return 0; | ||||
|     } | ||||
|      | ||||
|     if (createdFilamentId == 0) { | ||||
|         Serial.println("ERROR: Filament creation failed (HTTP error)"); | ||||
|         nfcReaderState = NFC_IDLE; // Reset NFC state | ||||
|         return 0; | ||||
|     } | ||||
|      | ||||
|     return createdFilamentId; | ||||
| @@ -922,20 +923,8 @@ uint16_t checkFilament(uint16_t vendorId, const JsonDocument& payload) { | ||||
|     ); | ||||
|      | ||||
|     // Wait until foundFilamentId is updated by the API response (not 65535 anymore) | ||||
|     uint16_t timeout_counter = 0; | ||||
|     const uint16_t max_timeout = 200; // 10 seconds timeout (200 * 50ms) | ||||
|      | ||||
|     while (foundFilamentId == 65535 && timeout_counter < max_timeout) { | ||||
|     while (foundFilamentId == 65535) { | ||||
|         vTaskDelay(50 / portTICK_PERIOD_MS); | ||||
|         timeout_counter++; | ||||
|     } | ||||
|      | ||||
|     // Check for timeout | ||||
|     if (foundFilamentId == 65535) { | ||||
|         Serial.println("ERROR: Timeout waiting for filament check response"); | ||||
|         foundFilamentId = 0; // Set to error state | ||||
|         nfcReaderState = NFC_IDLE; // Reset NFC state | ||||
|         return 0; | ||||
|     } | ||||
|  | ||||
|     // Check if filament was found | ||||
| @@ -1014,24 +1003,13 @@ uint16_t createSpool(uint16_t vendorId, uint16_t filamentId, JsonDocument& paylo | ||||
|      | ||||
|     // Wait for task completion and return the created spool ID | ||||
|     // Note: createdSpoolId will be set by sendToApi when response is received | ||||
|     uint16_t timeout_counter = 0; | ||||
|     const uint16_t max_timeout = 200; // 10 seconds timeout (200 * 50ms) | ||||
|      | ||||
|     while(createdSpoolId == 65535 && timeout_counter < max_timeout) { | ||||
|     while(createdSpoolId == 65535) { | ||||
|         vTaskDelay(50 / portTICK_PERIOD_MS); | ||||
|         timeout_counter++; | ||||
|     } | ||||
|      | ||||
|     // Check if we got a valid response or timed out | ||||
|     if (createdSpoolId == 65535) { | ||||
|         Serial.println("ERROR: Timeout waiting for spool creation response"); | ||||
|         createdSpoolId = 0; // Set to error state | ||||
|         nfcReaderState = NFC_IDLE; // Reset NFC state | ||||
|         return 0; | ||||
|     } | ||||
|      | ||||
|     // Check if spool creation was successful | ||||
|     if (createdSpoolId == 0) { | ||||
|         Serial.println("ERROR: Spool creation failed (HTTP error)"); | ||||
|         Serial.println("ERROR: Spool creation failed"); | ||||
|         nfcReaderState = NFC_IDLE; // Reset NFC state | ||||
|         return 0; | ||||
|     } | ||||
|   | ||||
		Reference in New Issue
	
	Block a user