PJe 2.1
Conteúdo |
Arquitetura PJe 2.1
Motivação
Alguns problemas começaram a ser notados mesmo na nova arquitetura proposta e implementada pelo CNJ. A modularização buscada até então não estava servindo de baseline para escalar o processo de desenvolvimento, de modo a desidratar o PJe 1.x e ao mesmo passo hidratar o PJe em seus módulos negociais.
As fachadas REST estavam começando a se tornar grandes controllers e repetiam muitas vezes códigos que estavam na controller da camada de visão angular. Verificou-se grande acoplamento entre o angular e sua fachada REST. Outro problema era a dificuldade em delimitar o escopo dos módulos negociais, desta maneira era difícil se identificar onde cada funcionalidade migrada do PJe 1 se encaixaria no PJe 2.
Tecnologias elencadas para o desenvolvimento da nova versão não permitiam uma escalabilidade horizontal, de modo que continuava sendo um monolito, não permitindo uma racionalização mais adequada dos recurso de infraestrutura. Os tribunais, por exemplo, continuariam tendo que fazer deploy de todo o monolito em uma mesma configuração de infraestrutura.
Outro fator problemático da primeira implementação do PJe 2 estava na burocracia de comunicação entre o PJe 1 e o PJe 2. Havia um excesso de lookups entre os serviços para resolver questões de autorização. Haviam ainda serviços do PJe 2 que consultavam serviços do PJe 1 em suas camadas DAO, isso tudo tornava a interação entre as versões algo muito complexo e passível de erros de difícil identificação.
A camada angular estava obrigada a ser disponibilizada no mesmo deploy do PJe 2, o que, mais uma vez representava uma limitação na racionalização dos recursos de infra.
Uma nova proposta arquitetural
Tendo sentido na pele todos estes problemas, a equipe do CNJ começou uma grande discussão interna sobre os avanços e dificuldades que o PJe 2 nos trazia numa perspectiva de futuro. Apesar dos problemas citados a nova arquitetura também nos trouxe boas perspectivas a respeito da abordagem ao problema. Algo notório é que sim, é possível migrar aos poucos os recursos do PJe 1 para uma nova arquitetura mais enxuta e com novas tecnologias. É indiscutível que o PJe precisa se renovar para abarcar o volume de processos e usuários que o sistema se propõe a atender, assim como não se discute que as tecnologias utilizada na versão 1 não darão conta por muito mais tempo da demanda que nosso sistema recebe diariamente.
A arquitetura modular monolítica proposta inicialmente resolvia alguns problemas, mas ainda era permissiva com erros do passado. Os módulos não tinham escopos negociais bem definidos, o que permitiria que desenvolvedores acabassem por fugir ao escopo sempre que se vissem em alguma dificuldade para resolução de um problema. Esse tipo de abordagem ao código é o fator causador de diversos problemas enfrentados no PJe 1, as classes não possuem escopos bem definidos e portanto não é difícil notar, por exemplo, métodos de escopo do processo que fazem alterações a outras entidades do sistema, que nada têm a ver com aquele contexto negocial.
Todo esse panorama nos direcionou a estratégia de desenvolvimento de um sistema baseado em micro serviços. Um sistema modular, mas não monolítico. A ideia é que cada escopo negocial bem definido seja envolto em um micro serviço. Por exemplo, poderíamos extrair toda a lógica negocial de audiências do PJe 1 e criar um serviço totalmente separado, com projeto separado, deploy separado e banco de dados separado. Esse serviço seria implementado e o PJe 1 se tornaria um cliente desse serviço para realizar atividades, como, marcar uma audiência, consultar audiências e etc.
Este tipo de abordagem permite que a implementação esteja focada naquele contexto negocial, facilitando o trabalho das equipes de negócio, desenvolvimento e testes. Outro benefício está na racionalização dos recursos tecnológicos, permitido ao tribunal que reserve para o serviço somente a quantidade adequada de recursos computacionais para que o serviço se comporte de maneira saudável.
O PJe passa, portanto a se comportar como um sistema mais moderno, dono de uma API REST composta por sua nuvem de serviços. Serviços estes que poderão ser disponibilizados para o público externo que deseje consumir os serviços através de aplicações mobile ou outros tipos de aplicações.
A interação entre os serviços
Cada contexto negocial terá portanto seu micro serviço, mas como estes serviços se comunicaram entre si? Muitas vezes o serviço de sessão de julgamento produzirá uma informação dizendo que o processo foi julgado, e neste momento o serviço de processo judicial deverá lançar uma movimentação.
Este tipo de interação irá funcionar como uma coreografia, onde cada serviço sabe exatamente o que fazer conforme as informações surgem em seu ecossistema. As informações serão passadas aos serviços através de um serviço de filas de mensagens, sempre que um processo for julgado o sistema de sessão irá enviar ao serviço de fila uma mensagem com informações referentes aquele julgamento. Neste momento um serviço será responsável por consumir a fila e redirecionar as mensagens a outros serviços através de uma estratégia baseada no conceito de webhooks. Um ou vários serviços estarão inscritos para receberem as mensagens para um dado evento, o serviço de webhooks será responsável por inscrever os serviços e direcionar as mensagens. Quando o serviço de processo receber a mensagem via webhook ele deverá saber que é necessário lançar uma movimentação no processo, após isso ele também deverá notificar ao serviço de mensagem que uma nova movimentação foi lançada, de modo que os serviços que se interessam por movimentações ajam como devem agir.
É importante que todo esse ecossistema funcione como uma nuvem de serviços, de modo que seja possível que o tribunal crie, por exemplo duas instâncias do serviço de consulta processual, ou até mais caso a demanda deste serviço cresça. Para isso é necessário um mecanismo de descoberta de serviços. Cada vez que iniciamos um serviço ele deve se registrar como um serviço ativo, esperando requisições de clientes. Este tipo de mecanismo funciona como um DNS e permite distribuir as requisições de maneira mais racional utilizando, por exemplo, um algoritmo round robin.
Um cliente para o PJe
Todos esse serviços precisam ser disponibilizados para o usuário, e para isso não usaremos mais o AngularJS, e sim o Angular que está em sua versão 4. A decisão de partir para a nova versão do Angular se motiva pelas grandes melhorias implementadas na versão, pela flexibilidade do TypeScript, pela rápida adoção da comunidade e pela baixa quantidade de código legado em angularJS no PJe 2.
O novo cliente angular estará totalmente separado e desacoplado dos serviços. Ele deverá se comportar como um cliente externo qualquer do sistema, utilizando-se da API de serviços do PJe.
Enquanto convive com o PJe 1, o nosso cliente Angular irá residir em um singelo iframe e talvez necessite se comunicar com a tela do PJe 1, como estarão em domínios separados a interação será efetivada através de mensagens entre janelas.
A nova versão do angular é baseada em componentes, o que nos permitirá criar um arcabouço de componentes que visem facilitar a implementação padronizada das telas do PJe, tendo como base a acessibilidade e experiência do usuário.
Como tudo se conecta
Descrevendo o diagrama acima temos o Angular 2+ como porta de entrada, cliente onde o usuário terá acesso aos vários serviços do PJe. O cliente angular irá acessar a API REST através de um serviço de borda, denominado “Gateway”. O Gateway nada mais é do que um serviço dentro da nossa nuvem de serviços, este conhece todos os outros e servirá de encaminhador das requisições do cliente.
Cada serviço, ao ser iniciado, se registra no “Discovery” informando que está disponível para aceitar as requisições. O Discovery também se encarrega de realizar load balancing entre os serviços registrados, desta maneira, se temos três instâncias de Processo, nosse serviço Discovery irá distribuir as requisições, de modo a não carregar uma mais que as outras.
O serviço OAuth2 se encarrega de controlar o acesso de usuários e serviços aos serviços da nuvem, sendo possível restringir o acesso a determinados serviços de acordo com as credenciais do usuário ou sistema.
Podemos perceber que cada micro serviço terá um contexto bem definido, inclusive sendo dono de seu próprio banco de dados, o qual poderá utilizar da tecnologia mais adequada para atender a proposta daquele serviço. Portanto não será mandatório que se use sempre um banco de dados relacional, por exemplo.
Os serviços irão ainda lançar seus logs para uma pilha ELK (Elastic, Logstash e Kibana). Os logs deverão observar não somente questões relacionadas a erros, mas também a sucesso das operações. Deste modo será possível avaliar a saúde dos serviços, se estão respondendo rápido, ou se estão muito lentos e com erros e precisam, portanto, de uma refatoração ou melhoria.
Como mencionado antes, os serviços funcionaram em modo de coreografia, onde cada serviço sabe bem o que fazer de acordo com o que acontece na nuvem. O RabbitMQ é um Message Broker que se responsabilizará por enfileirar as mensagens. Estas serão consumidas pelo serviço de webhooks que se encarregará de distribuir para os diversos serviços de nossa nuvem.
Sim, aquilo ali no topo é o PJe 1. Entenda o PJe 1 como um serviço também. Temos um serviço monolítico com muitas coisas que ainda não sabemos separar, portanto, inicialmente a versão legada servirá como um serviço sim, compondo a nova nuvem de serviços do PJe. A ideia é que a cada serviço “novo” criado o PJe legado se tornará um pouco menor. É importante dizer ainda, que o legado deverá se comportar como os outros serviços, escutando as filas do RabbitMQ, mandando mensagens para o RabbitMQ e autenticado através do serviço de autorização.
Estruturando um módulo/microserviço
Cada módulo, ou micro serviço, terá seu próprio domínio. Cada um deverá ser responsável por resolver um problema. A construção de módulo será iniciada pela equipe de negócio, que definirá um contexto bem definido para aquele pretenso serviço. Os requisitos negociais serão elicitados e a partir daí a equipe técnica começa a atuar.
A primeira tarefa da equipe técnica é definir a fachada REST, que irá prover as funcionalidades a serem acessadas pela camada de visão ou por outros módulos do PJe, ou ainda por outros sistemas externos.
Definidas as funcionalidades daquele novo serviço a equipe inicia a implementação do backend. Perceba que neste momento é possível que haja paralelismo entre a equipe que desenvolve o backend e a equipe que irá desenvolver o frontend. Inclusive é encorajador que se adote uma abordagem paralela. Equipes distintas trabalhando para frontend e backend evitarão acoplagem do serviço ao frontend, resultando em um serviço mais puros e enxutos que pode ser utilizado por outros sistemas, inclusive.
A dimensão de cada serviço pode ser variável. É importante que não sejam muito grandes nem muito pequenos. Um universo de muitos serviços pequenos pode tornar a coreografia dos serviços algo muito complexo de se manter, cada pequena alteração pode impactar em uma grande necessidade de reimplementação nos demais serviços. Os serviços também não devem ser grandes demais, um serviço muito grande representa algo que está tratando muitos problemas e acaba por se tornar um novo monolito.
O tamanho de um serviço é ideal quando, caso queiramos implementar todo o serviço, o tempo de codificação não passe de duas semanas. Certamente isso não é uma regra, mas uma notação a ser levada em consideração ao implementar novos serviços.
Cada micro serviço terá arquitetura simples, de modo a atender o seu contexto negocial. Dada a complexidade majorada de um determinada serviço, este pode ter um leve alteração arquitetural para atender a seu contexto. A abordagem de micro serviços permite um ambiente totalmente agnóstico de ponta a ponta, entretanto ter cada pedaço com uma tecnologia diferente torna a manutenção do sistema muito dependente de pessoas ou equipes específicas.
Tecnologias utilizadas
Integração PJE-LEGACY e a arquitetura 2.1
Registrando o PJe no Eureka
Embarcando o cliente Angular no PJe
Cofigurando o cliente Angular
Montando ambiente PJe 2.1
Ferramentas
- Eclipse Java EE (Versão mais atual) + JbossTools (Somente JbossAS)
- Eclipse STS (Spring Tool Suite)
- Visual Studio Code ou semelhante (Opcional)
- Java JDK 8 ou OpenJDK 8
- Git
- Wildfly (9 ou 10) ou JbossEAP7 (Ambos com o Mojarra 1.2)
Projetos necessários
- pje (http://git.cnj.jus.br/pje/pje)
- pje2-discovery-service (http://git.cnj.jus.br/pje2/pje2-infraestrutura/pje2-discovery-service)
- pje2-web (http://git.cnj.jus.br/pje2/pje2-clientes/pje2-web)
Clonando os repositórios
- Clonando o repositório pje (utilizar o branch PJE2-NG como base)
$ git clone git@git.cnj.jus.br:pje/pje.git $ ls pje pje-comum pje-web pom.xml $ git checkout PJE2-NG
- Clonando o repositório pje2-discovery-service (utilizar o branch master como base)
$ git clone git@git.cnj.jus.br:pje2/pje2-infraestrutura/pje2-discovery-service.git $ ls pje2-discovery-service pom.xml src
- Clonando o repositório pje2-web (utilizar o branch master como base)
$ git clone git@git.cnj.jus.br:pje2/pje2-clientes/pje2-web.git $ ls pje2-web frontend gateway pom.xml README.md src
Importando os projetos
Importando o projeto pje no eclipse
- No menu Arquivo selecione a opção Importar
- Selecionar a opção Existing Maven Project
- Selecionar a pasta do projeto clonado
- Selecionar Finish
- Adicionar um novo servidor de aplicação
- Selecionar o diretório raiz do wildfly/jboss e utilizar o standalone-full.xml
- Adicionar o projeto pje-web ao servidor de aplicação
Importando projetos pje2-web e pje2-discovery-service no STS
- Abrir o Eclipse STS
- No menu Arquivo selecione a opção Importar
- Selecionar a opção Existing Maven Project
- Selecionar a pasta do projeto pje2-web clonado
- Selecionar finish
- No menu Arquivo selecione a opção Importar
- Selecionar a opção Existing Maven Project
- Selecionar a pasta do projeto pje2-discovery-service clonado
- Selecionar finish
Iniciando os serviços
Inicializando os serviços SpringBoot no Eclipse STS
- Na ferramenta Eclipse STS selecione os projetos e efetue um Project>Clean...
- No Boot Dashboard execute o start ou debug dos dois serviços disponíveis
Inicializando o pje no Eclipse
- Na ferramenta Eclipse abrir o arquivo integracao.properties
- Alterar a propriedade pje2.cloud.registrar para o valor true, isso fará com que o pje se registro no pje2-discovery-service
- Iniciar o servidor de aplicação após efetuar o build do projeto
- Após o startup da aplicação acessar a página http://localhost:8761/ para verificar se o pje-legacy foi registrado no eureka
- Acesse o pje através de http://localhost:8080/pje-web
- Acesse o painel do usuário interno com papel de diretor de secretaria http://localhost:8080/pje-web/ng2/dev.seam#/painel-usuario-interno