Multi-instance parallel/sequential calls are getting stuck

Hello,

I have series of calls which I need to make either in sequential/parallel manner (based on the input). I’m using multiInstanceLoopCharacteristics with subprocess in order to achieve the same.

Here’s the bpmn,
check in the comments.

Flowable: 6.7.0
Springboot: 2.4.3
PostgreSQL: 11

Ignore the two different subprocesses, that’ll be enhanced later

Issue here is that if I run multiple calls (more than 5) simultaneously then processes are getting stuck. I checked the database and after a certain point of time, act_ru_job and act_ru_execution table stop getting updated. There isn’t any specific task where it is getting stuck.
There are known issues of subprocess with parallel multiInstanceLoopCharacteristics and for this following are the blogs I’ve read and followed the recommendation,

  1. series of Handling asynchronous operations with Flowable – Part 1: Introducing the new Async Executor – Flowable Blog
  2. True Parallel Service Task Execution with Flowable – Flowable Blog

Check the comment section for one of the class implementations

For Flowable Configurations, I’m using mainly the default ones, and below are additional configurations,

@Bean
    public EngineConfigurationConfigurer<SpringProcessEngineConfiguration> configurer() {
        return engineConfiguration -> {
            engineConfiguration.setDataSource(postgresDbProvider.getDataSource());
            engineConfiguration.setDatabaseSchemaUpdate(Boolean.toString(true));
            engineConfiguration.setAsyncHistoryExecutorActivate(false);
            engineConfiguration.setAsyncHistoryEnabled(false);
            engineConfiguration.setHistory(HistoryLevel.NONE.getKey());

            //Async Executor
            engineConfiguration.setAsyncExecutorActivate(true);
            engineConfiguration.setAsyncExecutorNumberOfRetries(0);
        };
    }

An additional point, I took a thread dump and noticed that there are 8 threads for flowable tasks and all are in state WAITING with lockName “java.util.concurrent.CompletableFuture$Signaller@…”. Do I need to do anything explicit in this scenario?

Help would be really appreciated here.

Regards,
aashi

BPMN:

