Problema Vraptor + Interceptor

Senhores,

Estou com um problema estranho, pois só ocorre às vezes.
Na minha opiniã o é o pior tipo de problema.

Deixa eu explicar:
Tenho uma aplição em VRaptor na qual eu tenho uma lista de Interceptors anotados com as anotações @after e @before.
A lista de interceptors não formam um cíclo, isso foi a primeira coisa que eu verifiquei.

Mesmo assim, em alguns casos, na hora que eu dou o deploy da aplicação ocorre o erro a baixo.
Importante falar que basta uma reinicialização do app server que o erro não ocorre novamente, e minha aplicação funciona até a necessidade de um novo deploy:

Alguém tem algum idéia do que pode estar causando isso?

Segue o erro:

GRAVE: Servlet.service() for servlet [default] in context with path [] threw exception
java.lang.IndexOutOfBoundsException: index (0) must be less than size (0)
        at com.google.common.base.Preconditions.checkElementIndex(Preconditions.java:301)
        at com.google.common.base.Preconditions.checkElementIndex(Preconditions.java:280)
        at com.google.common.collect.Iterables.get(Iterables.java:639)
        at br.com.caelum.vraptor.interceptor.Graph.findCycle(Graph.java:105)
        at br.com.caelum.vraptor.interceptor.Graph.cycle(Graph.java:101)
        at br.com.caelum.vraptor.interceptor.Graph.orderTopologically(Graph.java:73)
        at br.com.caelum.vraptor.interceptor.Graph.topologicalOrder(Graph.java:61)
        at br.com.caelum.vraptor.interceptor.TopologicalSortedInterceptorRegistry.all(TopologicalSortedInterceptorRegistry.java:37)
        at br.com.caelum.vraptor.core.EnhancedRequestExecution.execute(EnhancedRequestExecution.java:20)
        at br.com.caelum.vraptor.VRaptor$1.insideRequest(VRaptor.java:92)
        at br.com.caelum.vraptor.ioc.spring.SpringProvider.provideForRequest(SpringProvider.java:56)
        at br.com.caelum.vraptor.VRaptor.doFilter(VRaptor.java:89)
        at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:244)
        at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:210)
        at org.apache.catalina.core.StandardWrapperValve.invoke(StandardWrapperValve.java:240)
        at org.apache.catalina.core.StandardContextValve.invoke(StandardContextValve.java:161)
        at org.apache.catalina.core.StandardHostValve.invoke(StandardHostValve.java:164)
        at org.apache.catalina.valves.ErrorReportValve.invoke(ErrorReportValve.java:100)
        at org.apache.catalina.valves.AccessLogValve.invoke(AccessLogValve.java:541)
        at org.apache.catalina.core.StandardEngineValve.invoke(StandardEngineValve.java:118)
        at org.apache.catalina.connector.CoyoteAdapter.service(CoyoteAdapter.java:383)
        at org.apache.coyote.ajp.AjpProcessor.process(AjpProcessor.java:294)
        at org.apache.coyote.ajp.AjpProtocol$AjpConnectionHandler.process(AjpProtocol.java:183)
        at org.apache.coyote.ajp.AjpProtocol$AjpConnectionHandler.process(AjpProtocol.java:169)
        at org.apache.tomcat.util.net.JIoEndpoint$SocketProcessor.run(JIoEndpoint.java:288)
        at java.util.concurrent.ThreadPoolExecutor$Worker.runTask(ThreadPoolExecutor.java:886)
        at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:908)
        at java.lang.Thread.run(Thread.java:662)
