[RESOLVIDO] RestEasy + AngularJS Reduzir número de requisições

Olá, estou trabalhando em um projeto que utiliza RestEasy e AngulaJS.

Porém a forma como é feito gera em algumas páginas um número muito alto de requisições, deixando a aplicação bastante lenta. Fora que são feitas N requisições * 2, como pode ser visto na imagem.
Hoje a aplicação está num mesmo servidor.

Eu pensei na possibilidade de usar algo parecido com o ModelAndView do SpringMVC, para fazer uma única requisição, e popular a tela com as informações necessárias.

Alguém enxerga uma ideia que possa ajudar a reduzir as requisições?

Obrigado

1 curtida

vamos la

vc desacoplou a sua aplicação em uma API que expoe diferentes recursos. era de se esperar que vc tivesse requisição demais.

por outro lado, mostra coisas curiosas sobre a sua aplicação. sua web app faz o que ? pra mim ela parece meio inutil e, potencialmente, um gargalo de algumas aplicações.

pense no seguinte:

  1. api rest com apenas um cliente ( a web app ) serve pra que? que problema vc esta resolvendo com uma api rest?
  2. onde vc faz cache? sim pq se a lista de unidade muda pouco ou nunca vc pode facilmente cachear e não requisitar sempre.
  3. o problema da sua aplicação é realmente as N*2 requests? pq isso em geral esta associado à gargalo de I/O.
  4. existe uma forma de vc encapsular varios requests dentro de um grande request e fazer um batch. eu tenho um serviço que usa isso e é uma bela porcaria diga-se de passagem. evite se possivel, um dia vc vai me agradecer.

Pois é, o WebApp realmente é inútil ao meu ver. Em parte ele só é utilizado para os recursos web (css, js e html) e expor alguns recursos externos e serve como “Proxy” parar filtrar as requisições do browser e enviar elas novamente para o RestClient, com cabeçalhos e nos retornos tratativas de exceção, porém esse proxy é um jar dentro do WebApp.

  1. Em se serve para expor a camada de negócio (EJB) e em rara ocasiões outros sistemas utilizam alguns esses serviços rest.

  2. Cache só é utilizado nos assets, é raro utilizar para atributos na tela. Foi uma alternativa que pensei para diminuir as requisições, mas ainda não apliquei.

  3. É uma parte dos problemas, o outro grande problema era que não estavam fazendo cache, mas isso já resolveram. Porém o número de requisições é algo que está começando a problemático, já que a tela demora muito para carregar.

  4. Este foi pensado por um outro desenvolvedor, mas seria necessário modificar parte do “proxy” e parte dos Javascript para encapsular o máximo.

o que vc pode pensar é que a WebApp faça coisas como cuidar do login, etc. nesse caso ela seria como um ‘middleware’ e algo que cuida da integridade entre o que vc pede e o que a api rest dá. não é inutil, só deve ser ‘leve’.

se vc usar um servidor web de verdade como nginx e cuidar dos cabeçalhos http com carinho, o cache sera facil de gerenciar. nao sei como é feito em java mas com certeza vc tem anotacoes tipo “cacheia isso por 1 dia, cacheia por 1 hora, etc”.

é interessante vc gerar ETAG pois o browser ( e a webapp ) podem perguntar “oi, eu cacheei a parada tal com o ETAG X, ainda é isso ou mudou”? e isso é gerenciado pelo web server que cuida do cache. ETAG geralmente é um md5 do recurso.

ETAG vai usar os headers If-Match e se vc utilizar tempo vai usar o If-Modify-Since. vc pode combinar os dois.

estude que a resposta esta por ai. REST é HTTP, use-o ao seu favor.

ps: vc pode pensar em algumas operações usar o verbo http HEAD, que basicamente diz “oi, esse recurso existe?”, outra coisa é paginar algumas operações.

Não sei se entendi bem, mas se quer diminuir a quantidade de requisições, por que você não traz todos os dados da página em uma requisição? Seria um objeto com tudo que é necessário para a tela:

{
    "unidades": [...],
    "orgaos": [...],
    "etc"
}

Claro que listagens grandes não vale a pena fazer isso, deixe sob demanda e paginado como @peczenyj falou.

