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

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

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

  1. package edu.demo.scheduler;
  2. import org.springframework.boot.SpringApplication;
  3. import org.springframework.boot.autoconfigure.SpringBootApplication;
  4. import org.springframework.scheduling.annotation.EnableAsync;
  5. import org.springframework.scheduling.annotation.EnableScheduling;
  6. @SpringBootApplication
  7. @EnableScheduling
  8. @EnableAsync
  9. public class SchedulerDemoApplication {
  10. public static void main(String[] args) {
  11. SpringApplication.run(SchedulerDemoApplication.class, args);
  12. }
  13. }

pom.xml

  1. <?xml version="1.0" encoding="UTF-8"?>
  2. <project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
  3. xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd">
  4. <modelVersion>4.0.0</modelVersion>
  5. <parent>
  6. <groupId>org.springframework.boot</groupId>
  7. <artifactId>spring-boot-starter-parent</artifactId>
  8. <version>2.6.6</version>
  9. <relativePath/> <!-- lookup parent from repository -->
  10. </parent>
  11. <groupId>edu.demo.scheduler</groupId>
  12. <artifactId>SchedulerDemo</artifactId>
  13. <version>0.0.1-SNAPSHOT</version>
  14. <name>SchedulerDemo</name>
  15. <description>Demo project for Spring Boot</description>
  16. <properties>
  17. <java.version>1.8</java.version>
  18. </properties>
  19. <dependencies>
  20. <dependency>
  21. <groupId>org.springframework.boot</groupId>
  22. <artifactId>spring-boot-starter-web</artifactId>
  23. </dependency>
  24. <dependency>
  25. <groupId>org.springframework.boot</groupId>
  26. <artifactId>spring-boot-devtools</artifactId>
  27. <scope>runtime</scope>
  28. <optional>true</optional>
  29. </dependency>
  30. <dependency>
  31. <groupId>org.projectlombok</groupId>
  32. <artifactId>lombok</artifactId>
  33. <optional>true</optional>
  34. </dependency>
  35. <dependency>
  36. <groupId>org.springframework.boot</groupId>
  37. <artifactId>spring-boot-starter-test</artifactId>
  38. <scope>test</scope>
  39. </dependency>
  40. </dependencies>
  41. <build>
  42. <plugins>
  43. <plugin>
  44. <groupId>org.springframework.boot</groupId>
  45. <artifactId>spring-boot-maven-plugin</artifactId>
  46. <configuration>
  47. <excludes>
  48. <exclude>
  49. <groupId>org.projectlombok</groupId>
  50. <artifactId>lombok</artifactId>
  51. </exclude>
  52. </excludes>
  53. </configuration>
  54. </plugin>
  55. </plugins>
  56. </build>
  57. </project>

Configuration class:

  1. package edu.demo.scheduler.config;
  2. import org.springframework.beans.factory.annotation.Value;
  3. import org.springframework.context.annotation.Bean;
  4. import org.springframework.context.annotation.Configuration;
  5. import org.springframework.scheduling.TaskScheduler;
  6. import org.springframework.scheduling.concurrent.ThreadPoolTaskScheduler;
  7. @Configuration
  8. public class SchedulerConfiguration {
  9. @Value("${spring.task.scheduling.pool.size}")
  10. int poolSize;
  11. @Bean("scheduler")
  12. public TaskScheduler taskScheduler() {
  13. ThreadPoolTaskScheduler scheduler = new ThreadPoolTaskScheduler();
  14. scheduler.setPoolSize(poolSize);
  15. scheduler.setThreadNamePrefix("PoolScheduler");
  16. return scheduler;
  17. }
  18. }

