Spring Boot Scheduler fixedRate与预期时间间隔存在偏差。

huangapple go评论61阅读模式
英文:

Spring Boot Scheduler fixedRate has deviation with expected time period

问题

I am working on a sample spring boot app which calls a downstream API from scheduler method execution. I have used the fixedRate variable under @Scheduled with 3000ms value. While I run the application, the follow up executions are sometimes lesser than 3 seconds (like 2.99 or 2.84 sec). Can I know what needs to be changed in the code in order to have the method executed properly. Please find below the code:

SchedulerDemoApplication

package edu.demo.scheduler;

import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.scheduling.annotation.EnableAsync;
import org.springframework.scheduling.annotation.EnableScheduling;

@SpringBootApplication
@EnableScheduling
@EnableAsync
public class SchedulerDemoApplication {

	public static void main(String[] args) {
		SpringApplication.run(SchedulerDemoApplication.class, args);
	}
}

pom.xml

<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
	xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd">
	<modelVersion>4.0.0</modelVersion>
	<parent>
		<groupId>org.springframework.boot</groupId>
		<artifactId>spring-boot-starter-parent</artifactId>
		<version>2.6.6</version>
		<relativePath/> <!-- lookup parent from repository -->
	</parent>
	<groupId>edu.demo.scheduler</groupId>
	<artifactId>SchedulerDemo</artifactId>
	<version>0.0.1-SNAPSHOT</version>
	<name>SchedulerDemo</name>
	<description>Demo project for Spring Boot</description>
	<properties>
		<java.version>1.8</java.version>
	</properties>
	<dependencies>
		<dependency>
			<groupId>org.springframework.boot</groupId>
			<artifactId>spring-boot-starter-web</artifactId>
		</dependency>

		<dependency>
			<groupId>org.springframework.boot</groupId>
			<artifactId>spring-boot-devtools</artifactId>
			<scope>runtime</scope>
			<optional>true</optional>
		</dependency>
		<dependency>
			<groupId>org.projectlombok</groupId>
			<artifactId>lombok</artifactId>
			<optional>true</optional>
		</dependency>
		<dependency>
			<groupId>org.springframework.boot</groupId>
			<artifactId>spring-boot-starter-test</artifactId>
			<scope>test</scope>
		</dependency>
	</dependencies>

	<build>
		<plugins>
			<plugin>
				<groupId>org.springframework.boot</groupId>
				<artifactId>spring-boot-maven-plugin</artifactId>
				<configuration>
					<excludes>
						<exclude>
							<groupId>org.projectlombok</groupId>
							<artifactId>lombok</artifactId>
						</exclude>
					</excludes>
				</configuration>
			</plugin>
		</plugins>
	</build>
</project>

Configuration class:

package edu.demo.scheduler.config;

import org.springframework.beans.factory.annotation.Value;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.scheduling.TaskScheduler;
import org.springframework.scheduling.concurrent.ThreadPoolTaskScheduler;

@Configuration
public class SchedulerConfiguration {

	@Value("${spring.task.scheduling.pool.size}")
	int poolSize;

	@Bean("scheduler")
	public TaskScheduler taskScheduler() {

		ThreadPoolTaskScheduler scheduler = new ThreadPoolTaskScheduler();
		scheduler.setPoolSize(poolSize);
		scheduler.setThreadNamePrefix("PoolScheduler");
		return scheduler;
	}
}

SchedulerService.

package edu.demo.scheduler.component;

import java.time.LocalDateTime;

import org.springframework.scheduling.annotation.Async;
import org.springframework.scheduling.annotation.Scheduled;
import org.springframework.stereotype.Component;

import lombok.NoArgsConstructor;
import lombok.extern.slf4j.Slf4j;

@Component
@Slf4j
@NoArgsConstructor
public class SchedulerService {

	@Scheduled(fixedRate = 3000)
	@Async("scheduler")
	public void taskScheduler() {

		System.out.println(Thread.currentThread().getName() + " - " + " Starting: " + LocalDateTime.now());
		try { Thread.sleep(5000); }catch (Exception e) {}	//	Dummy downstream call

		System.out.println(Thread.currentThread().getName() + " - " + " Running: " + LocalDateTime.now());
	}

}

