{"record":{"id":"469f64e419216239","repo":"flowable/flowable-engine","slug":"future-was-interrupted","errorCode":null,"errorMessage":"Future was interrupted","messagePattern":"Future was interrupted","errorType":"exception","errorClass":"FlowableException","httpStatus":null,"severity":"error","filePath":"modules/flowable-engine-common/src/main/java/org/flowable/common/engine/impl/agenda/ExecuteFutureActionOperation.java","lineNumber":42,"sourceCode":" */\npublic class ExecuteFutureActionOperation<T> implements Runnable {\n\n    protected final CompletableFuture<T> future;\n    protected final BiConsumer<T, Throwable> action;\n\n    public ExecuteFutureActionOperation(CompletableFuture<T> future, BiConsumer<T, Throwable> action) {\n        this.future = future;\n        this.action = action;\n    }\n\n    @Override\n    public void run() {\n        try {\n            T value = future.get();\n            action.accept(value, null);\n        } catch (InterruptedException e) {\n            Thread.currentThread().interrupt();\n            throw new FlowableException(\"Future was interrupted\", e);\n        } catch (CancellationException e) {\n            action.accept(null, new FlowableException(\"Future was canceled\", e));\n        } catch (ExecutionException e) {\n            action.accept(null, e.getCause());\n        }\n    }\n\n    public boolean isDone() {\n        return future.isDone();\n    }\n\n    public CompletableFuture<T> getFuture() {\n        return future;\n    }\n\n    public BiConsumer<T, Throwable> getAction() {\n        return action;\n    }","sourceCodeStart":24,"sourceCodeEnd":60,"githubUrl":"https://github.com/flowable/flowable-engine/blob/d6d39ce1c69ff244f2d9dc6af756a9b95e865586/modules/flowable-engine-common/src/main/java/org/flowable/common/engine/impl/agenda/ExecuteFutureActionOperation.java#L24-L60","documentation":"Thrown by ExecuteFutureActionOperation.run when Thread.interrupt() is called while the operation is blocked in future.get(). The interrupt status is restored and wrapped in a FlowableException so the engine operation loop can surface the interruption.","triggerScenarios":"Another thread or a timeout mechanism interrupts the thread executing this agenda operation while it waits for an async future to complete (e.g. job executor shutdown, external cancel of a waiting command).","commonSituations":"Engine/task executor shutdown while async operations are pending; watchdog timeouts interrupting long-running waits; application container redeploy interrupting worker threads.","solutions":["Investigate who interrupted the thread (shutdown hook, timeout watchdog) and ensure shutdown sequences drain pending operations before interrupting.","Increase or configure the max wait timeout on the waiting future so it completes before external interruption.","Ensure async jobs/async executor are properly started and futures complete; long-pending futures usually mean the async side failed to run.","Catch FlowableException in custom command code and check Thread.currentThread().isInterrupted() to handle cancellation gracefully."],"exampleFix":"// before\nfuture.get(); // blocks indefinitely, vulnerable to interrupt\n// after\nfuture.get(30, TimeUnit.SECONDS); // bounded wait; handle TimeoutException explicitly","handlingStrategy":"try-catch","validationCode":"if (future.isDone() || future.getNow(null) != null) { /* safe to proceed */ }","typeGuard":null,"tryCatchPattern":"try {\n  executeFutureActionOperation.run();\n} catch (FlowableException e) {\n  if (e.getCause() instanceof InterruptedException) {\n    Thread.currentThread().interrupt(); // propagate cancellation\n    return;\n  }\n  throw e;\n}","preventionTips":["Use bounded future.get timeouts instead of indefinite blocking.","Shut down executors gracefully, draining pending operations before interrupting threads.","Keep async jobs healthy so futures complete quickly.","Preserve and check the interrupt status in custom agenda code."],"tags":["concurrency","interrupt","future","async"],"backgroundTag":"operation-timeout","analyzedSha":"d6d39ce1c69ff244f2d9dc6af756a9b95e865586","analyzedAt":"2026-09-11T06:41:19.413Z","contentChangedAt":"2026-09-11T06:41:19.413Z","schemaVersion":2},"datasetVersion":"2026-09-14T05:17:10.506Z"}