SchedulerService.

  1. package edu.demo.scheduler.component;
  2. import java.time.LocalDateTime;
  3. import org.springframework.scheduling.annotation.Async;
  4. import org.springframework.scheduling.annotation.Scheduled;
  5. import org.springframework.stereotype.Component;
  6. import lombok.NoArgsConstructor;
  7. import lombok.extern.slf4j.Slf4j;
  8. @Component
  9. @Slf4j
  10. @NoArgsConstructor
  11. public class SchedulerService {
  12. @Scheduled(fixedRate = 3000)
  13. @Async("scheduler")
  14. public void taskScheduler() {
  15. System.out.println(Thread.currentThread().getName() + " - " + " Starting: " + LocalDateTime.now());
  16. try { Thread.sleep(5000); }catch (Exception e) {} // Dummy downstream call
  17. System.out.println(Thread.currentThread().getName() + " - " + " Running: " + LocalDateTime.now());
  18. }
  19. }

application.properties

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

Console Output:

  1. PoolScheduler1 - Starting: 2023-04-06T17:16:26.900489100
  2. PoolScheduler3 - Starting: 2023-04-06T17:16:29.901791600
  3. PoolScheduler1 - Running: 2023-04-06T17:16:31.905599700
  4. PoolScheduler2 - Starting: 2023-04-06T17:16:32.899475300
  5. PoolScheduler3 - Running: 2023-04-06T17:16:34.911002700
  6. PoolScheduler4 - Starting: 2023-04-06T17:16:35.891940200
  7. PoolScheduler2 - Running: 2023-04-06T17:16:37.911668800
  8. 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

  1. package edu.demo.scheduler;
  2. import org.springframework.boot.SpringApplication;
  3. import org.springframework.boot.autoconfigure.SpringBootApplication;
  4. import org.springframework.scheduling.annotation.EnableAsync;
  5. import org.springframework.scheduling.annotation.EnableScheduling;
  6. @SpringBootApplication
  7. @EnableScheduling
  8. @EnableAsync
  9. public class SchedulerDemoApplication {
  10. public static void main(String[] args) {
  11. SpringApplication.run(SchedulerDemoApplication.class, args);
  12. }
  13. }

pom.xml

  1. &lt;?xml version=&quot;1.0&quot; encoding=&quot;UTF-8&quot;?&gt;
  2. &lt;project xmlns=&quot;http://maven.apache.org/POM/4.0.0&quot; xmlns:xsi=&quot;http://www.w3.org/2001/XMLSchema-instance&quot;
  3. xsi:schemaLocation=&quot;http://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd&quot;&gt;
  4. &lt;modelVersion&gt;4.0.0&lt;/modelVersion&gt;
  5. &lt;parent&gt;
  6. &lt;groupId&gt;org.springframework.boot&lt;/groupId&gt;
  7. &lt;artifactId&gt;spring-boot-starter-parent&lt;/artifactId&gt;
  8. &lt;version&gt;2.6.6&lt;/version&gt;
  9. &lt;relativePath/&gt; &lt;!-- lookup parent from repository --&gt;
  10. &lt;/parent&gt;
  11. &lt;groupId&gt;edu.demo.scheduler&lt;/groupId&gt;
  12. &lt;artifactId&gt;SchedulerDemo&lt;/artifactId&gt;
  13. &lt;version&gt;0.0.1-SNAPSHOT&lt;/version&gt;
  14. &lt;name&gt;SchedulerDemo&lt;/name&gt;
  15. &lt;description&gt;Demo project for Spring Boot&lt;/description&gt;
  16. &lt;properties&gt;
  17. &lt;java.version&gt;1.8&lt;/java.version&gt;
  18. &lt;/properties&gt;
  19. &lt;dependencies&gt;
  20. &lt;dependency&gt;
  21. &lt;groupId&gt;org.springframework.boot&lt;/groupId&gt;
  22. &lt;artifactId&gt;spring-boot-starter-web&lt;/artifactId&gt;
  23. &lt;/dependency&gt;
  24. &lt;dependency&gt;
  25. &lt;groupId&gt;org.springframework.boot&lt;/groupId&gt;
  26. &lt;artifactId&gt;spring-boot-devtools&lt;/artifactId&gt;
  27. &lt;scope&gt;runtime&lt;/scope&gt;
  28. &lt;optional&gt;true&lt;/optional&gt;
  29. &lt;/dependency&gt;
  30. &lt;dependency&gt;
  31. &lt;groupId&gt;org.projectlombok&lt;/groupId&gt;
  32. &lt;artifactId&gt;lombok&lt;/artifactId&gt;
  33. &lt;optional&gt;true&lt;/optional&gt;
  34. &lt;/dependency&gt;
  35. &lt;dependency&gt;
  36. &lt;groupId&gt;org.springframework.boot&lt;/groupId&gt;
  37. &lt;artifactId&gt;spring-boot-starter-test&lt;/artifactId&gt;
  38. &lt;scope&gt;test&lt;/scope&gt;
  39. &lt;/dependency&gt;
  40. &lt;/dependencies&gt;
  41. &lt;build&gt;
  42. &lt;plugins&gt;
  43. &lt;plugin&gt;
  44. &lt;groupId&gt;org.springframework.boot&lt;/groupId&gt;
  45. &lt;artifactId&gt;spring-boot-maven-plugin&lt;/artifactId&gt;
  46. &lt;configuration&gt;
  47. &lt;excludes&gt;
  48. &lt;exclude&gt;
  49. &lt;groupId&gt;org.projectlombok&lt;/groupId&gt;
  50. &lt;artifactId&gt;lombok&lt;/artifactId&gt;
  51. &lt;/exclude&gt;
  52. &lt;/excludes&gt;
  53. &lt;/configuration&gt;
  54. &lt;/plugin&gt;
  55. &lt;/plugins&gt;
  56. &lt;/build&gt;
  57. &lt;/project&gt;

Configuration class:

  1. package edu.demo.scheduler.config;
  2. import org.springframework.beans.factory.annotation.Value;
  3. import org.springframework.context.annotation.Bean;
  4. import org.springframework.context.annotation.Configuration;
  5. import org.springframework.scheduling.TaskScheduler;
  6. import org.springframework.scheduling.concurrent.ThreadPoolTaskScheduler;
  7. @Configuration
  8. public class SchedulerConfiguration {
  9. @Value(&quot;${spring.task.scheduling.pool.size}&quot;)
  10. int poolSize;
  11. @Bean(&quot;scheduler&quot;)
  12. public TaskScheduler taskScheduler() {
  13. ThreadPoolTaskScheduler scheduler = new ThreadPoolTaskScheduler();
  14. scheduler.setPoolSize(poolSize);
  15. scheduler.setThreadNamePrefix(&quot;PoolScheduler&quot;);
  16. return scheduler;
  17. }
  18. }

SchedulerService.

  1. package edu.demo.scheduler.component;
  2. import java.time.LocalDateTime;
  3. import org.springframework.scheduling.annotation.Async;
  4. import org.springframework.scheduling.annotation.Scheduled;
  5. import org.springframework.stereotype.Component;
  6. import lombok.NoArgsConstructor;
  7. import lombok.extern.slf4j.Slf4j;
  8. @Component
  9. @Slf4j
  10. @NoArgsConstructor
  11. public class SchedulerService {
  12. @Scheduled(fixedRate = 3000)
  13. @Async(&quot;scheduler&quot;)
  14. public void taskScheduler() {
  15. System.out.println(Thread.currentThread().getName() + &quot; - &quot; + &quot; Starting: &quot; + LocalDateTime.now());
  16. try { Thread.sleep(5000); }catch (Exception e) {} // Dummy downstream call
  17. System.out.println(Thread.currentThread().getName() + &quot; - &quot; + &quot; Running: &quot; + LocalDateTime.now());
  18. }
  19. }

application.properties

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

Console Output:

  1. PoolScheduler1 - Starting: 2023-04-06T17:16:26.900489100
  2. PoolScheduler3 - Starting: 2023-04-06T17:16:29.901791600
  3. PoolScheduler1 - Running: 2023-04-06T17:16:31.905599700
  4. PoolScheduler2 - Starting: 2023-04-06T17:16:32.899475300
  5. PoolScheduler3 - Running: 2023-04-06T17:16:34.911002700
  6. PoolScheduler4 - Starting: 2023-04-06T17:16:35.891940200
  7. PoolScheduler2 - Running: 2023-04-06T17:16:37.911668800
  8. 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:

确定