编辑此页面

调度周期性任务

现代应用程序通常需要定期运行特定的任务。在本指南中,您将学习如何调度周期性任务。

如果您需要集群调度器,请使用 Quartz 扩展

先决条件

要完成本指南,您需要

  • 大约 15 分钟

  • 一个 IDE

  • 已安装 JDK 17+ 并正确配置了 JAVA_HOME

  • Apache Maven 3.9.9

  • 如果您想使用它,可以选择 Quarkus CLI

  • 如果您想构建本机可执行文件(或者如果您使用本机容器构建,则为 Docker),可以选择安装 Mandrel 或 GraalVM 并进行适当的配置

架构

在本指南中,我们将创建一个简单的应用程序,可以使用 HTTP 访问以获取计数器的当前值。此计数器会定期(每 10 秒)递增。

Architecture

解决方案

我们建议您按照以下章节中的说明,逐步创建应用程序。但是,您可以直接转到完整的示例。

克隆 Git 仓库:git clone https://github.com/quarkusio/quarkus-quickstarts.git,或者下载 存档

该解决方案位于 scheduler-quickstart 目录中。

创建 Maven 项目

首先,我们需要一个新项目。使用以下命令创建一个新项目

CLI
quarkus create app org.acme:scheduler-quickstart \
    --extension='rest,scheduler' \
    --no-code
cd scheduler-quickstart

要创建 Gradle 项目,请添加 --gradle--gradle-kotlin-dsl 选项。

有关如何安装和使用 Quarkus CLI 的更多信息,请参阅 Quarkus CLI 指南。

Maven
mvn io.quarkus.platform:quarkus-maven-plugin:3.24.4:create \
    -DprojectGroupId=org.acme \
    -DprojectArtifactId=scheduler-quickstart \
    -Dextensions='rest,scheduler' \
    -DnoCode
cd scheduler-quickstart

要创建 Gradle 项目,请添加 -DbuildTool=gradle-DbuildTool=gradle-kotlin-dsl 选项。

对于 Windows 用户

  • 如果使用 cmd,(不要使用反斜杠 \ 并将所有内容放在同一行上)

  • 如果使用 Powershell,请将 -D 参数用双引号括起来,例如 "-DprojectArtifactId=scheduler-quickstart"

它会生成一个新项目,包括

  • 一个可以在 https://:8080 上访问的欢迎页面

  • 用于 nativejvm 模式的示例 Dockerfile 文件

  • 应用程序配置文件

该项目还导入了 Quarkus REST(以前称为 RESTEasy Reactive)和调度器扩展。

如果您已经配置了 Quarkus 项目,则可以通过在项目基本目录中运行以下命令将 scheduler 扩展添加到您的项目中

CLI
quarkus extension add scheduler
Maven
./mvnw quarkus:add-extension -Dextensions='scheduler'
Gradle
./gradlew addExtension --extensions='scheduler'

这会将以下内容添加到您的构建文件中

pom.xml
<dependency>
    <groupId>io.quarkus</groupId>
    <artifactId>quarkus-scheduler</artifactId>
</dependency>
build.gradle
implementation("io.quarkus:quarkus-scheduler")

创建计划任务

org.acme.scheduler 包中,创建 CounterBean 类,其内容如下

package org.acme.scheduler;

import java.util.concurrent.atomic.AtomicInteger;
import jakarta.enterprise.context.ApplicationScoped;
import io.quarkus.scheduler.Scheduled;
import io.quarkus.scheduler.ScheduledExecution;

@ApplicationScoped              (1)
public class CounterBean {

    private AtomicInteger counter = new AtomicInteger();

    public int get() {  (2)
        return counter.get();
    }

    @Scheduled(every="10s")     (3)
    void increment() {
        counter.incrementAndGet(); (4)
    }

    @Scheduled(cron="0 15 10 * * ?") (5)
    void cronJob(ScheduledExecution execution) {
        counter.incrementAndGet();
        System.out.println(execution.getScheduledFireTime());
    }

    @Scheduled(cron = "{cron.expr}") (6)
    void cronJobWithExpressionInConfig() {
       counter.incrementAndGet();
       System.out.println("Cron expression configured in application.properties");
    }
}
1 应用程序作用域中声明 bean
2 get() 方法允许检索当前值。
3 使用 @Scheduled 注解指示 Quarkus 每 10 秒运行一次此方法,前提是有一个工作线程可用(Quarkus 为调度器使用 10 个工作线程)。如果不可用,则应默认重新调度方法调用,即应尽快调用。计划方法的调用不依赖于先前调用的状态或结果。
4 代码非常简单。每 10 秒,计数器递增。
5 使用类似 cron 的表达式定义作业。带注解的方法每天上午 10:15 执行。
6 使用类似 cron 的表达式 cron.expr 定义作业,该表达式可在 application.properties 中配置。