<?xml version="1.0" encoding="UTF-8"?>
<definitions xmlns="http://www.omg.org/spec/BPMN/20100524/MODEL" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
             xmlns:flowable="http://flowable.org/bpmn"
             xmlns:bpmndi="http://www.omg.org/spec/BPMN/20100524/DI"
             xmlns:omgdc="http://www.omg.org/spec/DD/20100524/DC"
             xmlns:omgdi="http://www.omg.org/spec/DD/20100524/DI"
             typeLanguage="http://www.w3.org/2001/XMLSchema"
             expressionLanguage="http://www.w3.org/1999/XPath"
             targetNamespace="http://www.flowable.org/processdef">
    <signal id="sequentialAbortSignal" name="Sequential Abort Signal"></signal>
    <signal id="parallelAbortSignal" name="Parallel Abort Signal"></signal>
    <process id="CAS_IMPORT" name="CAS Import Scenario" isExecutable="true">

        <startEvent id="idStartEvent" name="Start Event"></startEvent>
        <sequenceFlow id="sid-229F1647-5E61-473F-92BB-FFC4F4D61CB9" sourceRef="idStartEvent" targetRef="idParseDescriptorsAndValidationsAndOrderList"></sequenceFlow>

        <serviceTask id="idParseDescriptorsAndValidationsAndOrderList" name="Parse descriptors and Validations" flowable:async="true" flowable:delegateExpression="${parseDescriptorsAndValidationsAndOrderList}"></serviceTask>
        <sequenceFlow id="sid-2EDC0D10-F5F4-45D8-8B01-88DF1D10FDE5" sourceRef="idParseDescriptorsAndValidationsAndOrderList" targetRef="deploymentModeExGateway"></sequenceFlow>

        <exclusiveGateway id="deploymentModeExGateway" name="Deployment Mode" default="sid-383F66F1-5539-4025-A4EB-91F2A2CC21BE"></exclusiveGateway>
        <sequenceFlow id="sid-383F66F1-5539-4025-A4EB-91F2A2CC21BE" sourceRef="deploymentModeExGateway" targetRef="idComputeNextModulesSequential"></sequenceFlow>
        <sequenceFlow id="sid-8FB602D5-5C46-407B-8B1F-36579A41CE30" sourceRef="deploymentModeExGateway" targetRef="idComputeNextModules">
            <conditionExpression xsi:type="tFormalExpression"><![CDATA[${(isValidDescriptor == "YES" && deployInParallel)}]]></conditionExpression>
        </sequenceFlow>
        <sequenceFlow id="sid-9E93940E-B548-4A8B-BFE0-8D68E292B3A8" sourceRef="deploymentModeExGateway" targetRef="idCASDeleteReources">
            <conditionExpression xsi:type="tFormalExpression"><![CDATA[${(isValidDescriptor == "NO")}]]></conditionExpression>
        </sequenceFlow>

        <serviceTask id="idComputeNextModulesSequential" name="Compute next modules to deploy sequentially" flowable:delegateExpression="${computeNextModulesSequentially}"></serviceTask>
        <sequenceFlow id="sid-BCDCC4CB-9F0A-407E-BD70-D70DA957673C" sourceRef="idComputeNextModulesSequential" targetRef="seqSubProcess"></sequenceFlow>

        <subProcess id="seqSubProcess" name="subProcess">
            <multiInstanceLoopCharacteristics isSequential="true" flowable:collection="moduleList" flowable:elementVariable="currentModuleForDeployment"></multiInstanceLoopCharacteristics>

            <startEvent id="sid-5E3ACF9B-DF6F-4778-BE3D-2FC3A6D85814"></startEvent>
            <sequenceFlow id="sid-251E3F33-4CED-4061-8575-98F917404C3B" sourceRef="sid-5E3ACF9B-DF6F-4778-BE3D-2FC3A6D85814" targetRef="idPrepareClientConfiguration"></sequenceFlow>

            <serviceTask id="idPrepareClientConfiguration" name="Get Version and Prepare Deployer Client Configuration" flowable:delegateExpression="${prepareClientConfiguration}"></serviceTask>
            <sequenceFlow id="sid-F3486366-C86E-4B84-81A0-4CA89CCEE1A3" sourceRef="idPrepareClientConfiguration" targetRef="idUploadAndDeploy">
                <conditionExpression xsi:type="tFormalExpression"><![CDATA[${!isUploadAndDeployFailed}]]></conditionExpression>
            </sequenceFlow>
            <sequenceFlow id="sid-7B4E8150-12B5-429B-ABC1-AFBD60972782" sourceRef="idPrepareClientConfiguration" targetRef="idHandleUploadAndDeployFailure">
                <conditionExpression xsi:type="tFormalExpression"><![CDATA[${isUploadAndDeployFailed}]]></conditionExpression>
            </sequenceFlow>

            <serviceTask id="idUploadAndDeploy" name="Upload and Deploy" flowable:delegateExpression="${uploadAndDeploy}"></serviceTask>
            <sequenceFlow id="sid-D643E813-BEFE-4845-83AB-408EC3BAA5B0" sourceRef="idUploadAndDeploy" targetRef="idGetGACDStatus">
                <conditionExpression xsi:type="tFormalExpression"><![CDATA[${!isUploadAndDeployFailed}]]></conditionExpression>
            </sequenceFlow>
            <sequenceFlow id="sid-7B4E8150-12B5-429B-ABC1-AFBD60972783" sourceRef="idUploadAndDeploy" targetRef="idHandleUploadAndDeployFailure">
                <conditionExpression xsi:type="tFormalExpression"><![CDATA[${isUploadAndDeployFailed}]]></conditionExpression>
            </sequenceFlow>

            <serviceTask id="idHandleUploadAndDeployFailure" name="Handle Upload and Deploy Failure" flowable:delegateExpression="${handleUploadAndDeployFailure}"></serviceTask>
            <sequenceFlow id="sid-F3486366-C86E-4B84-81A0-4CA89CCEE1B3" sourceRef="idHandleUploadAndDeployFailure" targetRef="idCASPreparModuleForDeployment"></sequenceFlow>

            <serviceTask id="idGetGACDStatus" name="Get Status" flowable:delegateExpression="${getGACDStatus}"></serviceTask>
            <sequenceFlow id="sid-3C73E1CA-3D9E-42C4-A2A9-20930119FDCB" sourceRef="idGetGACDStatus" targetRef="idGetGACDLogs"></sequenceFlow>

            <serviceTask id="idGetGACDLogs" name="Get Logs" flowable:delegateExpression="${getGACDLogs}"></serviceTask>
            <sequenceFlow id="sid-2A910F8E-3BE0-4CDC-A31C-0713AE34407E" sourceRef="idGetGACDLogs" targetRef="idGACDDelete"></sequenceFlow>

            <serviceTask id="idGACDDelete" name="Delete Content" flowable:delegateExpression="${gACDDelete}"></serviceTask>
            <sequenceFlow id="sid-DC9D452D-4920-4650-A6AA-0B5402909951" sourceRef="idGACDDelete" targetRef="idCASPreparModuleForDeployment"></sequenceFlow>

            <serviceTask id="idCASPreparModuleForDeployment" name="Prepare Next Module For Deployment" flowable:delegateExpression="${prepareModuleForDeployment}"></serviceTask>
            <sequenceFlow id="sid-B86B6F7A-516A-422F-A3A8-41C3FAFDF255" sourceRef="idCASPreparModuleForDeployment" targetRef="sid-72B86C42-C862-44FD-968C-3FD9FFAA9821">
                <conditionExpression xsi:type="tFormalExpression"><![CDATA[${!isProcessAborted}]]></conditionExpression>
            </sequenceFlow>
            <sequenceFlow id="sid-BBE0F6A4-C634-4996-976A-7D6DAC4B5EAF" sourceRef="idCASPreparModuleForDeployment" targetRef="idThrowSequentialSignal">
                <conditionExpression xsi:type="tFormalExpression"><![CDATA[${isProcessAborted}]]></conditionExpression>
            </sequenceFlow>

            <intermediateThrowEvent id="idThrowSequentialSignal" name="Throw Signal Event for Sequential Process Abort">
                <signalEventDefinition signalRef="sequentialAbortSignal"></signalEventDefinition>
            </intermediateThrowEvent>
            <sequenceFlow id="sid-ECB2A637-BEFB-402C-83F6-7EEE2C8938E0" sourceRef="idThrowSequentialSignal" targetRef="sid-72B86C42-C862-44FD-968C-3FD9FFAA9821"></sequenceFlow>

            <endEvent id="sid-72B86C42-C862-44FD-968C-3FD9FFAA9821"></endEvent>
        </subProcess>
        <sequenceFlow id="sid-4A0C878F-B42D-4CBC-9D36-5B32353D6C56" sourceRef="seqSubProcess" targetRef="idCASDeleteReources"></sequenceFlow>

        <boundaryEvent id="catchSeqErrorToAbortProcess" attachedToRef="seqSubProcess" cancelActivity="true">
            <signalEventDefinition signalRef="sequentialAbortSignal"></signalEventDefinition>
        </boundaryEvent>
        <sequenceFlow id="sid-C8D59D2C-4244-4EB0-B0FB-FF5878BE8434" sourceRef="catchSeqErrorToAbortProcess" targetRef="idCASDeleteReources"></sequenceFlow>

        <serviceTask id="idComputeNextModules" name="Compute next modules to deploy parallelly" flowable:delegateExpression="${computeNextModules}"></serviceTask>
        <sequenceFlow id="sid-5532E5C7-60F6-4093-8C58-A55FAE136192" sourceRef="idComputeNextModules" targetRef="parSubProcess"></sequenceFlow>

        <subProcess id="parSubProcess" name="subProcess">
            <multiInstanceLoopCharacteristics isSequential="false" flowable:collection="modulesToIterateInParallel" flowable:elementVariable="currentModuleForDeployment"></multiInstanceLoopCharacteristics>
            <startEvent id="parSubProcessStart"></startEvent>
            <sequenceFlow id="sid-21BCE72F-3F33-4D70-8BE3-AE2F24EFF32C" sourceRef="parSubProcessStart" targetRef="idPrepareClientConfigurationP"></sequenceFlow>

            <serviceTask id="idPrepareClientConfigurationP" name="Get Version and Prepare Deployer Client Configuration" flowable:delegateExpression="${prepareClientConfiguration}"></serviceTask>
            <sequenceFlow id="sid-F3486366-C86E-4B84-81A0-4CA89CCEE1A1" sourceRef="idPrepareClientConfigurationP" targetRef="idUploadAndDeployP">
                <conditionExpression xsi:type="tFormalExpression"><![CDATA[${!isUploadAndDeployFailed}]]></conditionExpression>
            </sequenceFlow>
            <sequenceFlow id="sid-7B4E8150-12B5-429B-ABC1-AFBD60972781" sourceRef="idPrepareClientConfigurationP" targetRef="idHandleUploadAndDeployFailureP">
                <conditionExpression xsi:type="tFormalExpression"><![CDATA[${isUploadAndDeployFailed}]]></conditionExpression>
            </sequenceFlow>

            <serviceTask id="idUploadAndDeployP" name="Upload and Deploy" flowable:delegateExpression="${uploadAndDeploy}"></serviceTask>
            <sequenceFlow id="sid-F3486366-C86E-4B84-81A0-4CA89CCEE1A2" sourceRef="idUploadAndDeployP" targetRef="idGetGACDStatusP">
                <conditionExpression xsi:type="tFormalExpression"><![CDATA[${!isUploadAndDeployFailed}]]></conditionExpression>
            </sequenceFlow>
            <sequenceFlow id="sid-7B4E8150-12B5-429B-ABC1-AFBD60972780" sourceRef="idUploadAndDeployP" targetRef="idHandleUploadAndDeployFailureP">
                <conditionExpression xsi:type="tFormalExpression"><![CDATA[${isUploadAndDeployFailed}]]></conditionExpression>
            </sequenceFlow>

            <serviceTask id="idHandleUploadAndDeployFailureP" name="Handle Upload and Deploy Failure" flowable:delegateExpression="${handleUploadAndDeployFailure}"></serviceTask>
            <sequenceFlow id="sid-F3486366-C86E-4B84-81A0-4CA89CCEE1B0" sourceRef="idHandleUploadAndDeployFailureP" targetRef="idCASPreparModuleForDeploymentP"></sequenceFlow>

            <serviceTask id="idGetGACDStatusP" name="Get Status" flowable:delegateExpression="${getGACDStatus}"></serviceTask>
            <sequenceFlow id="sid-26D1B58A-A083-4AA5-977E-F35E7AE99CCE" sourceRef="idGetGACDStatusP" targetRef="idGetGACDLogsP"></sequenceFlow>

            <serviceTask id="idGetGACDLogsP" name="Get Logs" flowable:delegateExpression="${getGACDLogs}"></serviceTask>
            <sequenceFlow id="sid-3834AB76-1061-4FAB-990F-8CAC39ACEFA4" sourceRef="idGetGACDLogsP" targetRef="idGACDDeleteP"></sequenceFlow>

            <serviceTask id="idGACDDeleteP" name="Delete Content" flowable:delegateExpression="${gACDDelete}"></serviceTask>
            <sequenceFlow id="sid-FA4F4B5F-2001-4F8C-B614-976C6C43F834" sourceRef="idGACDDeleteP" targetRef="idCASPreparModuleForDeploymentP"></sequenceFlow>

            <serviceTask id="idCASPreparModuleForDeploymentP" name="Prepare Next Module For Deployment" flowable:delegateExpression="${prepareModuleForDeployment}"></serviceTask>
            <sequenceFlow id="sid-0E24E68D-D39B-46F4-9A6B-512443BFA4D6" sourceRef="idCASPreparModuleForDeploymentP" targetRef="sid-33E34BEF-20D1-4F7D-8C58-DA2F1F4B0F19">
                <conditionExpression xsi:type="tFormalExpression"><![CDATA[${!isProcessAborted}]]></conditionExpression>
            </sequenceFlow>
            <sequenceFlow id="sid-5652CDE3-C62B-45BF-8077-FAEDC0CC3A73" sourceRef="idCASPreparModuleForDeploymentP" targetRef="idThrowParallelSignal">
                <conditionExpression xsi:type="tFormalExpression"><![CDATA[${isProcessAborted}]]></conditionExpression>
            </sequenceFlow>

            <intermediateThrowEvent id="idThrowParallelSignal" name="Throw Signal Event for Parallel Process Abort">
                <signalEventDefinition signalRef="parallelAbortSignal"></signalEventDefinition>
            </intermediateThrowEvent>
            <sequenceFlow id="sid-90FBA2FB-DEF0-4480-8063-E7BC39025034" sourceRef="idThrowParallelSignal" targetRef="sid-33E34BEF-20D1-4F7D-8C58-DA2F1F4B0F19"></sequenceFlow>

            <endEvent id="sid-33E34BEF-20D1-4F7D-8C58-DA2F1F4B0F19"></endEvent>
        </subProcess>
        <sequenceFlow id="sid-E344588E-CC9F-4BC1-A6CF-50A4F2360335" sourceRef="parSubProcess" targetRef="parallelDeploymentStatusCheck"></sequenceFlow>

        <boundaryEvent id="catchParallelErrorToAbortProcess" attachedToRef="parSubProcess" cancelActivity="true">
            <signalEventDefinition signalRef="parallelAbortSignal"></signalEventDefinition>
        </boundaryEvent>
        <sequenceFlow id="sid-B744C8A8-F68F-4827-99C3-B6D8BCA29663" sourceRef="catchParallelErrorToAbortProcess" targetRef="idCASDeleteReources"></sequenceFlow>

        <exclusiveGateway id="parallelDeploymentStatusCheck" name="Parllel deployment done or all modules completed" default="sid-2A2E5272-3227-4804-AFCD-9C64A51E2F83"></exclusiveGateway>
        <sequenceFlow id="sid-2A2E5272-3227-4804-AFCD-9C64A51E2F83" sourceRef="parallelDeploymentStatusCheck" targetRef="idComputeNextModules"></sequenceFlow>
        <sequenceFlow id="sid-8E2FFB48-D4F0-4594-9F95-D6E09849554E" sourceRef="parallelDeploymentStatusCheck" targetRef="idCASDeleteReources">
            <conditionExpression xsi:type="tFormalExpression"><![CDATA[${(modulesToDeploy.size() == completedModules.size())}]]></conditionExpression>
        </sequenceFlow>

        <serviceTask id="idCASDeleteReources" name="CAS Delete Reources from Disk" flowable:delegateExpression="${cASDeleteResources}"></serviceTask>
        <sequenceFlow id="sid-FBA5986F-44A1-4BE4-80BA-B005A572E1A8" sourceRef="idCASDeleteReources" targetRef="idEndEvent"></sequenceFlow>

        <endEvent id="idEndEvent" name="End Event"></endEvent>
    </process>