16/04/2012 13:23:05 org.apache.catalina.core.StandardWrapperValve invoke
GRAVE: Servlet.service() for servlet [default] in context with path [] threw exception
java.lang.IndexOutOfBoundsException: index (0) must be less than size (0)
        at com.google.common.base.Preconditions.checkElementIndex(Preconditions.java:301)
        at com.google.common.base.Preconditions.checkElementIndex(Preconditions.java:280)
        at com.google.common.collect.Iterables.get(Iterables.java:639)
        at br.com.caelum.vraptor.interceptor.Graph.findCycle(Graph.java:105)
        at br.com.caelum.vraptor.interceptor.Graph.cycle(Graph.java:101)
        at br.com.caelum.vraptor.interceptor.Graph.orderTopologically(Graph.java:73)
        at br.com.caelum.vraptor.interceptor.Graph.topologicalOrder(Graph.java:61)
        at br.com.caelum.vraptor.interceptor.TopologicalSortedInterceptorRegistry.all(TopologicalSortedInterceptorRegistry.java:37)
        at br.com.caelum.vraptor.core.EnhancedRequestExecution.execute(EnhancedRequestExecution.java:20)
        at br.com.caelum.vraptor.VRaptor$1.insideRequest(VRaptor.java:92)
        at br.com.caelum.vraptor.ioc.spring.SpringProvider.provideForRequest(SpringProvider.java:56)
        at br.com.caelum.vraptor.VRaptor.doFilter(VRaptor.java:89)
        at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:244)
        at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:210)
        at org.apache.catalina.core.StandardWrapperValve.invoke(StandardWrapperValve.java:240)
        at org.apache.catalina.core.StandardContextValve.invoke(StandardContextValve.java:161)
        at org.apache.catalina.core.StandardHostValve.invoke(StandardHostValve.java:164)
        at org.apache.catalina.valves.ErrorReportValve.invoke(ErrorReportValve.java:100)
        at org.apache.catalina.valves.AccessLogValve.invoke(AccessLogValve.java:541)
        at org.apache.catalina.core.StandardEngineValve.invoke(StandardEngineValve.java:118)
        at org.apache.catalina.connector.CoyoteAdapter.service(CoyoteAdapter.java:383)
        at org.apache.coyote.ajp.AjpProcessor.process(AjpProcessor.java:294)
        at org.apache.coyote.ajp.AjpProtocol$AjpConnectionHandler.process(AjpProtocol.java:183)
        at org.apache.coyote.ajp.AjpProtocol$AjpConnectionHandler.process(AjpProtocol.java:169)
        at org.apache.tomcat.util.net.JIoEndpoint$SocketProcessor.run(JIoEndpoint.java:288)
        at java.util.concurrent.ThreadPoolExecutor$Worker.runTask(ThreadPoolExecutor.java:886)
        at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:908)
        at java.lang.Thread.run(Thread.java:662)

não existe @Before e @After… é @Intercepts(before=…, after=…)

vc colocou o before e o after corretamente? tem algum ciclo nessa ordem?

Tudo bom Lucas?

Sim, sim você está correto.
Anotei os Interceptors com @Intercepts(before=…) e @Intercepts(after=…).

O engano foi apenas por pressa na hora de escrever o post.

A resposta para suas duas perguntas é sim.
Como expliquei no post original: A lista de interceptors não formam um ciclo.

Agradeço pela atenção.

vc tá com a última versão do vraptor? a 3.4.1?

Estou trabalhando com duas versões, onde o problema ocorreu.
Tenho um projeto com a 3.4, onde o problema ocorre em aproximadamente 40% das implantações.

E tenho um projeto com a 3.2.1, onde o problema ocorreu em raríssimas vezes, mas já ocorreu.

Por acaso existe algo fazendo requisições para o servidor logo na hora que ele está inicializando?
Ou isso ocorre muito depois da inicialização?

Ou ainda, isso ocorre quando dá reload no contexto?

Devido ao nosso processo de implantação, não ocorre reload do projeto.
O processo é o seguinte:
1 - Retiramos o .war do Tomcat, para fazer o undeploy;
2 - Colocamos o novo .war;
3 - Esperamos o tomcat implantar;
4 - Reiniciamos o tomcat.

