Spring scheduler + ShedLock

spring.main.allow-bean-definition-overriding: true
server:
port: 8080
spring.devtools:
add-properties: false
livereload:
enabled: false

#spring cron expression see https://riptutorial.com/spring/example/21209/cron-expression, use UTC time zone
cron:
credit: "0 0 4 * * 2-6"
commodity: "* * * * * 2-6"
gsm: "0 0 7 * * 2-6"

scheduledThreadPool:
threadNamePrefix: "lci-task-pool-"
threadCount: 10

# Could set lock time to '5S', '3M' or '0'(means no lock)
# Use 'lockAtLeastFor' to avoid concurrent running on cluster(cluster should use same clock)
# Use 'lockAtMostFor' to avoid indefinite lock time in case the machine which obtained the lock died before releasing it.
scheduler.lock:
credit:
lockAtMostFor: "3M"
lockAtLeastFor: "1M"
commodity:
lockAtMostFor: "3M"
lockAtLeastFor: "30s"
gsm:
lockAtMostFor: "3M"
lockAtLeastFor: "1M"
dependencies {
    implementation platform(project(':lci-core:lci-core-hive'))
    implementation platform(project(':lci-flow:lci-flow-credit'))
    implementation platform(project(':lci-flow:lci-flow-gsm'))
    implementation platform(project(':lci-modules:lci-modules-oauth2'))
    implementation "org.springframework.boot:spring-boot-starter-webflux"
    implementation 'org.springframework.boot:spring-boot-starter-actuator'
    implementation 'org.springframework.boot:spring-boot-starter-data-mongodb-reactive'
    implementation "net.javacrumbs.shedlock:shedlock-spring:${shedlockVersion}"
    implementation "net.javacrumbs.shedlock:shedlock-provider-mongo:${shedlockVersion}"

    // Test dependencies
    testImplementation 'org.springframework.boot:spring-boot-starter-test'
    testImplementation 'com.squareup.okhttp3:mockwebserver'
    testImplementation 'org.springframework.security:spring-security-test'
    testImplementation 'org.awaitility:awaitility'
}

jar {
    enabled = false
}

bootJar {
    enabled = true
    archiveFileName = "lci-app.jar"
    launchScript {
        properties "mode": "run"
    }
}

project.afterEvaluate {
    springBoot {
        buildInfo {
            properties {
                version = citi.buildVersion.get()
            }
        }
    }
}
springBootVersion=2.3.2.RELEASE
shedlockVersion=4.15.1
package com.citi.xip.lci.app;

import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.boot.autoconfigure.data.mongo.MongoDataAutoConfiguration;
import org.springframework.boot.autoconfigure.data.mongo.MongoReactiveDataAutoConfiguration;
import org.springframework.boot.autoconfigure.data.mongo.MongoReactiveRepositoriesAutoConfiguration;
import org.springframework.boot.autoconfigure.data.mongo.MongoRepositoriesAutoConfiguration;
import org.springframework.boot.autoconfigure.mongo.MongoAutoConfiguration;
import org.springframework.boot.autoconfigure.mongo.MongoReactiveAutoConfiguration;

/** Bootstrap entrypoint. */
@SpringBootApplication(
    exclude = {
      MongoAutoConfiguration.class,
      MongoDataAutoConfiguration.class,
      MongoRepositoriesAutoConfiguration.class,
      MongoReactiveAutoConfiguration.class,
      MongoReactiveDataAutoConfiguration.class,
      MongoReactiveRepositoriesAutoConfiguration.class
    })
public class Application {

  public static void main(String[] args) {
    SpringApplication.run(Application.class, args);
  }
}
package com.citi.xip.lci.app.schedulers;

import org.springframework.beans.factory.annotation.Value;
import org.springframework.context.annotation.Configuration;
import org.springframework.scheduling.annotation.EnableScheduling;
import org.springframework.scheduling.annotation.SchedulingConfigurer;
import org.springframework.scheduling.concurrent.ThreadPoolTaskScheduler;
import org.springframework.scheduling.config.ScheduledTaskRegistrar;

@Configuration
@EnableScheduling
public class SchedulerConfig implements SchedulingConfigurer {

  @Value("${scheduledThreadPool.threadCount}")
  private int threadPoolSize;

  @Value("${scheduledThreadPool.threadNamePrefix}")
  private String threadNamePrefix;

  @Override
  public void configureTasks(ScheduledTaskRegistrar scheduledTaskRegistrar) {
    ThreadPoolTaskScheduler threadPoolTaskScheduler = new ThreadPoolTaskScheduler();

    threadPoolTaskScheduler.setPoolSize(threadPoolSize);
    threadPoolTaskScheduler.setThreadNamePrefix(threadNamePrefix);
    threadPoolTaskScheduler.initialize();

    scheduledTaskRegistrar.setTaskScheduler(threadPoolTaskScheduler);
  }
}
package com.citi.xip.lci.app.schedulers;