更新应用程序配置文件

编辑 application.properties 文件并添加 cron.expr 配置

# By default, the syntax used for cron expressions is based on Quartz - https://www.quartz-scheduler.org/documentation/quartz-2.3.0/tutorials/crontrigger.html
# You can change the syntax using the following property:
# quarkus.scheduler.cron-type=unix
cron.expr=*/5 * * * * ?

创建 REST 资源

创建 CountResource 类,如下所示

package org.acme.scheduler;

import jakarta.inject.Inject;
import jakarta.ws.rs.GET;
import jakarta.ws.rs.Path;
import jakarta.ws.rs.Produces;
import jakarta.ws.rs.core.MediaType;

@Path("/count")
public class CountResource {

    @Inject
    CounterBean counter;            (1)


    @GET
    @Produces(MediaType.TEXT_PLAIN)
    public String hello() {
        return "count: " + counter.get();  (2)
    }
}
1 注入 CounterBean
2 发回当前计数器值

打包并运行应用程序

使用以下命令运行应用程序

CLI
quarkus dev
Maven
./mvnw quarkus:dev
Gradle
./gradlew --console=plain quarkusDev

在另一个终端中,运行 curl localhost:8080/count 以检查计数器值。几秒钟后,重新运行 curl localhost:8080/count 以验证计数器是否已递增。

观察控制台以验证消息 Cron expression configured in application.properties 是否已显示,指示使用在 application.properties 中配置的表达式的 cron 作业已被触发。

与往常一样,可以使用以下命令打包应用程序

CLI
quarkus build
Maven
./mvnw install
Gradle
./gradlew build

并使用 java -jar target/quarkus-app/quarkus-run.jar 执行。

您还可以使用以下命令生成原生可执行文件

CLI
quarkus build --native
Maven
./mvnw install -Dnative
Gradle
./gradlew build -Dquarkus.native.enabled=true

调度器配置参考

构建时固定的配置属性 - 所有其他配置属性都可以在运行时覆盖

配置属性

类型

默认

在 CRON 表达式中使用的语法。

环境变量:QUARKUS_SCHEDULER_CRON_TYPE

显示更多

cron4j, quartz, unix, spring, spring53

quartz

如果存在指标扩展并且此值为 true,则将启用计划任务指标。

环境变量:QUARKUS_SCHEDULER_METRICS_ENABLED

显示更多

布尔值

false

控制是否启用跟踪。如果设置为 true 并且存在 OpenTelemetry 扩展,则将启用跟踪,从而为每个计划任务创建自动 Spans。

环境变量:QUARKUS_SCHEDULER_TRACING_ENABLED

显示更多

布尔值

false

默认情况下,只使用一个 Scheduler 实现。如果设置为 true,则使用一个复合 Scheduler,它委托给所有正在运行的实现。

调度器实现的启动将取决于 quarkus.scheduler.start-mode 的值,即,除非找到相关的 io.quarkus.scheduler.Scheduled 业务方法,否则不会启动调度器。

环境变量:QUARKUS_SCHEDULER_USE_COMPOSITE_SCHEDULER

显示更多

布尔值

false

是否启用调度器。

环境变量:QUARKUS_SCHEDULER_ENABLED

显示更多

布尔值

true

如果下一个执行时间超过此期限,计划任务将被标记为过期。

环境变量:QUARKUS_SCHEDULER_OVERDUE_GRACE_PERIOD

显示更多

Duration 

1S

调度器可以在不同的模式下启动。默认情况下,除非找到 io.quarkus.scheduler.Scheduled 业务方法,否则不会启动调度器。

环境变量:QUARKUS_SCHEDULER_START_MODE

显示更多

normal除非找到 io.quarkus.scheduler.Scheduled 业务方法,否则不会启动调度器。, forced即使没有找到计划的业务方法,也将启动调度器。这对于“纯”程序化调度是必需的。, halted就像 forced 模式一样,但在调用 Scheduler#resume() 之前,调度器不会开始触发作业。这对于运行需要在调度器启动之前执行的一些初始化逻辑很有用。

normal除非找到 {@link io.quarkus.scheduler.Scheduled} 业务方法,否则不会启动调度器。

关于 Duration 格式

要编写持续时间值,请使用标准的 java.time.Duration 格式。有关更多信息,请参见 Duration#parse() Java API 文档

您还可以使用简化的格式,以数字开头

  • 如果该值仅为一个数字,则表示以秒为单位的时间。

  • 如果该值是一个数字后跟 ms,则表示以毫秒为单位的时间。

在其他情况下,简化格式将被转换为 java.time.Duration 格式以进行解析

  • 如果该值是一个数字后跟 hms,则在其前面加上 PT

  • 如果该值是一个数字后跟 d,则在其前面加上 P

相关内容