Stuck Threads no WebLogic

Um problema comum para tarefas demoradas no WebLogic é o famoso Stuck Thread. Para simular esse problema é só criar um projeto Web com uma servlet com o seguinte código: (Atenção!!! Não faça isso em casa. Isso é feito por profissionais treinados :D)

package br.com.thiagovespa.stuckthread.web.servlet;

import java.io.IOException;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

public class LongRunningServlet extends HttpServlet {
	private static final long serialVersionUID = 1L;

	protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
		for(int i=0;i<30;i++) { // 15min
			try {
				System.out.println("Estou executando: " + i);
				Thread.sleep(30*1000); //0.5 segundo
			} catch (InterruptedException e) {
				// TODO Auto-generated catch block
				e.printStackTrace();
			}
		}
	}
}

Thread e System.out no código (como eu disse.. não faça isso em casa e nem no trabalho :)).

Coloque o seguinte conteúdo no web.xml:

<?xml version="1.0" encoding="UTF-8"?>
<web-app xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns="http://java.sun.com/xml/ns/javaee" xmlns:web="http://java.sun.com/xml/ns/javaee/web-app_2_5.xsd" xsi:schemaLocation="http://java.sun.com/xml/ns/javaee http://java.sun.com/xml/ns/javaee/web-app_2_5.xsd" id="WebApp_ID" version="2.5">
  <display-name>StuckThreadWebProject</display-name>
  <servlet>
    <description></description>
    <display-name>LongRunningServlet</display-name>
    <servlet-name>LongRunningServlet</servlet-name>
    <servlet-class>br.com.thiagovespa.stuckthread.web.servlet.LongRunningServlet</servlet-class>
  </servlet>
  <servlet-mapping>
    <servlet-name>LongRunningServlet</servlet-name>
    <url-pattern>/LongRunningServlet</url-pattern>
  </servlet-mapping>
</web-app>

Ao acessar essa servlet no browser, vai fazer com que o WebLogic gere o seguinte erro após uns 10 minutos:

<Sep 5, 2012 3:51:13 PM BRT> <Error> <WebLogicServer> <BEA-000337> <[STUCK] ExecuteThread: '9' for queue: 'weblogic.kernel.Default (self-tuning)' has been busy for "636" seconds working on the request "Workmanager: default, Version: 0, Scheduled=true, Started=true, Started time: 636207 ms
[
GET /StuckThreadWebProject/LongRunningServlet HTTP/1.1
Connection: keep-alive
User-Agent: Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.1 (KHTML, like Gecko) Chrome/21.0.1180.89 Safari/537.1
Accept: text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8
Accept-Encoding: gzip,deflate,sdch
Accept-Language: en-US,en;q=0.8,pt-BR;q=0.6,pt;q=0.4
Accept-Charset: ISO-8859-1,utf-8;q=0.7,*;q=0.3

]", which is more than the configured time (StuckThreadMaxTime) of "600" seconds. Stack trace:
	java.lang.Thread.sleep(Native Method)
	br.com.thiagovespa.stuckthread.web.servlet.LongRunningServlet.doGet(LongRunningServlet.java:30)
	javax.servlet.http.HttpServlet.service(HttpServlet.java:707)
	javax.servlet.http.HttpServlet.service(HttpServlet.java:820)
	weblogic.servlet.internal.StubSecurityHelper$ServletServiceAction.run(StubSecurityHelper.java:227)
	weblogic.servlet.internal.StubSecurityHelper.invokeServlet(StubSecurityHelper.java:125)
	weblogic.servlet.internal.ServletStubImpl.execute(ServletStubImpl.java:301)
	weblogic.servlet.internal.TailFilter.doFilter(TailFilter.java:26)
	weblogic.servlet.internal.FilterChainImpl.doFilter(FilterChainImpl.java:56)
	oracle.security.jps.ee.http.JpsAbsFilter$1.run(JpsAbsFilter.java:119)
	java.security.AccessController.doPrivileged(Native Method)
	oracle.security.jps.util.JpsSubject.doAsPrivileged(JpsSubject.java:315)
	oracle.security.jps.ee.util.JpsPlatformUtil.runJaasMode(JpsPlatformUtil.java:442)
	oracle.security.jps.ee.http.JpsAbsFilter.runJaasMode(JpsAbsFilter.java:103)
	oracle.security.jps.ee.http.JpsAbsFilter.doFilter(JpsAbsFilter.java:171)
	oracle.security.jps.ee.http.JpsFilter.doFilter(JpsFilter.java:71)
	weblogic.servlet.internal.FilterChainImpl.doFilter(FilterChainImpl.java:56)
	oracle.dms.servlet.DMSServletFilter.doFilter(DMSServletFilter.java:139)
	weblogic.servlet.internal.FilterChainImpl.doFilter(FilterChainImpl.java:56)
	weblogic.servlet.internal.WebAppServletContext$ServletInvocationAction.wrapRun(WebAppServletContext.java:3730)
	weblogic.servlet.internal.WebAppServletContext$ServletInvocationAction.run(WebAppServletContext.java:3696)
	weblogic.security.acl.internal.AuthenticatedSubject.doAs(AuthenticatedSubject.java:321)
	weblogic.security.service.SecurityManager.runAs(SecurityManager.java:120)
	weblogic.servlet.internal.WebAppServletContext.securedExecute(WebAppServletContext.java:2273)
	weblogic.servlet.internal.WebAppServletContext.execute(WebAppServletContext.java:2179)
	weblogic.servlet.internal.ServletRequestImpl.run(ServletRequestImpl.java:1490)