Outra coisa, se as aplicações consomem somente dados via HTTP, EJB pode ser um recurso desnecessário, senão fica um peso a mais em vão.

@peczenyj O login é feito via SSO o máximo que o proxy faz é garantir se a requisição veio de um usuário logado, e modificar o cabeçalho. Penso que principal função é proteger acesso direto ao Rest, só é possível via esse Proxy.
Eu cai meio que de paraquedas para tentar achar uma solução para as inúmeras requisições. Seguindo a ideia abaixo.

@javaflex então é essa abordagem que estou seguindo, eu serializo um HashMap no retorno, mas devido ao fluxo do CRUD que basicamente se divide em duas ou 3 views separadas, como é necessário a cada view eu fazer uma nova requisição, penso que usar cache nesse caso deve ajudar.

Mas eu estou sem ideia de como sair de casos que acontece onde tenho 2 campos na pesquisa e 4 na edição/inserção. Se o ideal seria fazer métodos baseados nesse estado ou tentar algo diferença e mais genérico.

A camada de negocio é toda EJB, mas não se usa nada avançado, só o básico.

Vou continuar tentando a solução do hashMap e tentar o uso de cache nesses casos.

Muito obrigado

Se o fluxo do CRUD que você fala são etapas de preenchimento de formulário ou algo do tipo, isso não impede de você fazer uma única requisição de informações e usar determinado dado quando for o momento, dado A na etapa 1, o dado B na etapa 2, etc.

por que vc precisa fazer nova requisição a cada view? não pode desenvolver a aplicação pra fazer apenas 1 requisição?
nunca trabalhei com SPA.

Comecei a mexer a pouco tempo, ainda estou confuso.

A maior parte do meu tempo trabalhei com JSF e SpringMVC, e ao menos para mim, a diferença está sendo enorme.

A maior problema é que o AngularJS quando modifica a view (template?) o controller da view anterior é destruído, mesmo que seja o mesmo controller na nova view, ou seja, é necessário carregar tudo que já havia sido carregado (cache deve resolver isso).

Mas o que estou mais travado é como criar algo genérico que me permita especificar o que carregar dependendo da view, sem ter que criar N métodos no backend. Ou algo que eu consigo fazer de forma inteligente.

Essa pode não ser a melhor forma para resolver, mas me parece ser adequada similar o que já havia visto no SpringMVC e JSF.

Me expressei mal, não são etapas 1, 2, 3.

Na verdade são os “estados” da view, pesquisa/inserção/edição/visualização. Que pode ter diferente quantidade de informações necessárias por view.

eu analisaria tudo com um ou dois profilers.

pode ser que o seu problema seja no browser pq existe um limite de conexões simultaneas para o mesmo dominio ( por isso a galera inventa uns subdominios marotos )

Bom que tenha explicado melhor pra conseguir mais ajuda. Mesmo nesse cenário, você já não consegue tranquilamente carregar as informações das duas combos em uma única requisição? (Conforme seu exemplo). Ou tem algo além disso?

Claro que a tela/HTML de CRUD teria sua requisição e a tela de pesquisa a sua própria, pois são duas telas diferentes mesmo. Inserção/Edição/Visualização normalmente é o mesmo HTML, só muda o modo e poucas particularidades como por exemplo na visualização nem trazer as listas.

Então uma SPA mantém o estado no server? Não é isso que diz a wikipedia sobre Angular.

“In the AngularJS framework, the controller and model states are maintained within the client browser. Therefore, new pages are capable of being generated without any interaction with a server.”

Sim, eu quis dizer que o Angular não mantém o estado nem local. Menos ainda no server.

Bom, acabei desenvolvendo a solução de serializar um hashMap na primeira requisição com o máximo de informações que preciso.

A ideia de serviços não faz tanto sentido nesse sistema, então ao invés de ter serviços Rest separados foi melhor os Rest serem voltados para as telas que representam.

O método recebi um parametro que me diz qual estado da tela está e a partir daí faço If-Else para saber as informações necessárias em cada estado.

Para uma primeira versão está funcionando bem, tem bastante ainda para melhorar.

Vlw a todos que tiveram um tempo pra responder. E as outras dicas em relação ao cache vou buscar, pois em outro projeto que segue a mesma arquitetura será essencial o uso.