application.properties

logging.level.web=DEBUG
spring.task.scheduling.pool.size=5

Console Output:

PoolScheduler1 -  Starting: 2023-04-06T17:16:26.900489100
PoolScheduler3 -  Starting: 2023-04-06T17:16:29.901791600
PoolScheduler1 -  Running: 2023-04-06T17:16:31.905599700
PoolScheduler2 -  Starting: 2023-04-06T17:16:32.899475300
PoolScheduler3 -  Running: 2023-04-06T17:16:34.911002700
PoolScheduler4 -  Starting: 2023-04-06T17:16:35.891940200
PoolScheduler2 -  Running: 2023-04-06T17:16:37.911668800
PoolScheduler4 -  Running: 2023-04-06T17:16:40.900844100

I have tried the same code in another machine and the deviation was only of 30ms, and the scheduler method was executing at 2.997 or 2.996 sec on average. So I am guessing that the deviation is dependent on hardware.

英文:

I am working on a sample spring boot app which calls a downstream API from scheduler method execution. I have used the fixedRate variable under @Scheduled with 3000ms value. While I run the application, the follow up executions are sometimes lesser than 3 seconds (like 2.99 or 2.84 sec). Can I know what needs to be changed in the code in order to have the method executed properly. Please find below the code:

SchedulerDemoApplication

package edu.demo.scheduler;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.scheduling.annotation.EnableAsync;
import org.springframework.scheduling.annotation.EnableScheduling;
@SpringBootApplication
@EnableScheduling
@EnableAsync
public class SchedulerDemoApplication {
public static void main(String[] args) {
SpringApplication.run(SchedulerDemoApplication.class, args);
}
}

pom.xml

&lt;?xml version=&quot;1.0&quot; encoding=&quot;UTF-8&quot;?&gt;
&lt;project xmlns=&quot;http://maven.apache.org/POM/4.0.0&quot; xmlns:xsi=&quot;http://www.w3.org/2001/XMLSchema-instance&quot;
xsi:schemaLocation=&quot;http://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd&quot;&gt;
&lt;modelVersion&gt;4.0.0&lt;/modelVersion&gt;
&lt;parent&gt;
&lt;groupId&gt;org.springframework.boot&lt;/groupId&gt;
&lt;artifactId&gt;spring-boot-starter-parent&lt;/artifactId&gt;
&lt;version&gt;2.6.6&lt;/version&gt;
&lt;relativePath/&gt; &lt;!-- lookup parent from repository --&gt;
&lt;/parent&gt;
&lt;groupId&gt;edu.demo.scheduler&lt;/groupId&gt;
&lt;artifactId&gt;SchedulerDemo&lt;/artifactId&gt;
&lt;version&gt;0.0.1-SNAPSHOT&lt;/version&gt;
&lt;name&gt;SchedulerDemo&lt;/name&gt;
&lt;description&gt;Demo project for Spring Boot&lt;/description&gt;
&lt;properties&gt;
&lt;java.version&gt;1.8&lt;/java.version&gt;
&lt;/properties&gt;
&lt;dependencies&gt;
&lt;dependency&gt;
&lt;groupId&gt;org.springframework.boot&lt;/groupId&gt;
&lt;artifactId&gt;spring-boot-starter-web&lt;/artifactId&gt;
&lt;/dependency&gt;
&lt;dependency&gt;
&lt;groupId&gt;org.springframework.boot&lt;/groupId&gt;
&lt;artifactId&gt;spring-boot-devtools&lt;/artifactId&gt;
&lt;scope&gt;runtime&lt;/scope&gt;
&lt;optional&gt;true&lt;/optional&gt;
&lt;/dependency&gt;
&lt;dependency&gt;
&lt;groupId&gt;org.projectlombok&lt;/groupId&gt;
&lt;artifactId&gt;lombok&lt;/artifactId&gt;
&lt;optional&gt;true&lt;/optional&gt;
&lt;/dependency&gt;
&lt;dependency&gt;
&lt;groupId&gt;org.springframework.boot&lt;/groupId&gt;
&lt;artifactId&gt;spring-boot-starter-test&lt;/artifactId&gt;
&lt;scope&gt;test&lt;/scope&gt;
&lt;/dependency&gt;
&lt;/dependencies&gt;
&lt;build&gt;
&lt;plugins&gt;
&lt;plugin&gt;
&lt;groupId&gt;org.springframework.boot&lt;/groupId&gt;
&lt;artifactId&gt;spring-boot-maven-plugin&lt;/artifactId&gt;
&lt;configuration&gt;
&lt;excludes&gt;
&lt;exclude&gt;
&lt;groupId&gt;org.projectlombok&lt;/groupId&gt;
&lt;artifactId&gt;lombok&lt;/artifactId&gt;
&lt;/exclude&gt;
&lt;/excludes&gt;
&lt;/configuration&gt;
&lt;/plugin&gt;
&lt;/plugins&gt;
&lt;/build&gt;
&lt;/project&gt;

