{"record":{"id":"4302ec7e439514be","repo":"elastic/elasticsearch","slug":"retry-interrupted","errorCode":null,"errorMessage":"Retry interrupted","messagePattern":"Retry interrupted","errorType":"exception","errorClass":"RuntimeException","httpStatus":null,"severity":"error","filePath":"build-tools/src/main/java/org/elasticsearch/gradle/util/GradleUtils.java","lineNumber":228,"sourceCode":"     * @param retries number of retries before giving up\n     * @param runnable action to run\n     * */\n    public static void withRetries(int retries, int gracePeriodInS, Runnable runnable) {\n        int delay = gracePeriodInS;\n        for (int attempt = 0; attempt <= retries; attempt++) {\n            try {\n                runnable.run();\n                return;\n            } catch (GradleException e) {\n                if (attempt == retries) {\n                    throw e;\n                }\n                System.out.println(\"Attempt \" + (attempt + 1) + \" failed, retrying in \" + delay + \" seconds...\");\n                try {\n                    Thread.sleep(delay * 1000L);\n                } catch (InterruptedException ie) {\n                    Thread.currentThread().interrupt();\n                    throw new RuntimeException(\"Retry interrupted\", ie);\n                }\n                // After the first sleep, increase delay by 20 seconds once, then grow by gracePeriodInS each retry\n                if (attempt == 0) {\n                    delay = gracePeriodInS + 20;\n                } else {\n                    delay += gracePeriodInS;\n                }\n            }\n        }\n    }\n}\n","sourceCodeStart":210,"sourceCodeEnd":240,"githubUrl":"https://github.com/elastic/elasticsearch/blob/db6a809a667c081ca1dc7500389d26975573215f/build-tools/src/main/java/org/elasticsearch/gradle/util/GradleUtils.java#L210-L240","documentation":"Thrown by the GradleUtils retry helper when Thread.sleep during backoff between attempts is interrupted. The method restores the interrupt flag (Thread.currentThread().interrupt()) and wraps the InterruptedException in a RuntimeException. It indicates the build thread was signalled to stop while waiting to retry a flaky GradleException-throwing operation.","triggerScenarios":"Another thread calls Thread.interrupt() while the retry loop is sleeping between attempts, e.g. a Gradle daemon shutdown, worker cancellation, or explicit build abort during a network-retry backoff.","commonSituations":"User cancels the build (Ctrl+C) mid-retry; Gradle worker executor cancels a long-running task; a parent process sends an interrupt to the build JVM during backoff.","solutions":["Avoid interrupting the build while a retried operation is in its backoff sleep.","If invoking retry programmatically, ensure the calling thread's interrupt status is clear before entry.","For cooperative cancellation, use a flag checked by the runnable instead of Thread.interrupt().","Reduce retry count or delay so the backoff window exposed to interruption is shorter."],"exampleFix":null,"handlingStrategy":"try-catch","validationCode":null,"typeGuard":null,"tryCatchPattern":"try {\n    GradleUtils.retry(runnable, retries, gracePeriodInS);\n} catch (RuntimeException e) {\n    if (Thread.currentThread().isInterrupted()) {\n        // build was cancelled during backoff — shut down gracefully\n    } else {\n        throw e;\n    }\n}","preventionTips":["Do not interrupt build threads while network retries are in progress.","Prefer cooperative cancellation flags over Thread.interrupt() for stopping retries.","Keep retry counts and delays small so the interruption-prone window is short."],"tags":["retry","threading","interruption","build-tools"],"analyzedSha":"db6a809a667c081ca1dc7500389d26975573215f","analyzedAt":"2026-08-12T01:39:14.192Z","schemaVersion":2},"datasetVersion":"2026-08-12T08:17:17.861Z"}