多个示例上的Spring任务和计划任务

llycmphe  于 2022-10-30  发布在  Spring
关注(0)|答案(7)|浏览(285)

我们有一个Sping Boot 应用程序,并且有计划的任务。
我们希望在多个服务器上部署我们的应用程序,因此将有多个应用程序示例。
如何将Spring配置为仅在指定的服务器上运行计划任务?

rbpvctlc

rbpvctlc1#

这是一个非常广泛的主题。有很多选择来实现这一点。
1.您可以将应用程序配置为具有多个配置文件。例如,使用另一个配置文件“cron”。并且仅在一台具有此配置文件的服务器上启动应用程序。因此,例如,在生产环境中,您有三台服务器(S1、S2、S3),那么您可以在S1上运行prod和cron(-Dspring.profiles.active=prod,cron)配置文件。而在S2和S3上仅使用prod配置文件(-Dspring.profiles.active=prod)。
在代码中,您可以在调度程序类上使用@Profile("cron")
1.使用分布式锁。如果你的环境中有Zookeeper,你可以使用它来实现分布式锁系统。
1.您可以使用一些数据库(mysql)并创建一个示例代码来获取其中一个表的锁并添加一个条目。无论哪个示例获取了锁,都会在此数据库中创建一个条目并执行cron作业。您需要在代码中放置一个检查,如果getLock()成功,则继续执行。Mysql有一些实用程序,如LOCK TABLES、您可以使用它来避免并发读/写。
我个人认为,第二种选择是最好的。

qv7cva1a

qv7cva1a2#

Spring - ShedLock项目专门用于实现此目的。

依赖关系-

<groupId>net.javacrumbs.shedlock</groupId>
<artifactId>shedlock-spring</artifactId>

组态-

@EnableScheduling
@EnableSchedulerLock(defaultLockAtMostFor = "PT30S")

实施-

@Scheduled(cron = "0 0/15 * * * ?")
@SchedulerLock(name = "AnyUniqueName", 
  lockAtLeastForString = "PT5M", lockAtMostForString = "PT10M")
public void scheduledTask() {
    // ...
}

此设置将确保只有一个示例应运行计划任务。
如果只希望特定示例运行“排定程序”任务,
您需要配置您的调度程序以使用属性文件并控制调度程序开关,如下所示-