Configuration class:

package edu.demo.scheduler.config;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.scheduling.TaskScheduler;
import org.springframework.scheduling.concurrent.ThreadPoolTaskScheduler;
@Configuration
public class SchedulerConfiguration {
@Value(&quot;${spring.task.scheduling.pool.size}&quot;)
int poolSize;
@Bean(&quot;scheduler&quot;)
public TaskScheduler taskScheduler() {
ThreadPoolTaskScheduler scheduler = new ThreadPoolTaskScheduler();
scheduler.setPoolSize(poolSize);
scheduler.setThreadNamePrefix(&quot;PoolScheduler&quot;);
return scheduler;
}
}

SchedulerService.

package edu.demo.scheduler.component;
import java.time.LocalDateTime;
import org.springframework.scheduling.annotation.Async;
import org.springframework.scheduling.annotation.Scheduled;
import org.springframework.stereotype.Component;
import lombok.NoArgsConstructor;
import lombok.extern.slf4j.Slf4j;
@Component
@Slf4j
@NoArgsConstructor
public class SchedulerService {
@Scheduled(fixedRate = 3000)
@Async(&quot;scheduler&quot;)
public void taskScheduler() {
System.out.println(Thread.currentThread().getName() + &quot; - &quot; + &quot; Starting: &quot; + LocalDateTime.now());
try { Thread.sleep(5000); }catch (Exception e) {}	//	Dummy downstream call
System.out.println(Thread.currentThread().getName() + &quot; - &quot; + &quot; Running: &quot; + LocalDateTime.now());
}
}

application.properties

logging.level.web=DEBUG
spring.task.scheduling.pool.size=5

Console Output:

PoolScheduler1 -  Starting: 2023-04-06T17:16:26.900489100
PoolScheduler3 -  Starting: 2023-04-06T17:16:29.901791600
PoolScheduler1 -  Running: 2023-04-06T17:16:31.905599700
PoolScheduler2 -  Starting: 2023-04-06T17:16:32.899475300
PoolScheduler3 -  Running: 2023-04-06T17:16:34.911002700
PoolScheduler4 -  Starting: 2023-04-06T17:16:35.891940200
PoolScheduler2 -  Running: 2023-04-06T17:16:37.911668800
PoolScheduler4 -  Running: 2023-04-06T17:16:40.900844100

I have tried the same code in another machine and the deviation was only of 30ms and the scheduler method was executing at 2.997 or 2.996 sec on average. So I am guessing that the deviation is dependent on hardware.

答案1

得分: 2

我建议使用ScheduledThreadPoolExecutor,它可以同时运行定时和多线程任务。

英文:

As you obviously want to run your tasks both scheduled and multi threaded I suggest to use ScheduledThreadPoolExecutor which combine both concepts.

huangapple
  • 本文由 发表于 2023年4月6日 20:38:29
  • 转载请务必保留本文链接:https://go.coder-hub.com/75949617.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定