java 如何为Sping Boot 应用程序执行命令行任务,如Rake任务?

neskvpey  于 2023-04-19  发布在  Java
关注(0)|答案(3)|浏览(124)

我如何从命令行运行一个任务,用于长时间运行的作业,如Sping Boot 中的Jenkins报告?我正在寻找类似于Ruby on Rails Rake任务的东西。Rake任务在与Web服务器相同的应用程序上下文中从命令行执行代码,以便您可以重用代码。

  • 我发现Spring Batch听起来更像Resque
  • 我找到了command line runners,但它说它们都在Web服务器启动之前运行,所以我不能不运行它或只运行一个任务。
  • 我发现scheduled tasks听起来很完美,但我的应用程序是负载平衡的,有很多示例,所以我不希望它一次运行多次!

我有一个报告,其中查询需要超过30秒的时间来运行,并生成一个CSV文件,我想邮件。我希望它每周自动运行与cron或Jenkins。

lvmkulzt

lvmkulzt1#

我破解了一个解决方案欢迎提出建议。

package com.example.tasks;

@Component
public class WeeklyReport implements CommandLineRunner {

    @Override
    public void run(String... args) throws Exception {
        Arrays.asList(args).stream().forEach(a -> System.out.println(a));
        if (!(args.length > 0 && args[0].equals("-task report:weekly"))) return;
        System.out.println("weekly report");
        System.exit(0);
    }

并从一个'cron'作业运行它

$ mvn spring-boot:run -Drun.arguments="-task report:weekly"

https://docs.spring.io/spring-boot/docs/1.5.19.RELEASE/reference/htmlsingle/#boot-features-command-line-runner
https://www.baeldung.com/spring-boot-command-line-arguments
https://therealdanvega.com/blog/2017/04/07/spring-boot-command-line-runner

jljoyd4f

jljoyd4f2#

我最近遇到了一个类似的问题,我想出了三个可能的解决方案:
1.指定一个“管家”角色,最多只能由一个示例承担,该示例的职责是完成预定的作业。但是,为此,管家必须向其他示例发送心跳(通过负载均衡器..),如果心跳停止,则剩余的示例必须选择一个新的示例,因此这似乎是一个有趣但更复杂的方法,我稍后可能会尝试。
1.拥有一个单示例外部服务,它将运行计划任务并为您生成每周CSV
1.有一个单示例的外部服务,它只具有进行计划API调用的能力,并且会通过负载均衡器调用您的原始服务。我更喜欢这种解决方案,因为完成任务的所有资源都已经存在于原始服务中,并且它保留了功能。它也很灵活,因为调度器服务可以被更轻量级的cron作业替换,或者在未来合并到另一个服务中。

j0pj023g

j0pj023g3#

实现这一目标的一种方法是将每个任务视为一个单独的应用程序。这允许您在同一个JAR中运行它们,但具有不同的配置:

  • Application.java:这是默认的Web应用程序
  • FooApplication.java这是“Foo”任务应用程序

目录结构如下所示:

src/
  main/java/com/example/
    Application.java
    FooApplication.java
  resources/
    application.yml
    foo-application.yml

对于您希望确保Web应用程序类型设置为none以便不启动嵌入式Web服务器的任务:

foo-application.yml

spring:
  main:
    web-application-type: none

要定义应用程序,请执行以下操作:

FooApplication.java

package com.example

import com.example.runner.BootstrapContentfulRunner;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;

@SpringBootApplication
@ComponentScan(excludeFilters={@ComponentScan.Filter(type=FilterType.ASSIGNABLE_TYPE, value=Application.class)})
public class FooApplication {
    public static void main(String[] args) {
        System.exit(SpringApplication.exit(
            SpringApplication.run(FooRunner.class, args)
        ));
    }

    @EventListener(ApplicationReadyEvent.class)
    public void foo() {
        // Do your task here
        System.out.println("Foo task complete!");
    }

}

然后,为了运行任务应用程序:

mvn spring-boot:run \
  -Dspring-boot.run.main-class='com.example.FooApplication' \
  -Dspring-boot.run.jvmArguments='-Dspring.config.name=foo-application'

相关问题