WebObjects/Web 应用程序/部署/常见问题和故障排除
我正在处理的当前应用程序在调用 editingContext.saveChanges 时会冻结大约一分钟。以下消息将添加到系统输出中
<WorkerThread3> <WOWorkerThread id=3 socket=Socket[addr=/xxx.xxx.xxx.xxx,port=51634,localport=51563]> Exception while sending response: java.net.SocketException: Broken pipe
奇怪的是,实际上没有抛出异常,并且更改已保存到数据库。关于此消息的含义,有什么线索吗?
此消息表示 woadaptor 在分配的时间内未收到您的应用程序的响应。此时,woapdator 会挂断您的应用程序,假设它已死或过于繁忙。如果您运行了多个实例,woadaptor 将把请求转发到另一个实例。对于组件操作,这将产生会话过期或无法恢复页面的错误消息。
当您的应用程序最终完成处理请求时,它会尝试将结果返回给 woadaptor,但发现它已挂断(即关闭了套接字,断开了管道)。此时,上面的异常将输出到日志。
有几种方法可以避免这种情况
- 优化您的应用程序,以便更快地处理请求。
- 使用 WOLongReponsePage 处理长时间运行的请求。
- 在 JavaMonitor 中增加连接超时和接收超时值,以便 woadaptor 会等待足够长的时间,直到您的应用程序提供响应。
注意: 如果此消息发生在其他情况下(即不是在处理请求需要很长时间时),它可能仅表示用户在浏览器中按下了停止按钮或单击了另一个链接。
Wotaskd 使用名为 SpawnOfWotaskd.sh 的脚本启动新的 WOA 实例,该脚本位于 OS X 上的 /System/Library/WebObjects/JavaApplications/wotaskd.woa/Contents/Resources/SpawnOfWotaskd.sh。出于某种原因,此脚本被编写为丢弃 stderr。这意味着如果您想获得线程堆栈转储,您将无能为力。幸运的是,这是一个简单的修复。如果您编辑 SpawnOfWotaskd.sh,股票版本看起来像
#!/bin/sh $@ 1>/dev/null 2>&1 &
请注意,流 1 转到 /dev/null,流 2 写入流 1。糟糕。将其更改为
#!/bin/sh $@ 1>>/var/log/webobjects.err 2>&1 &
现在唯一的问题是,WebObjects 应用程序通常以 appserver 用户身份运行,这意味着它们将无法写入此文件。要解决此问题,您可以以 root 身份“touch /var/log/webobjects.err”,然后将空文件 chown 到您的 WebObjects 应用程序运行的任何用户。
啊,是的,AWT 的乐趣。如果您触摸任何 AWT 类(即使是那些没有意义的类,例如 Dimension 或 Rectangle),AWT Toolkit 将被创建(在静态块中),并且 AWT 将尝试连接到窗口服务器。当然,当您在开发模式下运行时,您有权访问窗口服务器,一切都很顺利。只要您尝试以 appserver 用户身份部署,一切都乱了套。您有几个选项可以解决此问题
- 停止使用它们。这是避免此问题最可靠的方法。在不需要时不要使用 AWT 类。显然,这往往说起来容易做起来难。
- 将 -Djava.awt.headless=true 添加到您的 VM 启动参数。这告诉 AWT 使用无头模式。如果您使用的是旧版本的 Apple JVM,这可能仍然会导致问题(奇怪的调试语句要求您在控制台上按一个键)。
- PJA Toolkit。这实际上是一个很酷的库。它是 AWT 工具包的纯 Java 实现。在普通系统上,您的 AWT 实现是 JNI(与您的本地窗口系统通信)。PJA 提供了所有功能的纯 Java 实现,这些功能是普通 AWT 工具包会尝试执行的。显然它并没有真正使用窗口服务器,而是类似于具有虚拟帧缓冲区的 VNC 服务器。
- 以 root 身份运行。这通常不建议,但您可以修改您的 /System/Library/StartupItems/WebObjects/WebObjects 脚本,以便以 root 身份运行 WO,而不是 appserver 用户。您将在该脚本中找到有关如何执行此操作的说明。
对于在 Mac OS X 上遇到监视器问题的人,请检查以下参数
- 检查机器在 DNS 中是否被正确识别,包括反向查找。
- 验证在监视器中添加机器时,您是否包含了完全限定名称,例如“machine.domain.com”,而不仅仅是“machine”。使用较短的版本可能会起作用,但实际上不起作用(Apple 有此说明)。
- 检查适配器配置(/System/Library/WebObjects/Adaptors/Apache/apache.conf),特别是实例发现方法:这需要与 wotaskd 的命令行启动一致(请参阅 /System/Library/StartupItems/ 中的脚本)。您可能需要手动修改脚本。
- 一切设置完成后,重新启动。它应该可以工作。
在旧版本的 OS X 服务器中,WOtaskd 和 JavaMonitor 是使用 StartupItems 系统启动的。在较新版本的 OS X 服务器和 WebObjects 中,Apple 使用了新的 launchd 框架。如果您使用开发人员工具安装 WebObjects,您通常只会在 Startupitem 脚本中找到这些脚本,因此您应该遵循这些说明。
有关 launchd 的概述,您可以阅读 Apple 的文档。
WebObjects launch daemon 项默认情况下处于禁用状态,因此您需要做的第一件事是启用它们
- cd /System/Library/LaunchDaemons
- 编辑“com.apple.womonitor.plist”和“com.apple.wotaskd.plist”
- 将 Disabled 键从“true”更改为“false”
- 保存并退出
接下来,您需要手动加载 launch daemon 项
- 以 root 身份运行“launchctl”
- “list”并查找 com.webobjects.womonitor 和 com.webobjects.wotaskd
- 如果它们确实存在,您需要手动加载它们
- “load /System/Library/LaunchDaemons/com.apple.wotaskd.plist”
- “load /System/Library/LaunchDaemons/com.apple.womonitor.plist”
- 再次“list”并验证它们都出现
- “start com.webobjects.wotaskd”
- “start com.webobjects.womonitor”
- 退出 launchctl(按 ctrl-c)
wotaskd 和 womonitor 现在都应该在运行。您可以通过访问 https://127.0.0.1:56789 来测试监视器。
如果这不起作用,请检查 /Library/WebObjects/Configuration 上的文件系统权限,这些权限应该是 appserver:appserverusr,或者至少应该具有对该目录的写入权限。
在终端窗口中运行以下命令将准确告诉您为什么 wotaskd 未启动...
sudo -u appserver /System/Library/WebObjects/JavaApplications/wotaskd.woa/Contents/Resources/javawoservice.sh -appPath /System/ Library/WebObjects/JavaApplications/wotaskd.woa/wotaskd
在开发人员安装和旧版本的 Mac OS X Server 安装中,WebObjects 是使用旧的 StartupItems 系统启动的。默认情况下,wotaskd 和 womonitor 处于禁用状态。幸运的是,启用它们很容易
- cd /System/Library/StartupItems/WebObjects
- 编辑“WebObjects”
- 搜索“-appPath”,您将在脚本的此区域中找到四行注释掉的代码。
- 要以 root 身份运行 WebObjects,请取消注释前两条命令(您应该会看到 WOTASKD 和 WOMONITOR 行)
- 要以另一个用户身份运行 WebObjects(默认情况下为 appserver 用户),请取消注释第二组行
- 保存并退出
- 使用以下两种方法之一启动 WebObjects 服务
- sudo systemstarter start "WebObjects Services"
- ./WebObjects start
进行这些更改后,wotaskd 和 womonitor 将在重新启动后自动启动。
注意:不要在安装了 WO 5.3.* 的 MacOS X 10.4.* 服务器机器上执行这些步骤。在这种情况下,进程会以 LaunchDeamon(如上所述)的形式启动。如果您启用了启动项,系统会尝试启动两次 wotaskd,这会导致什么都无法正常工作。
有多种方法可以处理死锁和应用程序挂起。
如果您使用的是 性能分析器 或调试器,您通常可以暂停执行并查看应用程序到底是在哪里崩溃的。
如果您使用的是 JDK 1.4,您可以向应用程序发送 QUIT 信号,它将转储所有活动线程。在 OS X 上,找到应用程序的 pid,然后执行 'kill -QUIT yourAppPID'。线程堆栈跟踪将转储到日志文件。如果您在日志中没有看到任何输出,请查看上面的“我的 stderr 在哪里?!”以了解可能的原因。
如果您使用的是 JDK 1.5,除了可以向应用程序发送 QUIT 信号之外,您还可以(以 root 或启动用户的身份)附加到应用程序,并使用 'jstack' 应用程序调用 'jstack yourAppPID' 获取线程堆栈转储。
如果您看到 WOWorkerThreads 在等待恢复会话时挂起,这通常意味着之前的请求从未正确检查其会话的某个位置抛出了异常。WebObjects 中的会话访问是单线程的。可能导致这种情况的常见情况包括从您的 awake 方法抛出异常以及从 DirectAction 方法抛出异常。
在 JDK 1.4 中,您将能够看到每个堆栈跟踪持有的对象锁列表。您可以通过查找包含两个或多个重叠锁的多个线程来查找死锁。在 JDK 1.5 中,VM 会检测死锁情况,并在线程堆栈转储中识别它们。