Apache Camel e Twitter: Orquestrando mensagens

Se tem uma ferramenta que facilita a vida do desenvolvedor no âmbito da integração a ponto de libertá-lo de preocupações triviais como implementação/controle de interfaces, APIs, transações e tantos outros requisitos de tecnologia para focar quase que exclusivamente na regra de negócio, essa "utopia" é o Apache Camel por meio de EIPs (Enterprise Integration Patterns). Como muito bem foi explicado no site oficial, resumindo é um modelo genérico para implementação independente de tecnologia para qualquer tipo de situação, literalmente.

Para termos noção do poder bélico desse troço, criei algumas estórias a fim de termos alguns cenários de integração. Eis as issues criadas a partir das demandas da empresa fictícia Estaminosflaw:
  1. Monitorar uma hashtag na rede social Twitter e salvar em nosso banco de dados as postagens dos usuários junto com seus dados na tabela TwitterMessage. Por questões de limitação do storage, quando a tabela tiver mais que 15 de registros, a solução deverá salvar cada registro em uma fila JMS no formato JSON e então truncá-la, assim liberando mais espaço para novos registros.
  2. Consumir a fila JMS e salvar cada mensagem JSON como um arquivo no diretório C:\tmp porém seguindo a nomenclatura: {twitter-username}{yyyyMMdd-hhmmss}.json.
Você que está acostumado com desenvolvimento com certeza tem noção de como isso pode ser trabalhoso, principalmente quando não se tem um projeto sketch com lessons learned de implementações anteriores. Bom, antes de começarmos é mandatório sempre questionarmos:
  • Existe algum componente pronto que posso usar? Tem componente de integração para o Slack, XMPP, AWS-EC2 e vários outros.
  • Quais formatos de dados irei trabalhar? Vou precisar serializar/deserializar? A página data format do Apache Camel contém uma lista dos suportados e é possível customizar se for necessário.
Em função dos nossos requisitos, vamos precisar dos seguintes componentes:
  • Twitter para leitura cíclica da hashtag.
  • JPA a fim de persistir as postagens oriundas do Twitter.
  • Scheduler para criarmos uma verificação cíclica na tabela TwitterMessage e fazer uso do componente JPA para truncar a tabela, mas antes enviando cada registro para a fila JMS por meio de outro componente (logo abaixo).
  • Jackson para serializarmos/deserializarmos em JSON.
  • ActiveMQ que permitirá o Apache Camel conectar no broker em uma fila específica, enviar mensagens JMS e posteriormente consumi-las para então salvar em um diretório no servidor usando o componente abaixo.
  • File para por fim salvar a mensagem consumida da fila JMS como arquivo.
Como nosso broker é o ActiveMQ, vamos baixá-lo na página oficial e rodá-lo localmente executando o seguinte comando no terminal:
  • %ACTIVEMQ-HOME-FOLDER%\bin>activemq start
Quando terminar o processo de startup acesse o endereço localhost:8161/admin e se autentique com o clássico admin/admin. No menu superior acesse a opção Queue e crie uma fila com o nome Tweets.Trends, conforme definimos na primeira issue. Isso é tudo que precisamos fazer no broker. No final vai ficar assim:


OK, agora precisamos do projeto e já o deixei mais ou menos engatilhado. Ele pode ser baixado aqui. Para trabalharmos com o Twitter vamos precisar de uma conta devidamente habilitada para ser consumida por um App. Em 2015 fiz uma postagem detalhando o processo, acredito que não mudou. É necessário configurar nosso application.properties para a conexão funcionar.

Por questões de design e até de entendimento do que foi implementado, eu separei em 4 rotas, porém poderia ter mais ou até menos. Como não existe um design pattern disso (até onde eu sei), acabei optando assim. Eis a primeira rota:

  • Na rota temos um consumer (from) que utiliza o componente do Twitter para consultas cíclicas de 5s da hastag #SP1 (no final da postagem explico o porquê disso). Após o log, temos um processor que traduz a resposta (body) do Twitter para uma instância da entity TwitterMessage. Em seguida persistimos a mensagem e o Camel coloca no log qual o ID que representa o novo registro.
A segunda é mais simples:

  • A rota 2 faz apenas a análise condicional, encaminhando ou não para a rota 3. Poderia ter usado o Quartz que da muita mais liberdade e permite uma série de coisas, mas pela simplicidade optei pelo Scheduler para criar a CRON. Kiss principle, sempre!
A terceira já atua direto no broker:

  • A rota 3, em função de uma condicional, envia os registros recebidos da rota 2 para a fila JMS Tweets.Trends e então os exclui da tabela TwitterMessage. Repare que não precisei consultar o banco pois a mensagem foi direcionada para minha rota por meio da URI direct:informMyQueue, outra coisa é a serialização em JSON com Jackson e a conversão para String para justamente forçar o uso do TextMessage, assim é possível consultar diretamente no portal do ActiveMQ o payload da mensagem.
Por fim a quarta rota:

  • A rota 4 responde justamente a issue 2 da Estaminosflaw. Ela consome as mensagens da fila JMS do ActiveMQ e salva em um diretório qualquer o conteúdo seguindo a convenção do nome que foi definida. Fiz uma brincadeira com marshal/unmarshal para usar Simple Expression Language na definição do nome.
Veja o quanto que fizemos com poucas linhas de código. Lógico, tem uma série de coisas que não implementei e nem expliquei pois já está bem documentado na página do projeto. No meu caso, além da documentação da página do projeto, estudei pelos livros:
Uma opinião honesta? Sugiro apenas o segundo e o último livro, são excelentes! Aliás, o projeto suporta rodar tanto standalone como embedded em um container tipo Tomcat, acabei adaptando assim para rodá-lo no mesmo contexto do Hawtio para ele próprio desenhar os diagramas das rotas do projeto. Olha que legal:


Durante a explicação da primeira rota disse que explicaria o porquê que usei a hashtag #SP1. A ideia é usar o mesmo projeto para fazer algo parecido com os telões interativos do SPTV usando o componente websocket. Fica para a próxima postagem!


Parte de testing com mock, transação no broker para leitura de mensagens de fila e outras coisas serão postadas também. Aguarde!

Ao som de Silverhawks.

Comentários