public class SchedulerConstant {

  public static final String LOCK_UNTIL = "lockUntil";
  public static final String ID = "_id";
  public static final String SHEDLOCK_COLLECTION_NAME = "shedLock";
  public static final String LOCK_NAME_SUFFIX = "SchedulerLock";
  public static final String GSM_LOCK_NAME_PREFIX = "gsm";
  public static final String CREDIT_LOCK_NAME_PREFIX = "credit";
  public static final String COMMODITY_LOCK_NAME_PREFIX = "commodity";
}
package com.citi.xip.lci.app.schedulers;

import static com.citi.xip.lci.app.schedulers.SchedulerConstant.SHEDLOCK_COLLECTION_NAME;

import com.citi.xip.lci.core.base.spring.qualifiers.Quattro;
import com.mongodb.client.MongoCollection;
import net.javacrumbs.shedlock.core.LockProvider;
import net.javacrumbs.shedlock.provider.mongo.MongoLockProvider;
import net.javacrumbs.shedlock.spring.annotation.EnableSchedulerLock;
import org.bson.Document;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.data.mongodb.core.MongoTemplate;

@Configuration
@EnableSchedulerLock(defaultLockAtMostFor = "0")
public class ShedlockConfig {

  @Autowired @Quattro private MongoTemplate template;

  @Bean
  public LockProvider lockProvider() {
    MongoCollection<Document> mongo = template.getCollection(SHEDLOCK_COLLECTION_NAME);
    return new MongoLockProvider(mongo);
  }
}
package com.citi.xip.lci.app.schedulers;

import static com.citi.xip.lci.app.schedulers.SchedulerConstant.COMMODITY_LOCK_NAME_PREFIX;
import static com.citi.xip.lci.app.schedulers.SchedulerConstant.LOCK_NAME_SUFFIX;

import lombok.extern.slf4j.Slf4j;
import net.javacrumbs.shedlock.spring.annotation.SchedulerLock;
import org.springframework.scheduling.annotation.Scheduled;
import org.springframework.stereotype.Component;

@Slf4j
@Component
public class CommodityScheduler {

  @Scheduled(cron = "${cron.commodity}", zone = "UTC")
  @SchedulerLock(
      name = COMMODITY_LOCK_NAME_PREFIX + LOCK_NAME_SUFFIX,
      lockAtMostFor = "${scheduler.lock.commodity.lockAtMostFor}",
      lockAtLeastFor = "${scheduler.lock.commodity.lockAtLeastFor}")
  public void work() {
    log.info("Commodity detecting job start!");
  }
}
package com.citi.xip.lci.app.controller;

import static com.citi.xip.lci.app.schedulers.SchedulerConstant.ID;
import static com.citi.xip.lci.app.schedulers.SchedulerConstant.LOCK_NAME_SUFFIX;
import static com.citi.xip.lci.app.schedulers.SchedulerConstant.LOCK_UNTIL;
import static com.citi.xip.lci.app.schedulers.SchedulerConstant.SHEDLOCK_COLLECTION_NAME;
import static com.mongodb.client.model.Filters.eq;
import static com.mongodb.client.model.Updates.combine;
import static com.mongodb.client.model.Updates.set;

import com.citi.xip.lci.core.base.spring.qualifiers.Quattro;
import com.mongodb.client.MongoCollection;
import java.time.Instant;
import lombok.extern.slf4j.Slf4j;
import org.bson.Document;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.mongodb.core.MongoTemplate;
import org.springframework.scheduling.annotation.ScheduledAnnotationBeanPostProcessor;
import org.springframework.scheduling.config.ScheduledTask;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.RestController;

@Slf4j
@RestController
public class SchedulerController {

  @Autowired org.springframework.context.ApplicationContext applicationContext;

  @Autowired @Quattro private MongoTemplate template;

  @GetMapping(path = "/scheduler/executeNow")
  public String execute(@RequestParam(value = "business") String business) {

    ScheduledAnnotationBeanPostProcessor bean =
        applicationContext.getBean(ScheduledAnnotationBeanPostProcessor.class);
    for (ScheduledTask task : bean.getScheduledTasks()) {
      if (task.toString().toLowerCase().contains(business.toLowerCase())) {
        removeLock(business);
        task.getTask().getRunnable().run();
        return "executed";
      }
    }
    return "No this business task";
  }

  // If lockUtil > now will not execute and skip
  private void removeLock(String business) {
    MongoCollection<Document> mongo = template.getCollection(SHEDLOCK_COLLECTION_NAME);
    mongo.findOneAndUpdate(
        eq(ID, business.toLowerCase() + LOCK_NAME_SUFFIX), combine(set(LOCK_UNTIL, Instant.now())));
  }
}
原文地址:https://www.cnblogs.com/tonggc1668/p/13949831.html