在 Spring 中使用 Cloud Foundry Worker
毫无疑问,你已经阅读了 Jennifer Hickey 的精彩博客文章,其中 介绍了 Cloud Foundry worker,它们在设置 Ruby Resque 后台作业中的应用,以及今天这篇介绍 Spring 支持的文章。
Spring 开发人员的关键要点
- 你需要通过
gem update vmc
更新你的vmc
版本。 - Cloud Foundry worker 允许你运行
public static void main
作业。也就是说,Cloud Foundry worker 本质上是一个进程,级别低于 Web 应用,这很自然地对应着许多所谓的后台作业。 - 你需要提供 Cloud Foundry 将运行的命令。你可以提供你希望它使用的
java
调用,但更简单的方法是随应用提供一个 shell 脚本,让 Cloud Foundry 为你运行该 shell 脚本。你提供的命令应该使用$JAVA_OPTS
,这是 Cloud Foundry 为了确保一致的内存使用和 JVM 设置而预先提供的。 - 有多种方法可以自动化创建 Cloud Foundry 可部署应用程序。如果你使用 Maven,那么
org.codehaus.mojo:appassembler-maven-plugin
插件将帮助你创建启动脚本并将你的.jars
打包以便于部署,同时还可以指定入口点类。 - 其他一切基本相同。当你对 Java
.jar
项目执行vmc push
时,Cloud Foundry 会询问你的应用程序是否是独立应用程序。确认后,它将引导你完成后续设置。
那么,让我们来看几个使用 Cloud Foundry worker 更简单、更自然的常见架构和安排。我们将从 Spring 框架和两个周边项目 Spring Integration 和 Spring Batch 的角度来看这些模式,这两个项目都在 Web 应用程序内外表现出色。正如我们将看到的,这两个框架都支持解耦和改进的可组合性。我们将把发生什么与何时发生分离,并将发生什么与何处发生分离,两者都是为了释放前端容量。
我有一个要遵守的计划!
我常遇到的一个问题是:如何在 Cloud Foundry 上做作业调度? Cloud Foundry 支持 Spring 应用程序,而 Spring 当然一直支持企业级的调度抽象,比如 Quartz 以及 Spring 3.0 的 @Scheduled
注解。@Scheduled
非常好用,因为它超级容易添加到现有应用程序中。在最简单的情况下,你只需将 @EnableScheduling
添加到你的 Java 配置或将 <task:annotation-driven/>
添加到你的 XML 中,然后在你的代码中使用 @Scheduled
注解即可。这在企业应用程序中是非常自然的事情——也许你有一个需要运行的分析或报告流程?或者一些长时间运行的批处理流程?我整理了一个示例,演示如何使用 @Scheduled
运行一个 Spring Batch Job
。这个 Spring Batch 作业本身是一个 worker 线程,它与一个 Web 服务交互,该服务的 SLA 较差,不适合实时使用。将工作放在 Spring Batch 中处理更安全、更清晰,它的恢复和重试能力可以弥补任何网络中断、网络延迟等问题。关于大部分细节,我会让你参考代码示例,我们只看入口点,然后看看如何将应用程序部署到 Cloud Foundry。
// set to every 10s for testing.
@Scheduled(fixedRate = 10 * 1000)
public void runNightlyStockPriceRecorder() throws Throwable {
JobParameters params = new JobParametersBuilder()
.addDate("date", new Date())
.toJobParameters();
JobExecution jobExecution = jobLauncher.run(job, params);
BatchStatus batchStatus = jobExecution.getStatus();
while (batchStatus.isRunning()) {
logger.info("Still running...");
Thread.sleep(1000);
}
logger.info(String.format("Exit status: %s", jobExecution.getExitStatus().getExitCode()));
JobInstance jobInstance = jobExecution.getJobInstance…