Estamos no desenvolvimento de um sistema WEB utilizando VRaptor + Hibernate.
Neste sistemas temos que gerar alguns relatorios ou arquivos txt, que demandam um certo tempo entre 10 a 40 minutos, dependendo da opção selecionada.
Para isto, estamos querendo fazer que esta tarefa trabalhe em forma de agendamento ou execução em segundo plano.
Exemplo: Usuário seleciona as informações e pede para gerar determinado relatorio. Esta solicitação lança uma requisição, que chamara a classe e metodo correspondete. e grava o mesmo numa pasta determinada na rede. Apos concluido gerá uma informação ao usuário que a solicitação foi concluida.
Qual seria a melhor forma de fazer isto utilizando-se VRaptor. Estamos em duvida como proceder. Seria o quartz?
Alguem poderia nos auxiliar. e dar um “norte” de como fazer, para que possamos seguir em frente.
Obrigado pela ajuda.
[RESOLVIDO] Executar tarefa segundo plano, sistema WEb + VRaptor: Quartz ou outra forma?
7 Respostas
o quartz é bom quando você precisa executar uma tarefa periódica… se for um trabalho para ser feito uma vez só você pode usar a própria API de concorrência do java com o ExercutorService + runnables
procura por ThreadPoolExecutor e as classes do mesmo pacote
o quartz é bom quando você precisa executar uma tarefa periódica… se for um trabalho para ser feito uma vez só você pode usar a própria API de concorrência do java com o ExercutorService + runnablesprocura por ThreadPoolExecutor e as classes do mesmo pacote
Lucas fiz assim no meu SpedController:
@Resource
public class SpedController {
private final GeradorSpedFiscal geradorSpedFiscal;
public SpedController(GeradorSpedFiscal geradorSpedFiscal) {
this.geradorSpedFiscal = geradorSpedFiscal;
}
public void gerar(){};
public void gerarSped(String sufixoCNPJ, String periodo) {
try {
this.geradorSpedFiscal.GerarSped("01/04/2011");
System.out.println("Teste");
} catch (FileNotFoundException e) {
e.printStackTrace();
}
}
}
meu metodo geradorSpedFiscal da Classe GeradorSpedFiscal é assim:
public void GerarSped(String dataInicial) throws FileNotFoundException {
this.periodo = CalculaPeriodo(dataInicial);
ThreadPoolExecutor tpe = new ThreadPoolExecutor(10, 10, 50000L, TimeUnit.MILLISECONDS,
new LinkedBlockingQueue<Runnable>());
tpe.execute(this);
}
e o run...
public void run() {
try {
this.executarSPED();
} catch (FileNotFoundException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
Ele até chama a execução em segundo plano… mais dentro do this.executarSPED() ele usa session e DAOS. dai ele chama. mas ele finaliza o controller. .dai da erro na execução que esta em segundo plano:
Exception in thread "pool-1-thread-1" org.hibernate.SessionException: Session is closed! at org.hibernate.impl.AbstractSessionImpl.errorIfClosed(AbstractSessionImpl.java:72) at org.hibernate.impl.SessionImpl.getActionQueue(SessionImpl.java:1948) at org.hibernate.engine.query.NativeSQLQueryPlan.coordinateSharedCacheCleanup(NativeSQLQueryPlan.java:179) at org.hibernate.engine.query.NativeSQLQueryPlan.performExecuteUpdate(NativeSQLQueryPlan.java:189) at org.hibernate.impl.SessionImpl.executeNativeUpdate(SessionImpl.java:1310) at org.hibernate.impl.SQLQueryImpl.executeUpdate(SQLQueryImpl.java:396) at br.com.diplomata.infra.daos.LivroFiscalDAO.fabricaTemporariaParaAsMensagensDoLivroFiscal(LivroFiscalDAO.java:274) at br.com.diplomata.infra.daos.LivroFiscalDAO.CriaTabelasTemporarias(LivroFiscalDAO.java:67) at br.com.diplomata.infra.daos.LivroFiscalDAO.selecionaLivroFiscal(LivroFiscalDAO.java:33) at br.com.diplomata.sped.fiscal.GeradorSpedFiscal.selecionaInformacoesLivroFiscalParaSped(GeradorSpedFiscal.java:118) at br.com.diplomata.sped.fiscal.GeradorSpedFiscal.executarSPED(GeradorSpedFiscal.java:77) at br.com.diplomata.sped.fiscal.GeradorSpedFiscal.run(GeradorSpedFiscal.java:130) at java.util.concurrent.ThreadPoolExecutor$Worker.runTask(Unknown Source) at java.util.concurrent.ThreadPoolExecutor$Worker.run(Unknown Source) at java.lang.Thread.run(Unknown Source)
Como fazer para que ele continue com a session do hibernate. só finalize depois que terminar o “Run()” chamado?
Obrigado
vc vai precisar gerenciar as Sessions separadamente pra esssas tasks, não pode usar a mesma da requisição, pois não está na mesma thread e pode ser executado em qqer ponto
Acabei fazendo o JobScheduler, conforme mostra no vraptor.com.br. Pois tambem teria algumas rotinas que são chamadas em determinados momentos.
Agora uma duvida, posso mostrar o meu Pool de Task, e quais estão sendo executadas.
Grande Lucas, acabei mudando e fazendo como havia iniciado com ThreadPoolExecutor… A duvida anterior para saber quanto tem no pool consegui. usando this.executorFactory.getInstance().getTaskCount().
Preciso fazer o seguinte: Mostrar a lista de tarefas que estão no Pool… tem como identifcar uma task e listar.
Exemplo:
SPED 01 - Exec
SPED 02 - Exec
SPED 03 - Wait
SPED 04 - Wait
Minhas Classes são:
FabricadaThreadPool
@Component
@ApplicationScoped
public class FabricaDePoolThreadExecutor implements ComponentFactory<ThreadPoolExecutor>{
private ThreadPoolExecutor pool;
@PostConstruct
public void abre() {
pool = new ThreadPoolExecutor(10, 10, 50000L, TimeUnit.MILLISECONDS,
new LinkedBlockingQueue<Runnable>());
}
public ThreadPoolExecutor getInstance() {
return pool;
}
@PreDestroy
public void destroy() {
pool.shutdown();
}
}
Interface Tarefa:
public interface Tarefa extends Runnable {
void execute(ThreadPoolExecutor poolExecutor);
}
@Component
@RequestScoped
public class TarefaGeradorDeSpedFiscal implements Tarefa {
private Session session;
private String data;
public void run() {
this.session = new CriadorDeSessionParaTarefas().getInstance();
GeradorSpedFiscal geradorSpedFiscal = new GeradorSpedFiscal(session,new EmpresaFilialDAO(session),new LivroFiscalDAO(session),new MovimentoGIADAO(session), new CIAPParaSPEDDAO(session));
try {
geradorSpedFiscal.GerarSped(this.data);
} catch (FileNotFoundException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
public void execute(ThreadPoolExecutor poolExecutor) {
poolExecutor.execute(this);
}
public TarefaGeradorDeSpedFiscal paraData(String data) {
this.data = data;
return this;
}
}
bom, vc pode sobrescrever o toString da task e imprimir a lista de tasks que não foram executadas assim (algum dos métodos do pool faz isso)
PS: coloque o código entre e
bom, vc pode sobrescrever o toString da task e imprimir a lista de tasks que não foram executadas assim (algum dos métodos do pool faz isso)PS: coloque o código entre
e
Valeu lucas, e pode deixar que as proximas vão entre e .