@ConditionalOnProperty(
  value = "scheduling.enabled", havingValue = "true", matchIfMissing = true
)
@Configuration
@EnableScheduling
@EnableSchedulerLock(defaultLockAtMostFor = "PT30S")
public class SchedulingConfig {

现在,您需要在application.properties文件中为希望从中运行Schedular的示例提供一个属性scheduling.enabled = true
按照此link进行完整实施。

9q78igpj

9q78igpj3#

最佳选择之一-使用Quartz调度程序和集群。它很简单,只是:

implementation("org.springframework.boot:spring-boot-starter-quartz")

并为带Spring的石英配置作业(请参阅tutorial
应用程序.yaml中的集群配置:

spring:
  datasource: ... # define jdbc datasource
  quartz:
    job-store-type: jdbc # Database Mode
    jdbc:
      initialize-schema: never # For clustering do not initialize table structure
    properties:
      org.quartz:
          scheduler:
            instanceId: AUTO #Default hostname and timestamp generate instance ID, which can be any string, but must be the only corresponding qrtz_scheduler_state INSTANCE_NAME field for all dispatchers
            #instanceName: clusteredScheduler #quartzScheduler
          jobStore:
            class: org.quartz.impl.jdbcjobstore.JobStoreTX #Persistence Configuration
            driverDelegateClass: org.quartz.impl.jdbcjobstore.StdJDBCDelegate #We only make database-specific proxies for databases
            useProperties: true #Indicates that JDBC JobStore stores all values in JobDataMaps as strings, so more complex objects can be stored as name-value pairs rather than serialized in BLOB columns.In the long run, this is safer because you avoid serializing non-String classes to BLOB class versions.
            tablePrefix: QRTZ_  #Database Table Prefix
            misfireThreshold: 60000 #The number of milliseconds the dispatcher will "tolerate" a Trigger to pass its next startup time before being considered a "fire".The default value (if you do not enter this property in the configuration) is 60000 (60 seconds).
            clusterCheckinInterval: 5000 #Set the frequency (in milliseconds) of this instance'checkin'* with other instances of the cluster.Affects the speed of detecting failed instances.
            isClustered: true #Turn on Clustering
          threadPool: #Connection Pool
            class: org.quartz.simpl.SimpleThreadPool
            threadCount: 10
            threadPriority: 5
            threadsInheritContextClassLoaderOfInitializingThread: true

注意initialize-schema: never-集群模式需要自己初始化
见隶书:https://github.com/quartz-scheduler/quartz/tree/master/quartz-core/src/main/resources/org/quartz/impl/jdbcjobstore
您可以通过liquibase/flyway/etc使用它,但是要删除DROP ...查询!这就是为什么在集群中我们不自动初始化模式的原因。
请参阅quartz docs
见石英Spring Boot子文件
请参阅article with example

sxpgvts3

sxpgvts34#

在Spring中实现这一点最简单的方法是使用环境变量和Value注解:
1 -获取类中带有Value注解的环境变量:

@Value("${TASK_ENABLED}")
private boolean taskEnabled;

2 -检查taskEnabled值以执行任务:

@Scheduled(fixedDelay = 50000)
public void myTask() {
  if (this.taskEnabled) {
    //do stuff here...
  }
}

3 -为每个服务器设置正确的环境变量:
错误:

java -DTASK_ENABLED=0 -jar software.jar


正确答案:

java -DTASK_ENABLED=1 -jar software.jar

使用全局配置类的示例

要使用一个全局配置类,你应该说spring it 's a component with a @Component,并注解一个set方法,将值传递给static字段。
1 -创建具有静态字段的配置类:

@Component
public class AppConfiguration {

  public static boolean taskEnabled;

  @Value("${TASK_ENABLED}")
  public void setTaskEnabled(boolean taskEnabled) {
    this.taskEnabled = taskEnabled;
  }
}

2 -检查taskEnabled值以执行任务:

@Scheduled(fixedDelay = 50000)
public void myTask() {
  if (AppConfiguration.taskEnabled) {
    //do stuff here...
  }
}

3 -为每个服务器设置正确的环境变量:
错误:

java -DTASK_ENABLED=0 -jar software.jar


正确答案:

java -DTASK_ENABLED=1 -jar software.jar
erhoui1w

erhoui1w5#

我想你需要的帮助是在另一个职位的答案之一。
查看此帖子:https://stackoverflow.com/a/65551473/4147392

1u4esq0p

1u4esq0p6#

最简单的解决方案是可以为不同的示例使用不同的属性文件。
1.使用@ConditionalOnProperty(prefix = "enable-scheduler", havingValue = "true")注解调度程序类
1.在属性文件enable-scheduler=true中添加布尔值
1.现在,在属性文件中,对任何示例使用enable-scheduler=true,对任何其他示例使用enable-scheduler=false
示例:

@Component
@ConditionalOnProperty(prefix = "enable-scheduler", havingValue = "true")
public class AnyScheduler {

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

    private final AnyService service;

    @Autowired
    public AnyScheduler(AnyService service) {
        this.service = service;
    }

    @Scheduled(cron = "${scheduler-cron}")
    public void syncModifiedCve() {
        log.info("Scheduler started. . .");
        service.doTask();
    }

}
x8goxv8g

x8goxv8g7#

我们有相同的用例,但不允许使用数据库。简单的黑客,只需在一个共享位置创建一个文件,能够创建文件的示例将运行预定的进程。

File file =new File(path);
if(file.createNewFile()){
    //run task
}

您也可以在创建文件之前添加随机睡眠时间。

SecureRandom secureRandom =new SecureRandom();
Thread.sleep(secureRandom.nextInt(100));

相关问题