java - 如何强制 Java REST 应用程序进入空闲状态?
问题描述
我有一个包含大约 30 个端点的 REST 应用程序。除此之外,用户还可以提交一个需要 20-60 分钟才能处理的后台任务。有时很明显,提交的请求永远不会从日志中完成,但是,我唯一能做的就是重新部署相同版本的代码。
我希望能够杀死类似于我可以通过 mySQL 杀死的过程
'Show Process List' -> 'Kill <ProcessId>'.
我试图用 Thread.currentThread().interrupt() 来实现,但这并没有真正做任何事情。我在整个应用程序中多次使用 CompletionService 和多线程来加快进程。
我的目标是我应该能够调用此 API 以将应用程序返回到没有进程运行时的状态。我检查了这篇文章,但似乎每个人都在警告它。
这可以做到吗?
解决方案
为什么 Thread.currentThread().interrupt() 不起作用
Thread.currentThread()
返回您正在运行的当前线程的 Thread 对象,因此如果您在后台任务线程之外调用它,它将不会返回对您的后台线程的引用。如果你想引用你的后台线程,你必须自己跟踪它。
thread.interrupt()
在你的线程上设置一个中断标志。但是,如果您的线程从不明确检查中断标志,则它不会做任何事情。您必须定期检查后台任务中的中断标志,然后采取适当的措施。
if (Thread.currentThread().isInterrupted()) {
finishWork(); // Close any resources used.
return;
}
对于您的用例,我实际上不鼓励在后台任务上使用中断(),尤其是在您使用线程池的情况下。特别是如果您使用的是线程池,则可以重用同一个线程来运行多个后台任务。由于线程被重用,因此可能会意外中断您从未打算过的后台任务。
如何停止后台任务
这需要做大量的工作,但它是可行的。下面我将描述一个非常基本的实现,足以满足您的用例。
- 首先,您必须创建类似 SpringBoot 服务的东西。这是一个单例类,它被注入到执行其余端点的所有类中。该服务将是一个后台任务跟踪器,它保留从任务 ID 到指示是否应终止任务的标志的映射。
- 接下来,您必须创建一个休息端点来终止后台任务。其余端点应将任务 ID 作为查询参数或路径参数终止。
- 当端点执行时,您可以在后台任务跟踪器上调用终止方法,该方法将翻转指示任务应该终止的标志。注意:您的后台任务可能在您实际终止之前已经完成,因此您的代码应该处理这种极端情况。
- 当你启动你的后台任务时,你应该给它一个对你的后台任务跟踪器的引用。
- 您的后台任务应该做的第一件事是创建一个唯一的任务 ID。您可以从使用
UUID.randomUUID()
. - 创建任务 ID 后,将其提供给您的后台任务跟踪器。
- 在日志中为您的后台任务打印任务 ID。
- 后台任务可以继续完成它的工作,但它应该定期检查后台任务跟踪器是否已被取消。如果不继续处理,如果是,则关闭所有使用的资源并返回。
- 在您的后台任务退出之前,您应该将其从后台任务跟踪器中删除,以避免内存泄漏。
重要笔记
在实现这一点之前,请务必阅读如何正确同步 java 中线程之间的通信。这是一个很好的资源https://docs.oracle.com/javase/tutorial/essential/concurrency/sync.html
推荐阅读
- apache - 使用 Chrome 和 iframe 的内容安全策略
- r - 列中从小到大的订单号 (R)
- node.js - 保护 Javascript
- python - 我是 python 新手,正在寻求帮助。我正在尝试为 10 种不同的共同基金经营 Fama-French 并坚持下去
- reactjs - 未捕获的 FirebaseError:函数 CollectionReference.doc() 要求其第一个参数为非空字符串类型
- c# - 如何从流程中获取“项目名称”列表(不是流程名称或窗口标题)
- asp.net - 如何在 ASP.NET 中重置 Request.ServerVariables("SERVER_NAME")?
- javascript - 说明在一个参数和一个操作数(除法或乘法)的情况下如何使用 RPN 计算器
- ios - 如何使用 section 参数遍历集合内的每个文档以访问子集合的计数?
- prolog - 在 prolog 中使用 abs() 构建列表