Solution of Spring Timing Task Stopping Without Reason and Not Reporting Error

  • 2021-12-09 08:50:07
  • OfStack

Directory Spring timing task stops without reason and does not report error solution Spring timing task runs out and no longer starts spring timing task has the following two characteristics, troubleshooting methods and solutions

Spring timing task stops without reason and does not report errors

1 At the beginning, the timer provided by Spring was used to configure the timing task, which is simple and quick. The configuration is as follows:


<bean id="refreshCache" class="com.gionee.baserom.search.job.RefreshCache" />
<task:scheduled-tasks>
    <task:scheduled ref="refreshCache" method="execute" cron="0 */30 * * * ?"/>
</task:scheduled-tasks>

However, after using it for 1 period of time, it stops without reason and does not report errors, so there is no relevant error log, and it is necessary to restart Tomcat before continuing to execute timed tasks.

At first, I thought that due to the limit of the maximum number of connections in the database, this problem still occurred after being set to double. Under the reminder of my classmates, I realized that it might be caused by thread blocking, so I found the reason online:

Spring timed tasks are executed concurrently by default, and will not wait for the last task to be completed, but will be executed as long as the interval is up.

Solutions

1. Configure the concurrent property of JobDetail to false. Concurrent execution of tasks is not allowed.

2. When the task takes a long time to execute, find the root problem.

Therefore, the timer provided by Spring is changed to Quartz, relying on related packages:


<dependency>
        <groupId>org.quartz-scheduler</groupId>
        <artifactId>quartz</artifactId>
        <version>2.2.1</version>
</dependency>

Timing tasks are configured as follows:


<!--  Working bean -->
    <bean id="myJob" class=" com.gionee.baserom.exchangerate.job.DailyTaskJob" />
    <!--  To define a task, in order to avoid thread blocking, use the concurrent=false -->
    <bean id="myJobDetail"
        class="org.springframework.scheduling.quartz.MethodInvokingJobDetailFactoryBean">
        <property name="targetObject" ref="myJob" />
        <property name="targetMethod" value="execute" />
        <property name="concurrent" value="false" />
    </bean>
    <!--  Configure triggers   -->
    <bean id="myJobTrigger"
        class="org.springframework.scheduling.quartz.CronTriggerFactoryBean">
        <property name="jobDetail" ref="myJobDetail" />
        <property name="cronExpression" value="0 0/30 * * * ?" />
    </bean>
    <!--  Configure scheduler  -->
    <bean name="startQuertz" lazy-init="false" autowire="no" destroy-method="destroy" 
        class="com.gionee.baserom.exchangerate.util.SchedulerFactoryBeanWithShutdownDelay" >
        <property name="quartzProperties">
            <props>
                <prop key="org.quartz.threadPool.threadCount">1</prop>
            </props>
        </property>
        <property name="waitForJobsToCompleteOnShutdown">
            <value>false</value>
        </property>
        <property name="triggers">
            <list>
                <ref bean="myJobTrigger" />
            </list>
        </property>
    </bean>

SchedulerFactoryBeanWithShutdownDelay is used in startQuartz because when Tomcat is shut down, the task thread may not be completely shut down, resulting in a memory leak.

SchedulerFactoryBeanWithShutdownDelay.java


import org.quartz.SchedulerException;
import org.springframework.scheduling.quartz.SchedulerFactoryBean;
public class SchedulerFactoryBeanWithShutdownDelay extends SchedulerFactoryBean {
    @Override  
    public void destroy() throws SchedulerException {  
        super.destroy();  
        try {  
            Thread.sleep(1000);  
        } catch (InterruptedException e) {  
            throw new RuntimeException(e);  
        }  
    }  
}

Spring timing task is no longer started after running

The timed task of spring has the following two characteristics

1. Single-timing tasks are serial. If the previous tasks are not finished, the next task will not start.

2. Multiple tasks will interfere with each other. If other tasks started at the same time are not finished, the next task will not start.

Investigation method

1. First, check your own code, whether there are deadlocks, jams, bug, http requests without setting timeout time, etc.

2. Check whether all timed tasks are not started. If the basic judgment is caused by feature 2, check which timed task is slow, stuck, bug, etc.

Solutions

1. Fix bug, if any.

2. If there is a task that is slow to execute and cannot be optimized, you can use Quartz instead of the timed task of spring.

Dependency package


<dependency>
        <groupId>org.quartz-scheduler</groupId>
        <artifactId>quartz</artifactId>
        <version>2.2.1</version>
</dependency>

Configuration:


<!--  Working bean -->
    <bean id="myJob" class=" com.gionee.baserom.exchangerate.job.DailyTaskJob" />
 
    <!--  To define a task, in order to avoid thread blocking, use the concurrent=false -->
    <bean id="myJobDetail"
        class="org.springframework.scheduling.quartz.MethodInvokingJobDetailFactoryBean">
        <property name="targetObject" ref="myJob" />
        <property name="targetMethod" value="execute" />
        <property name="concurrent" value="false" />
    </bean>
 
    <!--  Configure triggers   -->
    <bean id="myJobTrigger"
        class="org.springframework.scheduling.quartz.CronTriggerFactoryBean">
        <property name="jobDetail" ref="myJobDetail" />
        <property name="cronExpression" value="0 0/30 * * * ?" />
    </bean>
 
    <!--  Configure scheduler  -->
    <bean name="startQuertz" lazy-init="false" autowire="no" destroy-method="destroy" 
        class="com.gionee.baserom.exchangerate.util.SchedulerFactoryBeanWithShutdownDelay" >
        <property name="quartzProperties">
            <props>
                <prop key="org.quartz.threadPool.threadCount">1</prop>
            </props>
        </property>
        <property name="waitForJobsToCompleteOnShutdown">
            <value>false</value>
        </property>
        <property name="triggers">
            <list>
                <ref bean="myJobTrigger" />
            </list>
        </property>
    </bean>

Related articles: