Evite o timer expunging no glassfish

Eu tenho um método anotado com @Schedule que é chamado pelo contêiner de vez em quando.

@Schedule(second = "*/5", minute = "*", hour = "*", persistent = false) public void myTimerMethod() throws Exception { ... } 

O problema está em certas condições que eu quero para este método lançar uma exceção para causar a transação em andamento para reverter. Mas se eu fizer isso mais de duas vezes, o timer será apagado e não será chamado mais!

 INFO: EJB5119:Expunging timer ['68@@1359143163781@@server@@domain1' 'TimedObject = MyBean' 'Application = My-War' 'BEING_DELIVERED' 'PERIODIC' 'Container ID = 89072805830524936' 'Fri Jan 25 21:49:30 CET 2013' '0' '*/5 # * # * # * # * # * # * # null # null # null # true # myTimerMethod # 0' ] after [2] failed deliveries 

Eu sei que posso configurar o reagendamento do timer em domain.xml usando

  ...   ...      ...   ...  

Mas a minha pergunta é, posso ter essa configuração configurada quando implantar meu aplicativo?

Não é possível encontrar em:

 glassfish-resources.xml glassfish-ejb-jar.xml glassfish-web.xml 

Existe alguma maneira de fazer isso programaticamente, talvez?

(Meu raciocínio por trás de colocar a configuração do servidor como esta nos arquivos de configuração em vez de configurar o servidor é para que meu aplicativo seja possível instalar diretamente em uma nova instalação do glassfish)

Eu usaria uma abordagem diferente.

Em vez de lançar uma exceção diretamente do método planejado, tente introduzir um nível de indireto como em:

 ... @Inject RealWorkHere realImplementation; @Schedule(second = "*/5", minute = "*", hour = "*", persistent = false) public void myTimerMethod(){ try{ realImplementation.myTimerMethodImpl() }catch (Exception x){ // hopefully log it somewhere } } ... 

onde RealWorkHere é o bean com a implementação real como em:

 @Stateless public class RealWorkHere{ @TransactionAttribute(REQUIRES_NEW) public void myTimerMethod() throws Exception { } } 

Isso vem com o benefício de:

  • Não lançar uma exceção em uma transação iniciada por contêiner (evitando assim o expunging)
  • Melhor registro da exceção
  • Demarcação clara da transação comercial ‘real’

Veja também

  • ejb-spec # 111: Por favor, limpe o comportamento de um contêiner se uma exceção de aplicativo for lançada durante a execução de um método de retorno de chamada temporizado

O Glassfish atual até a versão 4 expurga um cronômetro se, durante a execução do método de retorno de chamada de tempo limite, ocorrer uma exceção de aplicativo .

A exceção do aplicativo causa uma reversão da transação atual. Nessa situação, o Glassfish tenta novamente a execução livre de erros do método de retorno de chamada de tempo limite. Se ocorrer novamente uma reversão, o Glassfish expurgará o cronômetro.

Eu arquivei um problema no rastreador de problemas do Glassfish para não eliminar o cronômetro em caso de uma exceção. Glassfish parece ser o único servidor de aplicativos que expurga um timer no caso de uma exceção de aplicativo. Veja glassfish # 20749: Glassfish expurga o cronômetro mesmo se o método de callback mantém seu contrato para mais detalhes. Você gostaria de votar no meu problema.

Também arquivei um problema na especificação EJB para esclarecer como o contêiner EJB deveria se comportar em tais situações. Veja ejb-spec # 111: Por favor, desmarque o comportamento de um contêiner se uma exceção de aplicação for lançada durante a execução de um método de retorno de chamada do timer para mais detalhes.