我有一个shell脚本,我想从J2EE Web应用程序触发其。
该脚本很多东西 - 处理,FTP传送等 - 这是一个传统的东西。
这需要很长的时间来运行。
我想知道什么是对此最好的办法。 我希望用户能够点击一个链接,触发脚本,并显示一条消息给用户说,剧本已经开始。 我想在HTTP请求/响应周期是瞬时的,无论是我的脚本需要很长的时间来运行的事实。
我能想到的三个选项:
- 用户点击的处理过程中产生新线程。 不过,我不认为这是符合J2EE规范。
- 发送一些产量下降的HTTP响应流和触发脚本之前提交。 这给了HTTP请求/响应周期结束的错觉,但实际上该线程处理请求仍然坐在那里等待shell脚本来完成。 所以,我基本上劫持容器HTTP处理线程为我自己的目的。
- 创建该开始我的主要脚本在后台一个包装脚本。 这将让请求/响应循环到容器正常完成。
所有上述将被使用servlet和调用Runtime.getRuntime()。EXEC()。
这是使用Oracle的OC4J应用服务器,Java的1.4.2在Solaris上运行。
请没有任何人有任何意见上这是最哈克解决方案,为什么?
或者有没有人有一个更好的办法? 我们有石英可用,但我们不希望有重新实现shell脚本作为一个Java进程。
谢谢。
我与选项3去了,特别是如果你实际上并不需要知道什么时候该脚本完成(或者不是等待进程结束找出其他的一些其他的方式)。
选项1个浪费一个线程,只是将要围坐在等待脚本来完成。 选项2似乎是一个坏主意。 我不会劫持servlet容器线程。
你提到石英所以让我们去的第4个选项(这是国际海事组织当然最好):
- 使用Quartz调度和org.quartz.jobs.NativeJob
PS:最大的问题可能是为了寻找文件,这是我能找到的最好来源: 如何使用NativeJob?
是否有必要为您的应用程序,以评估从你开始脚本输出,或者这是一个简单的发射后不管的工作吗? 如果它不是必需的,你可以“虐待”的事实,调用Runtime.getRuntime()。EXEC()将立即与过程继续在后台运行返回。 如果你真的想等待脚本/过程到结束,你将不得不调用WAITFOR()()执委会返回Process对象上。
如果你开始的进程写入任何东西到标准输出或标准错误,一定要这些重定向到任何日志文件或/ dev / null,否则该过程将在一段时间后阻止,因为输出和错误都可以与通过有限的缓冲capabilites InputStreams Process对象。
我对这种做法很可能是类似以下内容:
- 设立的ExecutorService的servlet中执行的实际执行。
- 创建的实现可调用用适当的返回类型,封装了实际的脚本执行(使用的Runtime.exec() )来翻译Java输入变量shell脚本参数,脚本输出到适当的Java对象。
- 当一个请求进来,建立一个适当的
Callable
对象,将其提交给执行服务,并把所产生的Future
某处持久的(例如,用户的会话,或UID-加密映射返回键,用户供以后查询,根据需要)。 然后立即发送暗示脚本启动OK的HTTP响应用户(包括如果需要查找键)。 - 添加一些机制,为用户查询自己的任务进度,要么返回一个“仍在运行”回应,“失败”的反应还是取决于状态为“成功+结果”响应
Future
,你只是抬头。
这是一个有点handwavy但根据您的web应用程序是如何组织的,你可能可以在某处适合这些通用部件。
如果您的HTTP响应/用户并不需要看到脚本的输出,或知道该脚本完成时,那么你最好的选择是启动线程在某种包装脚本中你提到,以便它可以运行servlet容器整体环境之外。 这意味着你可以从需要在容器内管理线程,或劫持线程你提到,等自己开脱
只有当用户需要被告知当脚本完成和/或监控脚本的输出,我会考虑选择1或2。
对于第二个选项,你可以使用一个servlet,你已经回答了HTTP请求后,您可以使用java.lang.Runtime.exec()来执行脚本。 我也建议你看看这里: http://www.javaworld.com/javaworld/jw-12-2000/jw-1229-traps.html
...对于一些问题和使用它的缺陷。
异步后端进程最健壮溶液IMO使用消息队列。 最近,我这个使用Spring的嵌入式ActiveMQ代理,而且设备安装一个生产和消费的Bean实现的。 当工作需要启动,我的代码调用,它将一个消息队列中的生产商。 消费者订购了队列和消息在一个单独的线程被踢成行动。 这种方法整齐地分离从排队机制的UI(通过生产者),和从所述异步处理(由消费者处理)。
请注意,这是一个Java 5,Spring的配置环境中的开发人员计算机Tomcat服务器上运行,并部署到Weblogic上试/生产机器。
您的问题,从事实,你试图去针对J2EE模式“每个请求单个响应”,并让最终用户的页面动态更新作为后台任务执行茎。
除非你想下去引入基于Ajax的解决方案,你将不得不强制用户的浏览器,以“轮询”定期对信息的服务器所呈现的页面,直到后端任务完成。
这可以通过以下方式实现:
当J2EE容器接收该请求,生成一个线程这需要给会话对象的引用(其将被用来编写脚本的输出)
初始化响应servlet来写一个HTML网页,其中将包含Javascript函数从定期(每10秒左右)的服务器重新加载该页面。
对每个请求,轮询会话对象来显示由产生的线程在步骤1中存储的输出
[可加入清理逻辑从会话中删除存储的内容一旦线程完成如果需要的话,你也可以在你的脚本执行的标记状态转换会话设置任何其他标志]
这是为了实现你想要的一种方式 - 它不是最优雅的所有方法,但它主要是由于需要异步更新来自服务器的页面内容,与请求/响应模型。
还有其他的方法来实现这一点,但它真的取决于你如何约束是不够灵活。 我听到的直接Web远程 (虽然我还没有发挥它尚未),可能是值得考虑看看使用反向的Ajax开发应用程序