O erro ocorre nos passos 3 e 4 (no 4 é mais refrequente).
Sim, provavelmente o tomcat recebe requisições a esse contexto ainda quando ele está sendo carregado.
Mas o tomcat não encaminha essas requisições para o contexto antes dele estar totalmente carregado, correto?

Obrigado.

Quando acontece esse erro o sistema para de funcionar?

existe alguma requisição sendo feita internamente no sistema, na inicialização?

o erro acontece na lógica de ordenar os interceptors do vraptor, que é chamada no primeiro request.

Vc registra os interceptors manualmente em algum lugar, ou só via @Intercepts?

Quando acontece esse erro o sistema para de funcionar?
Sim, o problema ocorre na inicialização e quando ocorre o sistema não responde.

existe alguma requisição sendo feita internamente no sistema, na inicialização?
Não, não tem.

[b]o erro acontece na lógica de ordenar os interceptors do vraptor, que é chamada no primeiro request.

Vc registra os interceptors manualmente em algum lugar, ou só via @Intercepts?[/b]
Somente com a anotação @Intercepts.

vc tá com a conf de packages no web.xml apontando pra base-package da sua aplicação? se sim, tire.

Lucas, infelizmente agora você falou grego para mim.
O que é o conf de packages?

Mesmo assim, eu procurei pela palavra “package” no web.xml e não encontrei referência para essa palavra.

esse processo é pra aplicação não ficar indisponível?

não seria melhor:

-stop no tomcat
-substituir o war
-start no tomcat

?

é o que a gente geralmente faz.

Você está se referindo a isso?

<context-param>
    <param-name>br.com.caelum.vraptor.packages</param-name>
    <param-value>
        br.com.caelum.vraptor.util.one.package, 
        br.com.caelum.vraptor.util.other.package
    </param-value>
</context-param>

Se sim, a reposta é não. Não estou usando esse recurso, nem para registrar coisas nossas nem de terceiros.

Se fizermos esse processo:
-stop no tomcat
-substituir o war (sem apagar a pasta extraída
-start no tomcat

Sem apagar a pasta extraída, o Tomcat não irá implantar a nova versão do .war, pois ele tem a aplicação já extraída na pasta, e o Tomcat não saberá que o .war mudou.
Removemos o .war ainda com o Tomcat rodando para que ele realize o undeploy corretamente da aplicação antes de iniciarmos o deploy.

Você acredita que possa ser o processo de implantação? Por que estaria influenciando?

tente isso:

stop ==> ele vai fazer o undeploy corretamente
substitui o war e apaga o diretório
start

acho que é por causa dos redeploys mesmo… a gente não costuma usar isso em produção, pois acumula um monte de classes na memória.

sobre ele não reimplantar… se eu não me engano o tomcat faz o redeploy se vc substituir o war, mesmo que já esteja extraída a pasta. A menos que vc tenha um context apontando diretamente pra pasta e não pro war.

Obrigado Lucas, vou tentar isso e verificar se corrige o problema.
Mas acredito que não vai fazer diferença, pois como o Tomcat é reiniciado depois que o novo .war é implantado a mémoria é limpa.
Inclusive fazemos essa reiniciação para garantir que estamos sempre com a memória permanente da JVM sempre o mais limpa possível.

Quanto ao tomcat fazer o redeploy sem apagar a pasta tenho certeza: o tomcat não irá implantar o conteúdo do novo .war se você não apagar a pasta enquando ele tiver down, mesmo sem a configuração de context.

o restart que vc faz é como?

tenta fazer do jeito que vc faz normalmente, mas ao invés do restart, faça um shutdown até o final e um start.

não deveria dar o problema dos interceptors assim.

Hum…

Acho que pode ser isso.
De vez enquando, o pessoal da infraestrutura ao invés de fazer o shutdown, eles fazem um “killall -9 java”.

Acho que assim, pode ficar algum lixo para trás.

talvez seja por causa desse kill então :wink: