JobMonitor: mudanças entre as edições

De BIS Wiki
Ir para navegação Ir para pesquisar
Sem resumo de edição
Sem resumo de edição
Linha 91: Linha 91:


Caso esse método não seja chamado, no momento em que este documento é escrito, o JobMonitor tem um tempo limite de 6h para manter o Job em memória desde o momento em que a instância do Job é criado. Quando o job é removido de forma forçada, um logImprovement() é chamado com o título do Job.
Caso esse método não seja chamado, no momento em que este documento é escrito, o JobMonitor tem um tempo limite de 6h para manter o Job em memória desde o momento em que a instância do Job é criado. Quando o job é removido de forma forçada, um logImprovement() é chamado com o título do Job.
= Job & SessionManager =
Ao criar um novo objeto Job, ele mesmo tenta detectar se estamos em um ambiente com uma Session associada a Thread atual. Se encontrar ele automaticamente transfere a sessão de autenticação atual para a nova Thread do Job. A vantagem dessa operação é que o método '''SessionManager.getSession()''' passará a funcionar dentro do método run() do Job, bem como permitirá que outros serviços como [[FWLogger]] encontre a sessão do usuário.
{{stop|Transferir Session não Mantém a Transação CMT|Note que o SessionVO passa a fazer parte da nova Thread, mas caso a Thread principal retorne e "volte a fachada de acesso" o container que controla a transação CMT fechará a transação dando commit(). Ou seja, mesmo que o Job tenha acesso ao SessionVO, não indica que ele poderá executar acessos à banco de dados ou outros serviços que dependem de uma Transaction. Esses tipos de chamadas precisam que o Job faça outra chamada através da fachada, mas podem obter o UUID ou Token da sessão recebida para realizar nova autenticação na fachada.}}

Edição das 19h54min de 16 de outubro de 2020

O JobMonitor é o serviço do BISFW que permite que tarefas sejam executar em uma Thread paralela para que a thread principal não fique bloqueada esperando. Esse recurso é extremamente útil para tarefas demoradas, uma vez que permite retornar status sobre a execução da tarefa enquanto ela acontece, mesmo que seja pela interface WEB.

Criando o Job em Segundo Plano

Para colocar uma tarefa em background basta implementar a classe Job e iniciar a execução dentro do método runJob().

Exemplo Tarefa em Execução em Background
Job job = new Job("Título da Tarefa") { //O título da tarefa é colocado no título da thread, o que ajuda no DEV.
  @Override
  public Object runJob(Job job, JobStatus jobStatus) throws Throwable {
    //Código para execução da tarefa...
  }

  @Override
  public void jobFinished(Job job, JobStatus jobStatus) {
    // Quando a tarefa é finalizada, o serviço JobMonitor chama este método para notificar
  }
};
job.start(); //inicia a tarefa

Quando a tarefa finalizar o JobMonitor chama o método jobFinished() para notificar o fim da execução da tarefa. Embora não faça muito sentido quando implementado como no modelo acima (em innerclasses) o método jobFinished() tem maior utilidade para implementações mais genéricas da interface.

Ambos os métodos recebem dois parâmetros:

  • job - referência da própria instância do Job criado.
  • jobStatus - Instância do objeto de status do job. Dentro desse objeto a tarefa deve atualizar as propriedades como "mensagens", percentual de tarefa realizada, etc..
JobStatus é passado por referência
Note que este objeto é passado como referência de memória, isto é, ele não precisa ser retornado o conteúdo interno dele é "atualizado" automaticamente para todos que tiverem a mesma referência. O objeto JobStatus é um objeto final dentro da classe Job.

Este objeto é tanto o que é passado para dentro dos métodos, quanto para o métodos que solicitam informação sobre o andamento do Job.

Deve-se tomar cuidado quando esse objeto for enviado para outras partes do sistema, como por exemplo atravessar uma fachada, ou qualquer outra situação em que o objeto é clonado e não mais usada a mesma instância da memória. Nestes casos alterações no novo objeto não refletirão no objeto original.


JobMonitor

O JobMonitor é uma classe estática que controla e mantém todos os Jobs do Sistema. Ao criar uma instância de Job ele automaticamente se registra no JobMonitor. Mesmo antes de iniciar a tarefa o JobMonitor já tem a referência da classe e monitora seu status.