Se você reparar no código de erro, existe um trecho-chave para a gente resolver o problema: "working on the request "Workmanager: default". Em alguns casos, temos operações que podem demorar muito mais que 10 minutos. Nesse caso, temos que utilizar um Workmanager que ignore as nossas Struck Threads.

No seu projeto, altere o arquivo weblogic.xml para o seguinte conteúdo:

<?xml version="1.0" encoding="UTF-8"?><wls:weblogic-web-app xmlns:wls="http://xmlns.oracle.com/weblogic/weblogic-web-app" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://java.sun.com/xml/ns/javaee http://java.sun.com/xml/ns/javaee/web-app_2_5.xsd http://xmlns.oracle.com/weblogic/weblogic-web-app http://xmlns.oracle.com/weblogic/weblogic-web-app/1.3/weblogic-web-app.xsd">
    <wls:weblogic-version>10.3.6</wls:weblogic-version>
    <wls:context-root>StuckThreadWebProject</wls:context-root>
    <wls:work-manager>
        <wls:name>wm/NoStuckWorkManager</wls:name>
        <wls:ignore-stuck-threads>true</wls:ignore-stuck-threads>
    </wls:work-manager>
    <wls:wl-dispatch-policy>wm/NoStuckWorkManager</wls:wl-dispatch-policy>
</wls:weblogic-web-app>

E no seu web.xml, associe o WorkManager à Servlet desejada:

<?xml version="1.0" encoding="UTF-8"?>
<web-app xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns="http://java.sun.com/xml/ns/javaee" xmlns:web="http://java.sun.com/xml/ns/javaee/web-app_2_5.xsd" xsi:schemaLocation="http://java.sun.com/xml/ns/javaee http://java.sun.com/xml/ns/javaee/web-app_2_5.xsd" id="WebApp_ID" version="2.5">
  <display-name>StuckThreadWebProject</display-name>
  <servlet>
    <description></description>
    <display-name>LongRunningServlet</display-name>
    <servlet-name>LongRunningServlet</servlet-name>
    <servlet-class>br.com.thiagovespa.stuckthread.web.servlet.LongRunningServlet</servlet-class>
	<init-param>
	   <param-name>wl-dispatch-policy</param-name>
	   <param-value>wm/NoStuckWorkManager</param-value>
	</init-param>
  </servlet>
  <servlet-mapping>
    <servlet-name>LongRunningServlet</servlet-name>
    <url-pattern>/LongRunningServlet</url-pattern>
  </servlet-mapping>
