From 76bb88ab64ed6f25f8706c6d42fb161d17ddf804 Mon Sep 17 00:00:00 2001 From: Thomas Braun Date: Wed, 29 Jan 2025 16:32:30 +0100 Subject: [PATCH 1/5] Tests: Factor CreateOverrideResults out --- Packages/MIES/MIES_WaveDataFolderGetters.ipf | 2 +- Packages/tests/UTF_HelperFunctions.ipf | 9 ++++++++- 2 files changed, 9 insertions(+), 2 deletions(-) diff --git a/Packages/MIES/MIES_WaveDataFolderGetters.ipf b/Packages/MIES/MIES_WaveDataFolderGetters.ipf index 7560ed28c4..71ed1f82d7 100644 --- a/Packages/MIES/MIES_WaveDataFolderGetters.ipf +++ b/Packages/MIES/MIES_WaveDataFolderGetters.ipf @@ -7591,7 +7591,7 @@ End /// @brief Return the wave used for storing mock data for tests /// /// This wave is created by MSQ_CreateOverrideResults(), -/// PSQ_CreateOverrideResults() or TP_CreateOverrideResults() and does also not +/// PSQ_CreateOverrideResults(), TP_CreateOverrideResults(), CreateOverrideResults() and does also not /// follow our usual rules so it might not exist. Function/WAVE GetOverrideResults() diff --git a/Packages/tests/UTF_HelperFunctions.ipf b/Packages/tests/UTF_HelperFunctions.ipf index 192f62a19c..11286d82b4 100644 --- a/Packages/tests/UTF_HelperFunctions.ipf +++ b/Packages/tests/UTF_HelperFunctions.ipf @@ -1187,8 +1187,15 @@ End Function ResetOverrideResults() + CreateOverrideResults(0) +End + +Function/WAVE CreateOverrideResults(variable numRows) + KillOrMoveToTrash(wv = root:overrideResults) - Make/N=0 root:overrideResults + Make/N=(numRows) root:overrideResults/WAVE=wv + + return wv End Function [string baseSet, string stimsetList, string customWavePath, variable amplitude] CreateDependentStimset() From c5a1624723bab7d0c0aba2b7e9e0dd8c8415b2b9 Mon Sep 17 00:00:00 2001 From: Thomas Braun Date: Wed, 29 Jan 2025 15:59:57 +0100 Subject: [PATCH 2/5] UploadJSONPayload: Handle failed uploaded gracefully This avoids assertions in case the machine has no internet or the other side is down/misconfigured. --- Packages/MIES/MIES_MiesUtilities_Uploads.ipf | 19 +++++++++------- Packages/MIES/MIES_Utilities_System.ipf | 22 ++++++++++++++++-- Packages/tests/Basic/UTF_Utils_System.ipf | 24 +++++++++++++++++++- 3 files changed, 54 insertions(+), 11 deletions(-) diff --git a/Packages/MIES/MIES_MiesUtilities_Uploads.ipf b/Packages/MIES/MIES_MiesUtilities_Uploads.ipf index 7550654c20..2a8d03a34d 100644 --- a/Packages/MIES/MIES_MiesUtilities_Uploads.ipf +++ b/Packages/MIES/MIES_MiesUtilities_Uploads.ipf @@ -142,12 +142,7 @@ static Function UploadPing() jsonID = GenerateJSONTemplateForUpload() AddPayloadEntries(jsonID, {UPLOAD_BLOCK_USERPING}, {payload}, isBinary = 0) - AssertOnAndClearRTError() - try - UploadJSONPayload(jsonID); AbortOnRTE - catch - err = ClearRTError() - endtry + UploadJSONPayload(jsonID) JSON_Release(jsonID) return err @@ -241,7 +236,7 @@ Function UploadLogFiles([variable verbose, variable firstDate, variable lastDate string logPartStr, fNamePart, file, ticket, timeStamp string path, location, basePath, out - variable jsonID, numFiles, i, j, doFilter, isBinary, lastIndex, jsonIndex, partCnt, sumSize, fSize + variable ret, jsonID, numFiles, i, j, doFilter, isBinary, lastIndex, jsonIndex, partCnt, sumSize, fSize isBinary = 1 verbose = ParamIsDefault(verbose) ? 1 : !!verbose @@ -341,8 +336,16 @@ Function UploadLogFiles([variable verbose, variable firstDate, variable lastDate sprintf out, "Uploading %.0f MB (~%d Bytes)", sumSize / MEGABYTE, sumSize UploadLogFilesPrint(out, verbose) for(jsonID : jsonIDs) - UploadJSONPayload(jsonID) + ret = UploadJSONPayload(jsonID) JSON_Release(jsonID) + + if(ret) + sprintf out, "Error uploading the logfiles.\r" + UploadLogFilesPrint(out, verbose) + Make/FREE/N=(DimSize(jsonIDs, ROWS)) junk = JSON_Release(jsonIDs[p], ignoreErr = 1) + return NaN + endif + UploadLogFilesPrint(".", verbose) endfor UploadLogFilesPrint("\r", verbose) diff --git a/Packages/MIES/MIES_Utilities_System.ipf b/Packages/MIES/MIES_Utilities_System.ipf index a544000ff5..2b88c587e9 100644 --- a/Packages/MIES/MIES_Utilities_System.ipf +++ b/Packages/MIES/MIES_Utilities_System.ipf @@ -332,8 +332,26 @@ End /// See `tools/http-upload/upload-json-payload-v1.php` for the JSON format description. Function UploadJSONPayload(variable jsonID) - URLrequest/DSTR=(JSON_Dump(jsonID)) url="https://ai.customers.byte-physics.de/upload-json-payload-v1.php", method=put - ASSERT(!V_Flag, "URLrequest did not succeed due to: " + S_ServerResponse) + variable skip + +#ifdef AUTOMATED_TESTING + WAVE/Z overrideResults = GetOverrideResults() + skip = WaveExists(overrideResults) ? overrideResults[0] : 0 +#endif // AUTOMATED_TESTING + + if(!skip) + URLRequest/Z=1/DSTR=(JSON_Dump(jsonID)) url="https://ai.customers.byte-physics.de/upload-json-payload-v1.php", method=put + else + V_flag = 1 + S_ServerResponse = "fake error" + endif + + if(V_Flag) + LOG_AddEntry(PACKAGE_MIES, "URLRequest failed", keys = {"S_ServerResponse", "V_Flag"}, values = {S_ServerResponse, num2str(V_Flag)}, stacktrace = 1) + return 1 + endif + + return 0 End /// @brief Returns a hex string which is unique for the given Igor Pro session diff --git a/Packages/tests/Basic/UTF_Utils_System.ipf b/Packages/tests/Basic/UTF_Utils_System.ipf index e10766002c..9033c1eb29 100644 --- a/Packages/tests/Basic/UTF_Utils_System.ipf +++ b/Packages/tests/Basic/UTF_Utils_System.ipf @@ -25,7 +25,6 @@ // GetASLREnabledState // TurnOffASLR // IsWindows10 -// UploadJSONPayload // GetIgorInstanceID // CleanupOperationQueueResult @@ -89,3 +88,26 @@ static Function TestErrorCodeConversion() End /// @} + +/// UploadJSONPayload +/// @{ +static Function TestUploadJsonPayload() + + variable jsonID + string filename, logs, retFilename + + WAVE overrideResults = CreateOverrideResults(1) + overrideResults[] = 1 + + filename = LOG_GetFile(PACKAGE_MIES) + DeleteFile/Z filename + + jsonID = JSON_New() + UploadJSONPayload(jsonID) + JSON_Release(jsonID) + + [logs, retFilename] = LoadTextFile(filename) + CHECK_PROPER_STR(logs) + CHECK(GrepString(logs, "\"S_ServerResponse\":\"fake error\",\"V_Flag\":\"1\",\"action\":\"URLRequest failed")) +End +/// @} From 342b94dd1b95ca84bbb2a4dfd2f05daa51065a2d Mon Sep 17 00:00:00 2001 From: Thomas Braun Date: Tue, 4 Feb 2025 14:50:57 +0100 Subject: [PATCH 3/5] UploadJSONPayload: Release jsonID after the upload This avoids having each caller to care about that. --- Packages/MIES/MIES_MiesUtilities_Uploads.ipf | 3 --- Packages/MIES/MIES_Utilities_System.ipf | 4 +++- Packages/tests/Basic/UTF_Utils_System.ipf | 1 - 3 files changed, 3 insertions(+), 5 deletions(-) diff --git a/Packages/MIES/MIES_MiesUtilities_Uploads.ipf b/Packages/MIES/MIES_MiesUtilities_Uploads.ipf index 2a8d03a34d..6a5cd40b33 100644 --- a/Packages/MIES/MIES_MiesUtilities_Uploads.ipf +++ b/Packages/MIES/MIES_MiesUtilities_Uploads.ipf @@ -143,7 +143,6 @@ static Function UploadPing() jsonID = GenerateJSONTemplateForUpload() AddPayloadEntries(jsonID, {UPLOAD_BLOCK_USERPING}, {payload}, isBinary = 0) UploadJSONPayload(jsonID) - JSON_Release(jsonID) return err End @@ -215,7 +214,6 @@ Function UploadCrashDumps() #endif // DEBUGGING_ENABLED UploadJSONPayload(jsonID) - JSON_Release(jsonID) #ifndef DEBUGGING_ENABLED MoveFolder/P=$basePath "Diagnostics" as UniqueFileOrFolder(basePath, "Diagnostics_old") @@ -337,7 +335,6 @@ Function UploadLogFiles([variable verbose, variable firstDate, variable lastDate UploadLogFilesPrint(out, verbose) for(jsonID : jsonIDs) ret = UploadJSONPayload(jsonID) - JSON_Release(jsonID) if(ret) sprintf out, "Error uploading the logfiles.\r" diff --git a/Packages/MIES/MIES_Utilities_System.ipf b/Packages/MIES/MIES_Utilities_System.ipf index 2b88c587e9..3bbed18091 100644 --- a/Packages/MIES/MIES_Utilities_System.ipf +++ b/Packages/MIES/MIES_Utilities_System.ipf @@ -327,7 +327,7 @@ Function IsWindows10Or11() return GrepString(os, "^(Microsoft )?Windows 1[01]? ") End -/// @brief Upload the given JSON document +/// @brief Upload the given JSON document and release it /// /// See `tools/http-upload/upload-json-payload-v1.php` for the JSON format description. Function UploadJSONPayload(variable jsonID) @@ -346,6 +346,8 @@ Function UploadJSONPayload(variable jsonID) S_ServerResponse = "fake error" endif + JSON_Release(jsonID) + if(V_Flag) LOG_AddEntry(PACKAGE_MIES, "URLRequest failed", keys = {"S_ServerResponse", "V_Flag"}, values = {S_ServerResponse, num2str(V_Flag)}, stacktrace = 1) return 1 diff --git a/Packages/tests/Basic/UTF_Utils_System.ipf b/Packages/tests/Basic/UTF_Utils_System.ipf index 9033c1eb29..120e778227 100644 --- a/Packages/tests/Basic/UTF_Utils_System.ipf +++ b/Packages/tests/Basic/UTF_Utils_System.ipf @@ -104,7 +104,6 @@ static Function TestUploadJsonPayload() jsonID = JSON_New() UploadJSONPayload(jsonID) - JSON_Release(jsonID) [logs, retFilename] = LoadTextFile(filename) CHECK_PROPER_STR(logs) From 1257a96d407546b3b1f71fdbf2427dbbe230a716 Mon Sep 17 00:00:00 2001 From: Thomas Braun Date: Tue, 4 Feb 2025 15:23:38 +0100 Subject: [PATCH 4/5] UploadJSONPayloadAsync: Add asynchronous version --- Packages/MIES/MIES_Constants.ipf | 1 + Packages/MIES/MIES_IgorHooks.ipf | 2 ++ Packages/MIES/MIES_Utilities_System.ipf | 30 +++++++++++++++++++- Packages/MIES/MIES_WaveDataFolderGetters.ipf | 2 +- 4 files changed, 33 insertions(+), 2 deletions(-) diff --git a/Packages/MIES/MIES_Constants.ipf b/Packages/MIES/MIES_Constants.ipf index e5bc93d018..60f3ba9671 100644 --- a/Packages/MIES/MIES_Constants.ipf +++ b/Packages/MIES/MIES_Constants.ipf @@ -1671,6 +1671,7 @@ Constant POST_PLOT_FULL_UPDATE = 0x8 ///< Forces a complete update from scra ///@{ StrConstant WORKLOADCLASS_TP = "TestPulse" StrConstant WORKLOADCLASS_NWB = "nwb_writing" +StrConstant WORKLOADCLASS_URL = "json_payload_upload" ///@} /// @name Column numbers of epoch information diff --git a/Packages/MIES/MIES_IgorHooks.ipf b/Packages/MIES/MIES_IgorHooks.ipf index 1f9e392e4a..d6f208bc75 100644 --- a/Packages/MIES/MIES_IgorHooks.ipf +++ b/Packages/MIES/MIES_IgorHooks.ipf @@ -167,6 +167,8 @@ static Function IH_Cleanup() DFREF dfrNWB = GetNWBFolder() KilLVariables/Z dfrNWB:histRefNumber + + ASSERT(!ASYNC_WaitForWLCToFinishAndRemove(WORKLOADCLASS_URL, 300), "JSON Payload upload did not finish within timeout of 300s.") catch ClearRTError() BUG("Caught runtime error or assertion: " + num2istr(err)) diff --git a/Packages/MIES/MIES_Utilities_System.ipf b/Packages/MIES/MIES_Utilities_System.ipf index 3bbed18091..69abffcc69 100644 --- a/Packages/MIES/MIES_Utilities_System.ipf +++ b/Packages/MIES/MIES_Utilities_System.ipf @@ -327,10 +327,38 @@ Function IsWindows10Or11() return GrepString(os, "^(Microsoft )?Windows 1[01]? ") End +Function UploadJSONPayloadAsync(variable jsonID) + + DFREF threadDFR = ASYNC_PrepareDF("UploadJSONPayloadAsyncWorker", "UploadJSONPayloadAsyncReadout", WORKLOADCLASS_URL, inOrder = 0) + + ASYNC_AddParam(threadDFR, var = jsonID, name = "jsonID") + + ASYNC_Execute(threadDFR) +End + +threadsafe Function/DF UploadJSONPayloadAsyncWorker(DFREF threadDFR) + + variable jsonID, ret + + jsonID = ASYNC_FetchVariable(threadDFR, "jsonID") + + ret = UploadJSONPayload(jsonID) + + DFREF dfrOut = NewFreeDataFolder() + variable/G dfrOut:result = ret + + return dfrOut +End + +Function UploadJSONPayloadAsyncReadout(STRUCT ASYNC_ReadOutStruct &ar) + + // nothing to do +End + /// @brief Upload the given JSON document and release it /// /// See `tools/http-upload/upload-json-payload-v1.php` for the JSON format description. -Function UploadJSONPayload(variable jsonID) +threadsafe Function UploadJSONPayload(variable jsonID) variable skip diff --git a/Packages/MIES/MIES_WaveDataFolderGetters.ipf b/Packages/MIES/MIES_WaveDataFolderGetters.ipf index 71ed1f82d7..19783c0374 100644 --- a/Packages/MIES/MIES_WaveDataFolderGetters.ipf +++ b/Packages/MIES/MIES_WaveDataFolderGetters.ipf @@ -7593,7 +7593,7 @@ End /// This wave is created by MSQ_CreateOverrideResults(), /// PSQ_CreateOverrideResults(), TP_CreateOverrideResults(), CreateOverrideResults() and does also not /// follow our usual rules so it might not exist. -Function/WAVE GetOverrideResults() +threadsafe Function/WAVE GetOverrideResults() DFREF dfr = root: WAVE/Z/SDFR=dfr overrideResults From b6acc0a2f031434e1d9b5e42e658c8ccd0d9d940 Mon Sep 17 00:00:00 2001 From: Thomas Braun Date: Tue, 4 Feb 2025 15:43:33 +0100 Subject: [PATCH 5/5] treewide: Make uploads asynchronously --- Packages/MIES/MIES_MiesUtilities_Uploads.ipf | 32 ++++++-------------- 1 file changed, 9 insertions(+), 23 deletions(-) diff --git a/Packages/MIES/MIES_MiesUtilities_Uploads.ipf b/Packages/MIES/MIES_MiesUtilities_Uploads.ipf index 6a5cd40b33..66da69339d 100644 --- a/Packages/MIES/MIES_MiesUtilities_Uploads.ipf +++ b/Packages/MIES/MIES_MiesUtilities_Uploads.ipf @@ -32,9 +32,7 @@ Function UploadCrashDumpsDaily() return NaN endif - if(UploadCrashDumps()) - printf "Crash dumps have been successfully uploaded.\r" - endif + UploadCrashDumps() JSON_SetString(jsonID, "/diagnostics/last upload", GetIso8601TimeStamp()) AbortOnRTE @@ -142,7 +140,7 @@ static Function UploadPing() jsonID = GenerateJSONTemplateForUpload() AddPayloadEntries(jsonID, {UPLOAD_BLOCK_USERPING}, {payload}, isBinary = 0) - UploadJSONPayload(jsonID) + UploadJSONPayloadAsync(jsonID) return err End @@ -175,8 +173,6 @@ End /// The uploaded files are moved out of the way afterwards. /// /// See `tools/http-upload/upload-json-payload-v1.php` for the JSON format description. -/// -/// @return 1 if crash dumps had been uploaded, 0 otherwise Function UploadCrashDumps() string diagSymbPath, basePath, diagPath @@ -192,12 +188,9 @@ Function UploadCrashDumps() numLogs = DimSize(logs, ROWS) if(!numFiles && !numLogs) - return 0 + return NaN endif - printf "Please wait while we upload %d crash dumps. This might take a while.\r", numFiles + numLogs - ControlWindowToFront() - jsonID = GenerateJSONTemplateForUpload() AddPayloadEntriesFromFiles(jsonID, files, isBinary = 1) @@ -213,7 +206,7 @@ Function UploadCrashDumps() SaveTextFile(JSON_dump(jsonID, indent = 4), diagPath + ":" + UniqueFileOrFolder(basePath, "crash-dumps", suffix = ".json")) #endif // DEBUGGING_ENABLED - UploadJSONPayload(jsonID) + UploadJSONPayloadAsync(jsonID) #ifndef DEBUGGING_ENABLED MoveFolder/P=$basePath "Diagnostics" as UniqueFileOrFolder(basePath, "Diagnostics_old") @@ -221,7 +214,8 @@ Function UploadCrashDumps() DEBUGPRINT_ELAPSED(referenceTime) - return 1 + printf "Uploading %d crash dumps is in progress in the background.\r", numFiles + numLogs + ControlWindowToFront() End /// @brief Upload the MIES and ZeroMQ logfiles @@ -234,7 +228,7 @@ Function UploadLogFiles([variable verbose, variable firstDate, variable lastDate string logPartStr, fNamePart, file, ticket, timeStamp string path, location, basePath, out - variable ret, jsonID, numFiles, i, j, doFilter, isBinary, lastIndex, jsonIndex, partCnt, sumSize, fSize + variable jsonID, numFiles, i, j, doFilter, isBinary, lastIndex, jsonIndex, partCnt, sumSize, fSize isBinary = 1 verbose = ParamIsDefault(verbose) ? 1 : !!verbose @@ -334,22 +328,14 @@ Function UploadLogFiles([variable verbose, variable firstDate, variable lastDate sprintf out, "Uploading %.0f MB (~%d Bytes)", sumSize / MEGABYTE, sumSize UploadLogFilesPrint(out, verbose) for(jsonID : jsonIDs) - ret = UploadJSONPayload(jsonID) - - if(ret) - sprintf out, "Error uploading the logfiles.\r" - UploadLogFilesPrint(out, verbose) - Make/FREE/N=(DimSize(jsonIDs, ROWS)) junk = JSON_Release(jsonIDs[p], ignoreErr = 1) - return NaN - endif + UploadJSONPayloadAsync(jsonID) UploadLogFilesPrint(".", verbose) endfor UploadLogFilesPrint("\r", verbose) endif - UploadLogFilesPrint("Done.\r", verbose) - sprintf out, "Successfully uploaded the MIES, ZeroMQ-XOP and ITCXOP2 logfiles. Please mention your ticket \"%s\" if you are contacting support.\r", ticket + sprintf out, "Uploading the MIES, ZeroMQ-XOP and ITCXOP2 logfiles is in progress in the background. Please mention your ticket \"%s\" if you are contacting support.\r", ticket UploadLogFilesPrint(out, verbose) End