【问题标题】:Liferay module (OSGi bundle) stays in "Stopping"Liferay 模块(OSGi 捆绑包)停留在“Stopping”
【发布时间】:2018-01-07 23:06:34
【问题描述】:

有时当我停止我的 Liferay 模块时(例如,当我将其 JAR 的新版本放入 deploy/ 时)模块拒绝停止。

虽然模块应该进入“已解决”状态,但它会永远处于“停止”状态:

通常是由于某个线程未在某处终止,或者网络连接未正确关闭,通常很难调查。

我的问题:如何更有效地找出这个 Liferay 模块的问题是什么?

我尝试了什么:

  • 在 Gogo Shell 中,diag <module id> 似乎没有提供任何有价值的信息来说明模块拒绝离开“停止”状态的原因。
  • jstack 输出数千行,其中绝大多数在所讨论的 Liferay 模块之外。如果有办法只显示我的模块的 jstack 信息,那就太好了。

【问题讨论】:

  • 您是否在模块中使用了激活器?状态停止意味着 Activator.stop() 方法被调用但尚未返回。你的一个线程应该在那个方法中。
  • @ChristianSchneider:添加了我的 ServiceActivator。
  • 您在解决 jstack 问题方面做得很好。它创建了一个线程转储,但大多数线程大约有 5-10 行。寻找更大的线程,尤其是其中调用了 ServiceActivator.stop 方法的线程。然后您将看到导致死锁或长时间休眠的原因。
  • @BalazsZsoldos:寻找 ServiceActivator.stop 是一个很好的提示!你想写一个关于它的答案吗?或者你没时间我可以写。
  • @NicolasRaoul 我认为查看线程转储并尝试查找代码 sn-p 与其说是真正的答案,不如说是一个建议。如果您想就阻止的原因做出回应,请随意。

标签: liferay osgi liferay-7 jstack gogo-shell


【解决方案1】:

首先,找到你的 webapp 服务器的 PID:

ps aux | grep tomcat

如果您正在运行除 tomcat 之外的其他服务器,或者如果您有多个实例正在运行,请调整该命令。

然后,将该服务器的所有线程转储到一个文件中:

jstack 12345 > jstack.txt

其中 12345 是您在第一步中找到的 PID。

然后,查看捆绑包的源代码,并找到服务激活器。它通常看起来像这样:

package fr.free.nrw;

[import section]

public class ServiceActivator implements BundleActivator {

    private ServiceRegistration registration;

    @Override
    public void start(BundleContext context) throws Exception {
        registration = context.registerService(
            MyService.class.getName(), new MyServiceImpl(), null);
    }

    @Override
    public void stop(BundleContext context) throws Exception {
        registration.unregister();
    }
}

注意:

  • 命名空间,
  • 类名,
  • 停止方法名称。

例如在上面的例子中它们是fr.free.nrwServiceActivatorstop,从这三个中得到全名fr.free.nrw.ServiceActivator.stop

现在打开jstack.txt 并搜索全名。即使文件长达数千行,也很可能只有一次命中,这就是有问题的线程:

at org.eclipse.osgi.internal.serviceregistry.ServiceRegistrationImpl.unregister(ServiceRegistrationImpl.java:222)
at fr.free.nrw.ServiceActivator.stop(ServiceActivator.java:30)
at org.eclipse.osgi.internal.framework.BundleContextImpl$4.run(BundleContextImpl.java:830)
at org.eclipse.osgi.internal.framework.BundleContextImpl$4.run(BundleContextImpl.java:1)
at java.security.AccessController.doPrivileged(Native Method)
at org.eclipse.osgi.internal.framework.BundleContextImpl.stop(BundleContextImpl.java:823)

在这个文件中,向上到段落的开头,这将是这样的:

"fileinstall-/home/nico/p/liferay/osgi/modules" #37 daemon prio=5 os_prio=0 tid=0x00007f39480e3000 nid=0x384f waiting on condition [0x00007f395d169000]
  java.lang.Thread.State: WAITING (parking)
    at sun.misc.Unsafe.park(Native Method)
    - parking to wait for  <0x00000000eb8defb8> (a java.util.concurrent.locks.AbstractQueuedSynchronizer$ConditionObject)
    at java.util.concurrent.locks.LockSupport.park(LockSupport.java:175)

有了这些信息,您将知道发生了什么样的线程问题,并且您将能够使用通常的 Java 线程调试技术来解决它 (12)。

【讨论】:

    【解决方案2】:

    您共享的 Activator 永远不应阻塞 stop 方法。所以我怀疑它会导致你描述的行为。

    【讨论】:

    • 可以的。 Activator的stop方法是同步调用的。他取消注册服务,这会导致同步服务侦听器(和服务跟踪器)的调用。在 ServiceTracker 上可能会死锁。
    • 啊..有趣。所以原因可能是其他包中的一些写得很糟糕的服务跟踪器或监听器。
    • 可能是。我说的是服务跟踪器级别,但在更高级别上也很容易犯错误。例如:在 DS 组件的服务引用(或激活方法)的设置器中编写一些休眠或等待的业务逻辑。这些代码 sn-ps 通常在服务注册完成时在同一线程上调用,因为它们基于同步服务跟踪器。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2013-02-26
    • 2012-06-26
    • 2015-08-13
    • 2015-05-22
    • 2015-10-04
    • 2023-03-03
    相关资源
    最近更新 更多