Quando o Job é criado, ela cria também sua classe JobStatus, e dentro dela é possível encontrar seu identificador único (UUID). Com este UUID é possível solicitar informações do Job no JobMonitor. Assim, caso o JobMonitor esteja sendo executado em uma VM e o objeto que queira saber o status esteja em outra, ele pode solicitar o objeto JobStatus utilizando dessa UUID. Exemplo:

Exemplo Tarefa em Execução em Background
//Implementação do Job
Job job = new Job("Título da Tarefa") { ... }; 

//Recuepra o objeto que mantém o status de progresso diretamente da tarefa
JobStatus status = job.getStatus();

//Obtemos e salvamos para referência futura o UUID do Job
String uuid = status.getUuid();

//Obtendo o JobStatus a partir do JobMonitor com o UUID do job.
JobStatus status2 = JobMonitor.getJobStatus(uuid);

Note que no exemplo acima o start() do job pode ser dado a qualquer momento. O job não precisa estar sendo executado para que todo o restante funcione. Porém normalmete o job já é inicializado assim que que a instância é criada.

Retorno do UUID
Normalmente os métodos que executam um trabalho pesado já são implementados dentro do JobMonitor e o real retorno do método só ocorre quando o job termina.

Por isso o método chamado para iniciar o job em geral retorna o UUID da tarefa. O retorno real do método quando existir é retornado dentro do objeto JobStatus, bem como a exceção caso exista (melhor explicado a seguir).

JobChecker

JobChecker é a implementação de uma Thread que verifica periodicamente a tarefa sem segundo plano e notifica conforme atualização do objeto de status.

Para criar o JobChecker basta passar o UUID do job na sua construção:

JobChecker verificando o progresso da tarefa
JobChecker jobChecker = new JobChecker(uuid, true) {
  @Override
  public void updateStatus(JobStatus jobStatus) {
    // Código para lêr o conteúdo do JobStatus e atualizar qualquer sistema

    // Abaixo um código exemplo para atualizar o conteúdo da tela do Vaadin. É necessário obter a UI do usuário e criar uma classe de acesso primeiro
    ui.access(new Runnable() {
      @Override
      public void run() {
        // Código do Vaadin para atualizar a UI do usuário
      }
    });
  }
};

Note que no construtor foi passado além da UUID um booleano 'true'. Esse boleano indica se quando o JobChecker detectar que a tarefa finalizou ele mesmo se encarrega de avisar o JobMonitor que ele pode descartar a tarefa e seu status.

Isso é importante porque mesmo que o Job termine, o JobMonitor não sabe até quando deve guardar a referência do JobStatus para ser consultado, assim é importante que o descarte seja autorizado para economizar recursos.

Para forçar esse descarte manualmente, caso não se use o JobChecker ou se passe o atributo como false, deve ser chamado o método:

JobMonitor.cleanJob(uuid);

Caso esse método não seja chamado, no momento em que este documento é escrito, o JobMonitor tem um tempo limite de 6h para manter o Job em memória desde o momento em que a instância do Job é criado. Quando o job é removido de forma forçada, um logImprovement() é chamado com o título do Job.


Job & SessionManager

Ao criar um novo objeto Job, ele mesmo tenta detectar se estamos em um ambiente com uma Session associada a Thread atual. Se encontrar ele automaticamente transfere a sessão de autenticação atual para a nova Thread do Job. A vantagem dessa operação é que o método SessionManager.getSession() passará a funcionar dentro do método run() do Job, bem como permitirá que outros serviços como FWLogger encontre a sessão do usuário.

Transferir Session não Mantém a Transação CMT
Note que o SessionVO passa a fazer parte da nova Thread, mas caso a Thread principal retorne e "volte a fachada de acesso" o container que controla a transação CMT fechará a transação dando commit(). Ou seja, mesmo que o Job tenha acesso ao SessionVO, não indica que ele poderá executar acessos à banco de dados ou outros serviços que dependem de uma Transaction. Esses tipos de chamadas precisam que o Job faça outra chamada através da fachada, mas podem obter o UUID ou Token da sessão recebida para realizar nova autenticação na fachada.