概述
本文是Spring Cloud Task系列的第二篇文章,如果你尚未使用过Spring Cloud Task,请
移步spring cloud task1 简介与示例。
本篇文章将讲述更多Spring Cloud Task的细节内容,包括task的生命周期论与TaskRepository
中存储的任务数据结构。
Spring Cloud Task的生命周期
现代的云平台都是围绕着长生命周期的服务而设计的,如web应用,一经启用,除非手动去重启应用,否则就会没有终点的持续运行。虽然大多数平台都有方法在不重启应用的情况下,将服务的生命周期推向终点,但每个服务的处理结果难以以可重用的方式来维护。Spring Cloud Task可以在平台环境中执行短生命周期的应用,并记录这些应用的结果,经由通过消息通知的机制来集成各个tasks。通过这特性就可以实现让短生命周期的应用像长生命周期的应用一样组成微服务架构。
Spring Task Cloud的方式对现代的云环境是非常有用的,但它也在部署应用方面带来新问题。如使用调度器(如corn)来执行Spring Boot应用时,如何在应用结束后监控到其执行结果?
Spring Cloud Task采用的方法是,将Spring Boot应用分为开始、结束、以及正在运行等状态。如批处理任务就是一个清晰的短生命周期应用,Spring Cloud Task会监控指定任务的所有生命周期事件。
生命周期是一个任务task实例运行的全过程,也是一个被配置为task的Spring Boot应用被执行的过程(通过 添加@EnableTask
注解配置)。
在task刚刚开始运行时(CommandLineRunner
或ApplicationRunner
及其子类的实例被执行之前)TaskRespository
会创建一条task纪录并将其标记为start状态。start事件由spring框架的SmartLifecycle#start
触发。开始事件被触发说明了系统已经做好了执行CommandLineRunner
或ApplicationRunner
及其子类的实例的准备。
任务纪录只有在
ApplicationContext
被成功启动后才会被纪录。如果ApplicationContext
没有被成功启动,那么task的相关信息也不会被纪录。
当Spring Boot应用的所有*Runner#run
接口都被调用后,或者在ApplicationContext
发生了失败(由ApplicationFailedEvent
来表现),任务仓库中此任务的执行结果都会被更新。
task 完成之后(
*Runner#run
方法被执行完)默认情况下会被关闭ApplicationContext
。这个特性可以在配置文件中设置spring.cloud.task.closecontext_enable
属性为false
来更改。
其实现原理如下面代码所示:
public class TaskLifecycleListener{
...
/**
* 在发生task相关的事件后,会自动调用这个方法
* Utilizes {@link ApplicationEvent}s to determine the start, end, and failure of a
* task. Specifically:
* <ul>
* <li>{@link ContextRefreshedEvent} - Start of a task</li>
* <li>{@link ApplicationReadyEvent} - Successful end of a task</li>
* <li>{@link ApplicationFailedEvent} - Failure of a task</li>
* </ul>
*
* @param applicationEvent The application being listened for.
*/
@Override
public void onApplicationEvent(ApplicationEvent applicationEvent) {
if(applicationEvent instanceof ApplicationFailedEvent) {
this.applicationFailedEvent = (ApplicationFailedEvent) applicationEvent;
doTaskEnd();
}
else if(applicationEvent instanceof ExitCodeEvent){
this.exitCodeEvent = (ExitCodeEvent) applicationEvent;
}
else if(applicationEvent instanceof ApplicationReadyEvent) {
doTaskEnd();
}
}
...
}
1. 任务运行时信息
TaskRepository
中存储任务信息的数据结构是以TaskExecution
类为模板创建的,其内容如表1所示。
字段名 | 描述 |
---|---|
executionid |
任务执行时的编号,全局唯一 |
exitCode |
任务退出代码,由ExitCodeExceptionMapper 映射器的子类所生成,在没有相关的映射器时,,如果有ApplicationFailedEvent 被抛出,code码会是1。否则code码就是0,代表着task被成功执行。 |
taskName |
TaskNameResolver 所配置的task的名字。 |
startTime |
SmartLifecycle#start 被调用的时间,代表task的开始时间。 |
endTime |
ApplicationReadyEvent 事件所表示的task的完成时间 |
exitMessage |
退出task时所留下的有用的信息,可以1编程配置经由ApplicationReadyEvent 来实现。 |
errorMessage |
如果由于发生异常而导致应用结束(指发生了ApplicationFailedEvent 事件),运行时异常栈信息都会被存储到这个字段中。 |
arguments |
经Spring Boot校验通过的字符命令的参数集合 |
表1 TaskExecution
所包含的数据表
2. 退出代码映射
task应用执行结束后,它会返回一个code代码给操作系统。回想一下我们上面文章所描述的例子,我们并没有控制当应用程序结束后应该返回什么code码,所以当抛出异常时,JVM可能会返回一个对你的调试没有任何帮助的code码。
因此Spirng Boot提供了ExitCodeExceptionMapper
接口,将未捕获的异常直接转化为特定的code码,帮助你定位与分析问题。当实现了ExitCodeExceptionMapper
接口后,Spring Cloud Task会纪录下自定义的应用返回code码。
task在执行结束后会返回一个数字信号(SIG-INT)或术语信号(SIG-TERM)的code码,这个code码应该是在ExitCodeExceptionMapper
接口实现类中定义的非0的代码。
当task正在运行时,仓库中任务实例的
exitCode
字段存储的内容是 null。一旦任务执行完成,字段存储的内容就变成了从枚举中取出的特定code码。
引用
本文是我在学习使用Spring Cloud Task 时的笔记,在本文的写过过程中参考了大量其它资料,有些材料来源于网络,我由衷的表示感谢,但由于原作者不明,恕不能一一记述。
- Spring Cloud Task Reference Guide.[Michael Minella, Glenn Renfro].v1.2.4RELEASE
- Spring Cloud Task 项目仓库
- Spring Cloud Data Flow Reference Guide#Task
关于
示例源码
Spring Cloud Task learning 的 task-demo 子项目
补充
阅读本文之后,如果你还对Spring Cloud Task的生命周期有所疑惑,请重新复习一下 spring ApplicationEvent
和 ApplicationListener
所关联的 context.publishEvent()
事件发布模型,Spring Cloud Task的生命周期便是基于这个事件发布模型做的。详细代码请参考org.springframework.cloud.task.listener.TaskLifecycleListener
类的源码。如果还有不解之处,请你在文章下方留言,我会尽力帮你解答疑惑。
后记
Spring Cloud Task是一个优秀的项目,但是我找遍网络,也难以找出系统的、准确的中文相关文档。本系列文章以保证对Spring Cloud Task相关概念和设计理解的正确性为标准,尽量采用通俗易懂的语言,希望能给各位带来一些便捷。
本文内容主要是对 Spring Cloud Task 1.2.2-RELEASE 官方文档的翻译,不过作者水平有限,有不尽然的地方敬请指出。本项目和文档中所用的内容仅供学习和研究之用,转载或引用时请指明出处。如果你对文档有疑问或问题,请在项目中给我留言或发email到
weiwei02@vip.qq.com 我的github:
https://github.com/weiwei02/ 我相信技术能够改变世界 。
网友评论