</web-app>

O mesmo problema pode ocorrer com outros recursos como WebServices, criei um WebService para simular o problema. O código com a solução você pode pegar aqui (Projeto Eclipse). Para WebService você só precisa alterar o weblogic.xml com o seguinte conteúdo:

<?xml version="1.0" encoding="UTF-8"?><wls:weblogic-web-app xmlns:wls="http://xmlns.oracle.com/weblogic/weblogic-web-app" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://java.sun.com/xml/ns/javaee http://java.sun.com/xml/ns/javaee/web-app_2_5.xsd http://xmlns.oracle.com/weblogic/weblogic-web-app http://xmlns.oracle.com/weblogic/weblogic-web-app/1.3/weblogic-web-app.xsd">
    <wls:weblogic-version>10.3.6</wls:weblogic-version>
    <wls:context-root>StuckThreadWebProject</wls:context-root>
    <wls:work-manager>
        <wls:name>wm/NoStuckWorkManager</wls:name>
        <wls:ignore-stuck-threads>true</wls:ignore-stuck-threads>
    </wls:work-manager>
    <wls:wl-dispatch-policy>wm/NoStuckWorkManager</wls:wl-dispatch-policy>
</wls:weblogic-web-app>

Ao invés de ignorar as Stuck Threads, uma solução melhor é re-especificar o tempo máximo para que o problema ocorra, dessa forma se ocorrer realmente algum problema, você irá saber:

<?xml version="1.0" encoding="UTF-8"?><wls:weblogic-web-app xmlns:wls="http://xmlns.oracle.com/weblogic/weblogic-web-app" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://java.sun.com/xml/ns/javaee http://java.sun.com/xml/ns/javaee/web-app_2_5.xsd http://xmlns.oracle.com/weblogic/weblogic-web-app http://xmlns.oracle.com/weblogic/weblogic-web-app/1.3/weblogic-web-app.xsd">
    <wls:weblogic-version>10.3.6</wls:weblogic-version>
    <wls:context-root>StuckThreadWebProject</wls:context-root>
    <wls:work-manager>
        <wls:name>wm/NoStuckWorkManager</wls:name>
        <wls:response-time-request-class>
            <wls:name>ResponseTime</wls:name>
            <wls:goal-ms>12000000</wls:goal-ms>
        </wls:response-time-request-class>
    </wls:work-manager>
    <wls:wl-dispatch-policy>wm/NoStuckWorkManager</wls:wl-dispatch-policy>
</wls:weblogic-web-app>

Você também pode configurar um Work Manager Global. Para isso, devemos acessar o console do WebLogic, e em Environment e selecione a opção Work Manager. Clique em New, selecione Work Manager e clique em Next:

Work Manager
Work Manager

Especifique um nome e clique em Next. Selecione os targets e clique em Finish. Selecione o Work Manager criado, marque a opção Ignore Stuck Threads e clique em Save.

Ignore Stuck Threads
Ignore Stuck Threads

Reinicie o servidor e agora você pode referenciá-lo na sua aplicação.

Sobre: Thiago Galbiatti Vespa

Thiago Galbiatti Vespa é mestre em Ciências da Computação e Matemática Computacional pela USP e bacharel em Ciências da Computação pela UNESP. Coordenador de projetos do JavaNoroeste, membro do JCP (Java Community Process), consultor Oracle, arquiteto de software de empresas de médio e grande porte, palestrante de vários eventos e colaborador de projetos open source. Possui as certificações: Oracle Certified Master, Java EE 5 Enterprise Architect – Step 1, 2 and 3; Oracle WebCenter Portal 11g Certified Implementation Specialist; Oracle Service Oriented Architecture Infrastructure Implementation Certified Expert; Oracle Certified Professional, Java EE 5 Web Services Developer; Oracle Certified Expert, NetBeans Integrated Development Environment 6.1 Programmer; Oracle Certified Professional, Java Programmer; Oracle Certified Associate, Java SE 5/SE 6