Objetivos
-
Compreender o conceito de clock e suas principais aplicações.
-
Entender quais são os principais processos periódicos padrão do produto.
-
Aprender a desenvolver um clock.
-
Entender como configurar e acompanhar a execução de um clock no Portal.
Referências complementares
-
Content
Conceito
Um clock é um processo executado periodicamente de acordo com um agendamento realizado. Tipicamente um clock é utilizado para atividades de manutenção sobre o Portal.
Existe um processo central, que é executado de acordo com uma periodicidade definida nas configurações do Portal (30 segundos, por default) que é o responsável por verificar o agendamento dos demais clocks e dispará-los se já estiver na hora de serem executados. Esse processo é o PortalClock. Ou seja, cada execução do PortalClock é uma “janela” para execução dos demais, caso já tenha passado o intervalo definido para cada um desde a última execução. Sempre que o PortalClock identifica que um determinado clock deve ser disparado ele cria uma thread para essa execução. Sendo assim, cada clock roda em uma thread separada de modo que a execução de um não interfira na execução de outro e nem na execução da thread principal do Portal.
Para exemplificar, imaginemos o cenário de termos apenas dois clocks agendados além do processo que os dispara, com as seguintes configurações:
Processo
|
Periodicidade
|
---|---|
PortalClock (dispara os demais) |
1 minuto |
Clock A |
2 minutos |
Clock B |
5 minutos |
0 1 2 3 4 5 6 7 8 9 10 11 12
|_____|_____|_____|_____|_____|_____|_____|_____|_____|_____|_____|_____|
A e B - A - A B A - A - A e B - A
Repare que no instante 0 (ou seja, a primeira execução do PortalClock) os dois clocks são executados pois ainda não haviam sido executados nenhuma vez antes. A partir daí começa a valer o intervalo definido e o clock A é executado a cada dois minutos enquanto o clock B a cada 5 minutos. No entanto, em várias janelas definidas nenhum clock é de fato chamado pelo PortalClock pois ainda não passou o tempo definido de intervalo desde a última execução.
O Lumis utiliza esse mecanismo para, através de alguns clocks padrão existentes no produto, executar tarefas de manutenção periódicas. Um exemplo disso é o ContentClock, responsável, entre outras coisas, por mudar o status de um conteúdo de não publicado para publicado quando atingirmos a data de publicação definida para esse conteúdo.
Além disso, é possível criar clocks customizados e configurá-los em serviços para que sejam executados com a periodicidade desejada. A seguir veremos como criar clocks customizados.
Clocks customizados
Criando a classe que representa o clock
Uma classe de clock deve necessariamente implementar a interface IServiceClock. Essa interface possui apenas dois métodos: getNextScheduleTime, utilizado para identificar a data e hora da próxima execução e doTick, onde deve ser implementada a tarefa periódica, chamado quando o PortalClock identifica que o clock deve ser executado.
Uma boa opção para a criação de um clock, ao invés de implementar diretamente a interface IServiceClock é estender a classe GenericServiceClock classe também implementa IServiceClock e já implementa o método getNextScheduleTime com a inteligência de calcular a próxima execução com base nas configurações realizadas sobre o clock. Essas configurações são representadas pelo objeto ClockConfig é passado como parâmetro para esse método quando ele é chamado.
Uma questão importante a respeito da execução dos clocks, é sobre o contexto em que isso ocorre. Como, durante a execução de um clock, não estamos em uma chamada HTTP e muito menos em um contexto de ciclo de vida de uma interface DOUI, não temos os objetos request e response e tampouco o objeto douiContext, de onde normalmente são extraídas as informações quando estamos tratando da renderização de uma interface.
No caso de clocks, todo o contexto disponível está no objeto ClockConfig, passado como parâmetro para o método doTick e se resume ao conjunto de configurações realizadas para o clock no serviço ao qual ele pertence.
Além desse conjunto de configurações o método doTick também recebe um objeto sessionConfig com uma sessão criada através de impersonificação para o usuário FrameworkClockUser. Esse é um usuário de sistema do Portal, que possui as permissões necessárias para execução de tarefas agendadas. Com esse objeto o clock pode chamar API’s que precisem de validação de acesso sem possuir uma sessão que seria criada a partir do login de algum usuário, já que no contexto de execução de um clock não temos usuário logado.
A seguir vemos um exemplo de implementação do método doTick em uma classe de clock que estende GenericServiceClock. Nesse exemplo o objetivo do clock é realizar o arquivamento de todos os conteúdos mais antigos do que um determinado período, por exemplo, 30 dias.
publicvoid doTick(SessionConfig sessionConfig, ClockConfig clockConfig) throws ServiceException, PortalException { // Utiliza objeto para logar o resultado do clock em um log específico ILogger logger = LoggerFactory.getServiceLogger("arquivamentoNoticias"); // Cria uma nova transação ITransaction transaction = PortalTransactionFactory.createTransaction(); try { // Inicializa a transação transaction.begin(); // Chama o método para realizar o arquivamento dos conteúdos antigos int numConteudosArquivados = arquivaConteudos(sessionConfig, transaction); // Registra o resultado da execução do clock no log logger.info("\n OK. " + numConteudosArquivados + " conteúdos arquivados.\n"); // Faz o commit da transação após o arquivamento dos conteúdos transaction.commit(); } catch (PortalException e) { // Desfaz as alterações em caso de erro transaction.rollback(); throwe; } finally { // Garante a finalização da transação criada transaction.dispose(); } }
Algumas observações são importantes sobre o exemplo acima. Em primeiro lugar, diferente de quando estamos no fluxo de renderização de uma interface DOUI e sempre temos em mãos uma transação que foi criada pelo próprio framework, em um clock a classe que implementa o clock é responsável por criar e finalizar a transação, quando ela for necessária. Nesse caso é fundamental que se tenha o cuidado de sempre realizar o dispose da transação dentro de um finally para garantir que ela será finalizada mesmo no caso de ocorrer alguma exceção.
Além disso, vemos que foi utilizado um logger;específico desse clock para indicar o resultado da limpeza a cada execução. A utilização de log em um clock é uma prática recomendada, pois facilita a validação do resultado da execução desse clock, e a análise de eventuais problemas.
Configurando um clock em um serviço
Um clock sempre pertence a um serviço. Assim, para que um clock seja registrado no Portal e passe a ser executado conforme o agendamento definido o serviço precisa ser registrado.
Para os casos em que o clock é genérico e não faz sentido configurá-lo em nenhum serviço previamente existente é possível criar um serviço apenas para o clock, não possuindo nenhuma interface. Nesse caso o ideal é marcar o serviço como não instanciável, utilizando o atributo isInstantiable="false"na tag service do arquivo servicedefinition.xml. Nesse caso, depois de registrado, o serviço não aparecerá na lista de serviços disponíveis para instanciar em um canal, mas o clock será executado conforme agendado.
A configuração de clocks em um serviço, inclusive a definição da classe que implementa o clock e as informações relativas a periodicidade, é realizada na tag clocks;dentro da tag service. Um serviço pode possuir diversos clocks configurados, basta representar cada um deles em uma tag clock;abaixo da tag clocks. A seguir vemos um exemplo de arquivo de definição de um serviço não instanciável que não possui interfaces, apenas um clock configurado para ser executado a cada seis horas.
<?xml version="1.0" encoding="UTF-8"?> <serviceDefinition xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="http://www.lumis.com.br/lumisportal/xsd/servicedefinition.xsd"> <service id="exemplo.clock" name="Exemplo de Clock" isInstantiable="false" type="lum_service"> <description>Exemplo para a configuração de clock</description> <clocks> <clock className="exemplo.clock.ClockExemplo" id="ClockExemplo"> <tickInterval type="hours">6</tickInterval> </clock> </clocks> </service> </serviceDefinition>
Na tag clock, são definidos através de atributos um id para o clock (o id “final” do clock para o Portal na verdade será o id do serviço + “.” + id do clock) e o nome da classe implementada para o clock, no atributo className.
As configurações de agendamento de execução, todas representadas por tags dentro da tag clock, são as seguintes:
-
tickInterval = Define o intervalo de tempo entre uma execução e outra. O atributo type define a unidade de tempo do valor especificado (as opções são “seconds”, “minutes”, “hours” e “days”).
-
maxRunTime = Define o período máximo de execução do clock. Passado esse tempo, no momento em que PortalClock for obter os clocks para a próxima execução, ele poderá novamente selecionar essa tarefa. Assim, mesmo que uma thread ainda esteja em execução, o PortalClock poderá disparar mais uma para a mesma atividade. É importante deixar claro que, mesmo que tenha se passado o tempo definido, a thread não é interrompida. A unidade de tempo nesse caso é segundos, e o valor default caso a tag não seja definida é 1800 (30 minutos).
-
startTime = Define o horário em que o clock deverá ser executado pela primeira vez. A partir daí as próximas execuções serão definidas pela periodicidade definida em tickInterval. O formato dessa configuração é HH:MM:SS.
No exemplo anterior, em que temos um processo que deve arquivar os conteúdos mais antigos do que 30 dias, gostaríamos que o processo fosse executado apenas uma vez por dia em um horário de baixo acesso, por exemplo às 03h da manhã. Além disso gostaríamos de definir um tempo limite de execução de 10 minutos. Nesse caso a configuração do clock ficaria da seguinte forma:
<clock className="exemplo.clock.ArquivamentoConteudosClock" id="arquivamentoClock"> <tickInterval type="hours">24</tickInterval> <maxRunTime>600</maxRunTime> <startTime>03:00:00</startTime> </clock>
Configurações globais
<portalClock> <enable>1</enable> <tickInterval>30&llt;/tickInterval> </portalClock>
Na tag enable o clock pode ser habilitado ou desabilitado (por padrão ele está habilitado). Caso ele esteja desabilitado, nenhum clock de nenhum serviço será chamado pelo PortalClock.
A periodicidade definida em tickInterval (em segundos), define o tempo entre uma execução e outra do PortalClock, ou seja, define o tempo entre uma janela e outra de execução para chamada a todos os clocks configurados no Portal. Sendo assim, não faz sentido que o intervalo de execução de nenhum clock do Portal seja menor do que a periodicidade aqui definida, já que esses clocks só terão a oportunidade de execução nas janelas definidas por essa periodicidade global.
Outra característica implícita do tempo aqui definido é que ele acaba sendo como uma margem de erro para o horário definido para execução de clocks. Por exemplo, se temos aqui definida uma periodicidade de 2 minutos, um clock agendado para executar às 03h da manhã poderá ser executado entre 03h00 e 03h02.
Clocks padrão do Portal
Todos os serviços do tipo lum_content do Portal, por default já vem com um clock configurado caso não sejam especificados clocks na sua definição de serviços. O clock em questão é o ContentClock, que tem o objetivo de tratar a publicação e expiração agendada de conteúdos.
O ContentClock verifica todos os conteúdos que não estejam publicados e que tenham tido uma data de publicação configurada. Caso já tenhamos atingido a data de publicação, ele modifica o status desses conteúdos para “publicado”. Da mesma forma, ele verifica os conteúdos que estejam publicados e possuam uma data de expiração. Caso já tenhamos chegado à data de expiração, ele altera o status dos conteúdos para “não publicado”. Além disso, esse clock também remove o a indicação de conteúdo em destaque para aqueles que tenham uma data de expiração de destaque e essa data tenha passado. Além disso, esse clock cuida para que sejam disparados os eventos necessários para notificar o Portal sobre essas alterações de status, de modo que sejam realizadas as tarefas de limpeza de cache necessárias para que as interfaces reflitam essas mudanças.
Assim como acontece para outras configurações dos serviços, o ContentClock é automaticamente aplicado para todos os serviços do tipo lum_content caso não seja especificada a tag clocks na definição do serviço. Caso essa tag seja definida para que seja configurado um clock específico do serviço, por exemplo, passa a valer a configuração que está no arquivo de definição. Nesse caso, se for desejável que o ContentClock esteja ativo para o serviço em questão ele também precisa ser definido explicitamente na lista de clocks do serviço. Uma alternativa a essa abordagem é já implementar o clock customizado estendendo da classe ContentClock e garantir que no método doTick toda implementação da super classe será chamada.
Alguns serviços padrão utilizam clocks específicos além dos diversos serviços que possuem o ContentClock. Esses clocks específicos estão brevemente descritos a seguir:
-
lumis.collaboration.chat.chatClock = Trata da abertura e fechamento de salas de chat com base nas datas e horas configuradas, além de marcar como inativos os usuários que não tiverem acessado as salas por um período maior do que o configurado para o timeout.
-
lumis.portal.cluster.multiserver.DeleteExpiredDurableMessagesClock = Realiza manutenção sobre mensagens expiradas entre os servidores em cluster do Portal.
-
lumis.portal.monitor.impl.MonitorConsolidationClock = Trata da consolidação dos dados coletados pelo monitor.
-
lumis.service.mailmarketing.mailMarketingClock = Realiza os envios agendados no serviço de Mail Marketing.
-
lumis.service.newsletter.newsletterClock = Realiza os envios agendados no serviço de Newsletter.
-
lumis.service.portalmanagement.authentication.SessionClock = Remove as sessões inativas no Portal.
-
lumis.service.portalmanagement.lock.LockClock = Remove os locks ativos que já tenham expirado.
-
lumis.service.portalmanagement.sendmail.SessionClock = Processa a fila de envio de emails.
Monitoramento da execução de clocks
Na área administrativa do Portal, dentro de Módulos -> Tarefas Agendadas, é possível administrar todos os clocks que temos configurados para execução. Abaixo uma representação da interface Gerenciador de Tarefas Agendadas:

Nessa interface é possível habilitar e desabilitar a execução dos clocks de forma pontual, além de reiniciar o estado de execução de um clock marcando-o como não executando, através do botão Resetar.
É importante ressaltar que a ação de resetar uma tarefa não interrompe a execução da thread, caso ela esteja em andamento. Assim, essa ação pode ocasionar situações imprevistas. Por exemplo no caso de um thread estar em execução, a ação de resetar pode fazer com que outra thread seja disparada e tenhamos duas execuções simultâneas. O ideal é que esse botão seja utilizado apenas para limpar o estado de execução de tarefas nos casos em que se tenha certeza de que a thread não está mais em execução, por exemplo após um reinício forçado do servidor.
As informações existentes nessa interface para cada clock configurado são as seguintes:
-
Executando = Indica se o clock está em execução nesse exato momento.
-
Habilitado (intervalo) = Indica se o clock está habilitado e o intervalo configurado entre execuções.
-
Última Execução = Indica a data e hora da última execução registrada para esse clock.
-
Próxima Execução = Indica a data e hora da próxima execução, calculadas tendo como base a última execução registrada e o intervalo definido.
-
Duração Máxima = Indica o tempo máximo de execução configurado para o clock.
Existe uma particularidade na exibição do campo “Última Execução”. Além da data, esse campo exibe a hora de início da última execução seguida da hora de término da última execução, no formato HH:MM:SS – HH:MM:SS. A exceção é no caso da execução ter ocorrido toda dentro de um mesmo segundo. Nesse caso, para simplificar a visualização, é exibido apenas um horário, também no formato HH:MM:SS.
A partir das informações disponíveis no Gerenciador de Tarefas Agendadas é possível realizar análises sobre problemas na execução de clocks, como por exemplo confirmar se um determinado clock está sendo executado ou saber se sua última execução foi no momento em que se esperaria que fosse.
Autor: Sergio Fernandes