WebObjects/Web 应用程序/部署/计划重启
让我们更深入地看看发生了什么。当指定时间到来时,wotaskd 向应用程序发送一条消息,要求其开始拒绝新会话。应用程序将开始将所有后续没有会话的请求重定向到没有拒绝新会话的实例。当然,在你的情况下,最终所有实例都会拒绝,并且 woadaptor 会举手表示沮丧并宣称“无可用实例”。
但对我们来说,有趣的环节发生在之前。在被告知拒绝新会话后,应用程序会悄无声息地继续为已经拥有会话的用户提供服务,等待他们终止会话。当每个会话终止时,它会检查剩余会话的数量是否低于阈值(默认值为 1)。如果是,它会调用 terminate() 并关闭运行循环。此时,如果一切顺利,只有守护线程在运行,JVM 会停止它们并退出。wotaskd 会注意到应用程序没有运行,并重新启动它。前提是所有操作都正常。
现在,会发生什么问题?我所见过的两个最常见的问题是 (1) 永久会话 - 会话计数从未降至零,以及 (2) 卡住的非守护线程。第一种情况会阻止应用程序调用 terminate() 并开始退出进程。第二种情况会阻止 JVM 在主应用程序线程停止后终止。
永久会话是由你的代码中引发的异常引起的,这些异常会阻止会话被检入会话存储区。造成此问题的首要原因是在 session 的 sleep() 方法中引发异常。如果你使用此方法,请用 try...catch 包裹它以处理可抛出对象。不要让此方法在任何情况下都抛出异常。永久会话也可能是由 awake() 和 terminate() 中抛出的异常引起的,而且我相信还存在其他原因。
卡住的线程通常是由于某种线程死锁造成的,并且经常会在从另一个线程中请求从未检入的会话时,由于永久会话而导致。如果你的应用程序正在创建未标记为守护线程且在应用程序终止时未关闭的线程,则可能会出现类似的情况。
好的,所有这些都很好,但你该怎么做呢?首先,你要等到这种情况发生并获得应用程序的线程转储。这里有一些说明:http://lists.apple.com/archives/webobjects-dev/2003/Sep/msg00362.html 请注意,你需要编辑的文件位于 /System/Library/WebObjects/JavaApplications/wotaskd.woa/Contents/Resources 中。确保 appserver 用户对你要指向的目录/文件具有写入权限。
接下来,你需要在应用程序中添加一些更好的日志记录。至少,我建议你这样做
- 记录创建会话时的 ID
- 记录调用会话的 terminate() 时 ID
- 记录调用会话的 terminate() 时应用程序的剩余 activeSessionsCount()
- 记录应用程序中 dispatchRequest() 中的 RR 查找的启动和停止
- 记录拒绝会话和 refuseNewSessions(boolean) 中的 activeSessionsCount()
- 记录调用应用程序的 terminate() 时
我的首选是修复你的代码。其次,如果你设置了很长的会话超时,而用户仍在工作,则应用程序可能需要相当长的时间才能重新启动(只要用户继续工作,再加上会话超时)。第三,如果 JVM 正在等待卡住的线程,那么你无能为力,因为发送文本页面的任何守护线程都已经被杀死了(至少我认为是这样)。好了,忽略所有这些,当 true 传递时,在 refuseNewSessions(boolean) 中以守护线程的形式启动计时器。当计时器触发时,发送文本消息。或者,如果你像我一样喜欢睡觉,只需调用 System.runtime().exit(1)。如果稍后用 false 调用 refuseNewSessions(boolean),则停止计时器。这只是以防万一有人在 JavaMonitor 中点击。