</definitions>

Class:

@Service(“uploadAndDeploy”)
public class UploadAndDeploy implements MapBasedFlowableFutureJavaDelegate {

private final Logger logger = LoggerFactory.getLogger(getClass());

@Autowired
CASDbOperationManager dbOperationManager;

@Autowired
CASHttpRequestExecutor httpRequestExecutor;

@Lookup
public DeployHandlerV2 getV2() {
    return null;
}

@SneakyThrows
@Override
public Map<String, Object> execute(ReadOnlyDelegateExecution execution) {
    //this variable is picked directly from casimport.bpmn20.xml
    String moduleName = (String) execution.getVariable(FlowableConstants.contextVariables.CURRENTMODULEFORDEPLOYMENT);

    logger.info(MessageFormat.format(CASEngineConstants.ImportLogs.TASK_UPLOAD_AND_DEPLOY, execution.getProcessInstanceId(), moduleName));

    Map<String, Map<String, String>> deploymentDetails = (Map<String, Map<String, String>>) execution.getVariable(FlowableConstants.contextVariables.deploymentDetails);
    Map<String, String> moduleDeploymentDetails = new HashMap<>();
    int numOfDeployedModules = (int) execution.getVariable(FlowableConstants.contextVariables.NUMOFDEPLOYEDMODULES);
    String processInstanceId = execution.getProcessInstanceId();
    DeployHandlerV2 deployHandlerV2 = getV2();

    //getting execution variable from flowable context
    String service = ((Map<String, List<String>>) execution.getVariable(FlowableConstants.contextVariables.SERVICENAMESMAP)).get(moduleName).get(0);

    String location = ((Map<String, String>) execution.getVariable(FlowableConstants.contextVariables.FILELOCATIONMAP)).get(moduleName);
    Map<String, Object> configMap = (Map<String, Object>) ((Map<String, Object>) execution.getVariable(FlowableConstants.contextVariables.MODULECONFIGMAP)).getOrDefault(moduleName, null);
    String mtarPath = (String) execution.getVariable(FlowableConstants.contextVariables.MTAR);
    File mtar = new File(mtarPath);
    String user = (String) execution.getVariable(FlowableConstants.contextVariables.USERNAME);
    String zoneID = (String) execution.getVariable(FlowableConstants.contextVariables.ZONE);
    if (StringUtils.isEmpty(user)) {
        user = zoneID;
    }
    Map<String, Object> outputMap = new HashMap<>();
    Map<String, Object> resultMap = new HashMap<>();

    try {
        DeployerClientConfiguration deployerClientConfiguration = (DeployerClientConfiguration) execution.getVariable(moduleName);//fetches object from memory

        logger.info(MessageFormat.format(CASEngineConstants.ImportLogs.START_DEPLOYMENT, processInstanceId, moduleName));
        String token = deployerClientConfiguration.getToken();
        String version = deployerClientConfiguration.getVersion();
        Map<String, String> headerInfo = deployerClientConfiguration.getHeaders();
        try (CloseableHttpClient closeableHttpClient = httpRequestExecutor.getCustomClient(token, headerInfo)) {
            if (GACDConstants.Versions.v2.equalsIgnoreCase(version)) {
                deployHandlerV2.init(closeableHttpClient, deployerClientConfiguration.getProviderUrl(), deployerClientConfiguration.getPath());
                resultMap = deployHandlerV2.deployV2(mtar, location, configMap, user, moduleName, processInstanceId);
            }
        }

        resultMap.put(CASEngineConstants.Common.CONTENTTYPE, service);

        String contentId = (String) resultMap.getOrDefault(FlowableConstants.contextVariables.CONTENTID, null);
        if (StringUtils.isNotEmpty(contentId)) {
            moduleDeploymentDetails.put(FlowableConstants.contextVariables.CONTENTID, contentId);
        }
        String deployResourceId = (String) resultMap.getOrDefault(FlowableConstants.contextVariables.DEPLOYRESOURCEID, null);
        if (StringUtils.isNotEmpty(deployResourceId)) {
            moduleDeploymentDetails.put(FlowableConstants.contextVariables.DEPLOYRESOURCEID, deployResourceId);
        } else {
            logger.info(MessageFormat.format(CASEngineConstants.ImportLogs.NO_DEPLOYRESOURCEID_FOUND, processInstanceId, moduleName));
            dbOperationManager.saveLogs(MessageFormat.format(CASEngineConstants.ImportLogs.NO_DEPLOYRESOURCEID_FOUND, processInstanceId, moduleName), processInstanceId, CASEngineConstants.severity.ERROR, zoneID, "");
            throw new CASException(MessageFormat.format(CASEngineConstants.ImportLogs.NO_DEPLOYRESOURCEID_FOUND, processInstanceId, moduleName), HttpStatus.INTERNAL_SERVER_ERROR);
        }
        dbOperationManager.saveLogs(MessageFormat.format(CASEngineConstants.ImportLogs.DEPLOYMENT_STARTED, moduleName), processInstanceId, CASEngineConstants.severity.INFO, zoneID, null);

        //setting deploymentDetails
        deploymentDetails.put(moduleName, moduleDeploymentDetails);
        outputMap.put(FlowableConstants.contextVariables.deploymentDetails, deploymentDetails);

        //increasing NUMOFDEPLOYEDMODULES to move on to next module
        outputMap.put(FlowableConstants.contextVariables.NUMOFDEPLOYEDMODULES, ++numOfDeployedModules);

        //update flag UPLOAD_AND_DEPLOY_FAILED in flowable context to false
        outputMap.put(FlowableConstants.contextVariables.isUploadAndDeployFailed, false);
    } catch (Exception ex) {
        outputMap.put(FlowableConstants.contextVariables.isUploadAndDeployFailed, true);
        outputMap.put(FlowableConstants.contextVariables.ERRORMSG, ex.getMessage());
    }
    return outputMap;
}

}

Hello,
After testing a little more we were able to pinpoint that one of our implementations was getting stuck due to which execution couldn’t be completed by flowable and hence engine wasn’t able to pick any further task unless the application was restarted. And all 8 threads were blocked with the same execution.

After resolving the service implementation issue, it’s working fine now. But in the future, if such an issue occurs again due to which all the threads get occupied then is there any possibility to release thread from that execution based on a timer to avoid application restart?

No, that’s part of the JDK threading: if the thread is truly executing logic all the time, it won’t be interruptable.