关于如何优雅的停止任务

2023-07-28 10:36:53 +08:00
 codermax

第一次发帖还是提问贴,如有不妥还请诸多包涵,多多谅解。

目前有个接口任务,这个任务链比较长,里面包含了对外部系统的调用,异步查询外部任务的执行结果,文件上传,数据获取等,就是比较复杂,但是整个任务链属于一个任务,在数据库中有个对应的任务表维护任务的状态(运行中、超时、结束等)

目前的需求是想通过另一个接口对上面这个任务进行操作,需要在任意时刻停止该任务,然后更新表中的任务时刻状态。然后反馈给前端。

目前我的想法是在 redis 或者其他地方写入一个标识,在不同的耗时子任务后根据这个标识来停止任务,但是这么写比较繁杂,而且后续维护肯定也不太好,另一个想法(也是我请教另一个哥们的)是所有子任务维护到一个 map 中,做统一的判断启停,但是任务状态维护可能是个问题。

所以想问问各位大佬们,有没有别的比较优雅的方法,不胜感激!!!

2697 次点击
所在节点    Java
16 条回复
yazinnnn
2023-07-28 10:48:31 +08:00
https://www.reactive-streams.org/

随便找个 reactive streams 的实现, 比如 reactor 或者 rxjava, 把你的异步任务拆碎
codermax
2023-07-28 12:08:20 +08:00
@yazinnnn 感谢回复,大概看了下,感觉改造成本比较大,还要引入别的依赖。
sumarker
2023-07-28 12:23:44 +08:00
执行中的任务要立刻停止的话,肯定是直接杀进程最快吧
如果要等,那就维护一个队列,控制进入的入口,如果要停就 关闭入口,等队列都跑完了,再关进程
hangszhang
2023-07-28 13:35:20 +08:00
任务进程化,然后管理进程
hangszhang
2023-07-28 13:36:08 +08:00
比如用 java -jar 起一个进程,拿到这个进程的 pid ,终止的方式就是 kill 进程
wushigejiajia01
2023-07-28 13:40:54 +08:00
插眼学习下
rekulas
2023-07-28 13:42:37 +08:00
就加标识不就最简单有效的,为什么会觉得开发维护麻烦
yazinnnn
2023-07-28 14:09:13 +08:00
@codermax
引入依赖问题不大, 一般 java 框架比如 spring quarkus 之类都集成了 reactive streams, 重点是怎么把任务拆了, 而且取消时产生的副作用怎么处理(比如数据库(这个可以加事务), 上传完成但业务上作废的文件)
37Y37
2023-07-28 14:53:29 +08:00
正好写过几乎完全一样的功能,你这里所说的断开就是执行中的强制结束吧,我是 python 写的,你可以参考下看看
37Y37
2023-07-28 14:54:00 +08:00
kanepan19
2023-07-28 16:34:06 +08:00
可以用 java 的 中断 ....... 然而并不优雅
fantathat
2023-07-28 17:11:24 +08:00
任务比较耗时吧,必须要有一个公用的状态来判断是否执行当前阶段的子任务
burymme11
2023-07-28 17:34:31 +08:00
任务中使用一个标志变量来指示任务是否应该停止虽然看起来会比较麻烦,但是这种方式会比较稳,直接杀线程可能会导致一些意外。我给个写法思路,你看看是否可以帮你。
private Boolean handle0(Object... arg) {
// Prcoess 任务抽象接口。在 list 中排好子任务的执行顺序,从 list 中取子任务的实现类
Prcoess process = TaskProcessList.get(this.startIndex);
boolean taskRes = process.doTask(arg);
// 查询任务中断标识
boolean interruptFlag = getInterruptFlag();
// 子任务执行成功 && 非最后一个子任务 && 中断标识为 false -> 继续递归,执行下一个任务。
if (taskRes && this.startIndex < TaskProcessList.size() - 1 && !interruptFlag) {
this.startIndex = this.startIndex + 1;
return handle0(arg);
}
// 收到任务中断信号
if (interruptFlag) {
// update task status 。根据下标也可以知道哪些子任务已经执行,哪些未执行。
// todo
// 收到任务中断信号算正常业务结束,返回 true 。
return true;
}
// 某个子任务执行失败
if (!taskRes) {
// 上述同理。但是算业务异常,返回 false
return false;
}
// 只有当最后一个子任务执行正常执行完成。才会返回 true 。如果中间过程某个子任务返回失败,递归中断,并且
// 返回 false
return taskRes && this.startIndex == TaskProcessList.size() - 1;
}
burymme11
2023-07-28 17:42:25 +08:00
缺了一个全局变量。要补上。
private Integer startIndex = 0;
-----------------------------------------
不对,等下。你说的任意时刻停止任务,是 shutDown 还是 shutDownNow ?
NoSuchException
2023-07-28 17:50:32 +08:00
OP 的意思是要等整个调用链完整的执行完之后在停止任务吧。在任务链开始的时候往 Redis 里面丢一个标识进去,比如自定义一个任务 Id 之类的,整个调用链完成后删除这个任务 Id 标识。

停止任务的话可以另起一个接口,查看 Reids 中是否还存在任务,存在任务就暂时等待,不存在就给停止了。这个接口你可以用个 while 循环+Threed sleep 来做。
kamalei
2023-07-28 17:57:28 +08:00
不同语言编写的后端程序实现方式的 idioms 不一样。
要不要考虑进程会强杀的情况?
任务是分布式运行的吗?
更多细节问题确认后就好搞了,我觉得其实不用 redis 这么麻烦。

这是一个专为移动设备优化的页面(即为了让你能够在 Google 搜索结果里秒开这个页面),如果你希望参与 V2EX 社区的讨论,你可以继续到 V2EX 上打开本讨论主题的完整版本。

https://www.v2ex.com/t/960450

V2EX 是创意工作者们的社区,是一个分享自己正在做的有趣事物、交流想法,可以遇见新朋友甚至新机会的地方。

V2EX is a community of developers, designers and creative people.

© 2021 V2EX