Upgrade to Pro — share decks privately, control downloads, hide ads and more …

Distributed Scheduling com Spring Boot: os desa...

Distributed Scheduling com Spring Boot: os desafios e percalços de implementar um job em background

Cedo ou tarde um desenvolvedor(a) implementará seu primeiro job em background, o que geralmente é uma tarefa simples para maioria dos sistemas pode se tornar um pesadelo em sistemas que precisam lidar com grande volumetria de dados, alta performance e paralelismo. Cenários como esses escondem diversos problemas na qual a maioria dos desenvolvedores não está acostumado, como volume de dados, falhas na rede, reprocessamento indevido, sobrecarga no banco de dados, erros de estouro de memória até indisponibilidade de todo o sistema.

Lidar com boa parte desses problemas não requer tecnologias e serviços da moda (hype), mas sim fundamentos sólidos em sistemas distribuídos. Nessa talk, pretendo apresentar como um desenvolvedor(a) experiente implementa um job em background levando em conta os principais percalços e desenha uma solução para escala horizontal ao mesmo tempo em que tira proveito das tecnologias adotadas pelo time de desenvolvimento.

Se você acredita que um job em background é uma tarefa simples, então essa talk é para você!

(GRAVAÇÃO: https://youtu.be/I_kEO_HPfBU?list=PLHMMERsvy9EyWQPru4SrJAYHEGKfkjRgP&t=130)

Rafael Ponte

August 25, 2021
Tweet

More Decks by Rafael Ponte

Other Decks in Technology

Transcript

  1. DISTRIBUTED SCHEDULING | Spring Boot os desa fi os e

    percalços de implementar um job em background
  2. @Component public class OneJob { @Scheduled(fixedDelay = 60_000) public void

    runQuiteOften() { // lógica do job vai aqui } }
  3. @Component public class OneJob { @Scheduled(fixedDelay = 60_000) public void

    runQuiteOften() { // lógica do job vai aqui } }
  4. @Component public class OneJob { @Scheduled(fixedDelay = 60_000) public void

    runQuiteOften() { // lógica do job vai aqui } }
  5. @Component public class OneJob { @Scheduled(fixedDelay = 60_000) public void

    runQuiteOften() { // lógica do job vai aqui } }
  6. @Component public class OneJob { @Scheduled(fixedDelay = 60_000) public void

    runQuiteOften() { // lógica do job vai aqui } }
  7. @Component public class OneJob { @Scheduled(fixedDelay = 60_000) public void

    runQuiteOften() { // lógica do job vai aqui } }
  8. @Component public class AttachCardsToProposalsJob { private CardsClient cardsClient; private CardRepository

    cardRepository; private ProposalRepository proposalRepository; @Transactional @Scheduled(fixedDelay = 60_000) public void execute() { List<Proposal> proposals = proposalRepository.findAllByStatusOrderByCreatedAtAsc(ELIGIBLE); proposals.forEach(proposal -> { CardDataResponse cardData = cardsClient.findCardByProposalId(proposal.getId()); Card newCard = cardData.toModel(); cardRepository.save(newCard); proposal.attachTo(newCard); proposalRepository.save(proposal); }); } }
  9. @Component public class AttachCardsToProposalsJob { private CardsClient cardsClient; private CardRepository

    cardRepository; private ProposalRepository proposalRepository; @Transactional @Scheduled(fixedDelay = 60_000) public void execute() { List<Proposal> proposals = proposalRepository.findAllByStatusOrderByCreatedAtAsc(ELIGIBLE); proposals.forEach(proposal -> { CardDataResponse cardData = cardsClient.findCardByProposalId(proposal.getId()); Card newCard = cardData.toModel(); cardRepository.save(newCard); proposal.attachTo(newCard); proposalRepository.save(proposal); }); } }
  10. @Component public class AttachCardsToProposalsJob { private CardsClient cardsClient; private CardRepository

    cardRepository; private ProposalRepository proposalRepository; @Transactional @Scheduled(fixedDelay = 60_000) public void execute() { List<Proposal> proposals = proposalRepository.findAllByStatusOrderByCreatedAtAsc(ELIGIBLE); proposals.forEach(proposal -> { CardDataResponse cardData = cardsClient.findCardByProposalId(proposal.getId()); Card newCard = cardData.toModel(); cardRepository.save(newCard); proposal.attachTo(newCard); proposalRepository.save(proposal); }); } }
  11. @Component public class AttachCardsToProposalsJob { private CardsClient cardsClient; private CardRepository

    cardRepository; private ProposalRepository proposalRepository; @Transactional @Scheduled(fixedDelay = 60_000) public void execute() { List<Proposal> proposals = proposalRepository.findAllByStatusOrderByCreatedAtAsc(ELIGIBLE); proposals.forEach(proposal -> { CardDataResponse cardData = cardsClient.findCardByProposalId(proposal.getId()); Card newCard = cardData.toModel(); cardRepository.save(newCard); proposal.attachTo(newCard); proposalRepository.save(proposal); }); } }
  12. @Component public class AttachCardsToProposalsJob { private CardsClient cardsClient; private CardRepository

    cardRepository; private ProposalRepository proposalRepository; @Transactional @Scheduled(fixedDelay = 60_000) public void execute() { List<Proposal> proposals = proposalRepository.findAllByStatusOrderByCreatedAtAsc(ELIGIBLE); proposals.forEach(proposal -> { CardDataResponse cardData = cardsClient.findCardByProposalId(proposal.getId()); Card newCard = cardData.toModel(); cardRepository.save(newCard); proposal.attachTo(newCard); proposalRepository.save(proposal); }); } }
  13. @Component public class AttachCardsToProposalsJob { private CardsClient cardsClient; private CardRepository

    cardRepository; private ProposalRepository proposalRepository; @Transactional @Scheduled(fixedDelay = 60_000) public void execute() { List<Proposal> proposals = proposalRepository.findAllByStatusOrderByCreatedAtAsc(ELIGIBLE); proposals.forEach(proposal -> { CardDataResponse cardData = cardsClient.findCardByProposalId(proposal.getId()); Card newCard = cardData.toModel(); cardRepository.save(newCard); proposal.attachTo(newCard); proposalRepository.save(proposal); }); } }
  14. @Component public class AttachCardsToProposalsJob { private CardsClient cardsClient; private CardRepository

    cardRepository; private ProposalRepository proposalRepository; @Transactional @Scheduled(fixedDelay = 60_000) public void execute() { List<Proposal> proposals = proposalRepository.findAllByStatusOrderByCreatedAtAsc(ELIGIBLE); proposals.forEach(proposal -> { CardDataResponse cardData = cardsClient.findCardByProposalId(proposal.getId()); Card newCard = cardData.toModel(); cardRepository.save(newCard); proposal.attachTo(newCard); proposalRepository.save(proposal); }); } }
  15. @Component public class AttachCardsToProposalsJob { private CardsClient cardsClient; private CardRepository

    cardRepository; private ProposalRepository proposalRepository; @Transactional @Scheduled(fixedDelay = 60_000) public void execute() { List<Proposal> proposals = proposalRepository.findAllByStatusOrderByCreatedAtAsc(ELIGIBLE); proposals.forEach(proposal -> { CardDataResponse cardData = cardsClient.findCardByProposalId(proposal.getId()); Card newCard = cardData.toModel(); cardRepository.save(newCard); proposal.attachTo(newCard); proposalRepository.save(proposal); }); } }
  16. @Component public class AttachCardsToProposalsJob { private CardsClient cardsClient; private CardRepository

    cardRepository; private ProposalRepository proposalRepository; @Transactional @Scheduled(fixedDelay = 60_000) public void execute() { List<Proposal> proposals = proposalRepository.findAllByStatusOrderByCreatedAtAsc(ELIGIBLE); proposals.forEach(proposal -> { CardDataResponse cardData = cardsClient.findCardByProposalId(proposal.getId()); Card newCard = cardData.toModel(); cardRepository.save(newCard); proposal.attachTo(newCard); proposalRepository.save(proposal); }); } }
  17. @Component public class AttachCardsToProposalsJob { private CardsClient cardsClient; private CardRepository

    cardRepository; private ProposalRepository proposalRepository; @Transactional @Scheduled(fixedDelay = 60_000) public void execute() { List<Proposal> proposals = proposalRepository.findAllByStatusOrderByCreatedAtAsc(ELIGIBLE); proposals.forEach(proposal -> { CardDataResponse cardData = cardsClient.findCardByProposalId(proposal.getId()); Card newCard = cardData.toModel(); cardRepository.save(newCard); proposal.attachTo(newCard); proposalRepository.save(proposal); }); } }
  18. @Component public class AttachCardsToProposalsJob { private CardsClient cardsClient; private CardRepository

    cardRepository; private ProposalRepository proposalRepository; @Transactional @Scheduled(fixedDelay = 60_000) public void execute() { List<Proposal> proposals = proposalRepository.findAllByStatusOrderByCreatedAtAsc(ELIGIBLE); proposals.forEach(proposal -> { CardDataResponse cardData = cardsClient.findCardByProposalId(proposal.getId()); Card newCard = cardData.toModel(); cardRepository.save(newCard); proposal.attachTo(newCard); proposalRepository.save(proposal); }); } }
  19. @Component public class AttachCardsToProposalsJob { private CardsClient cardsClient; private CardRepository

    cardRepository; private ProposalRepository proposalRepository; @Transactional @Scheduled(fixedDelay = 60_000) public void execute() { List<Proposal> proposals = proposalRepository.findAllByStatusOrderByCreatedAtAsc(ELIGIBLE); proposals.forEach(proposal -> { CardDataResponse cardData = cardsClient.findCardByProposalId(proposal.getId()); Card newCard = cardData.toModel(); cardRepository.save(newCard); proposal.attachTo(newCard); proposalRepository.save(proposal); }); } }
  20. @Component public class AttachCardsToProposalsJob { private CardsClient cardsClient; private CardRepository

    cardRepository; private ProposalRepository proposalRepository; @Transactional @Scheduled(fixedDelay = 60_000) public void execute() { List<Proposal> proposals = proposalRepository.findAllByStatusOrderByCreatedAtAsc(ELIGIBLE); proposals.forEach(proposal -> { CardDataResponse cardData = cardsClient.findCardByProposalId(proposal.getId()); Card newCard = cardData.toModel(); cardRepository.save(newCard); proposal.attachTo(newCard); proposalRepository.save(proposal); }); } }
  21. @Component public class AttachCardsToProposalsJob { private CardsClient cardsClient; private CardRepository

    cardRepository; private ProposalRepository proposalRepository; @Transactional @Scheduled(fixedDelay = 60_000) public void execute() { List<Proposal> proposals = proposalRepository.findAllByStatusOrderByCreatedAtAsc(ELIGIBLE); proposals.forEach(proposal -> { CardDataResponse cardData = cardsClient.findCardByProposalId(proposal.getId()); Card newCard = cardData.toModel(); cardRepository.save(newCard); proposal.attachTo(newCard); proposalRepository.save(proposal); }); } }
  22. @Component public class AttachCardsToProposalsJob { private CardsClient cardsClient; private CardRepository

    cardRepository; private ProposalRepository proposalRepository; @Transactional @Scheduled(fixedDelay = 60_000) public void execute() { List<Proposal> proposals = proposalRepository.findAllByStatusOrderByCreatedAtAsc(ELIGIBLE); proposals.forEach(proposal -> { CardDataResponse cardData = cardsClient.findCardByProposalId(proposal.getId()); Card newCard = cardData.toModel(); cardRepository.save(newCard); proposal.attachTo(newCard); proposalRepository.save(proposal); }); } }
  23. DISTRIBUTED SCHEDULING | Spring Boot os desa fi os e

    percalços de implementar um job em background
  24. @Component public class AttachCardsToProposalsJob { private CardsClient cardsClient; private CardRepository

    cardRepository; private ProposalRepository proposalRepository; @Transactional @Scheduled(fixedDelay = 60_000) public void execute() { List<Proposal> proposals = proposalRepository.findAllByStatusOrderByCreatedAtAsc(ELIGIBLE); proposals.forEach(proposal -> { CardDataResponse cardData = cardsClient.findCardByProposalId(proposal.getId()); Card newCard = cardData.toModel(); cardRepository.save(newCard); proposal.attachTo(newCard); proposalRepository.save(proposal); }); } }
  25. @Component public class AttachCardsToProposalsJob { private CardsClient cardsClient; private CardRepository

    cardRepository; private ProposalRepository proposalRepository; @Transactional @Scheduled(fixedDelay = 60_000) public void execute() { List<Proposal> proposals = proposalRepository.findAllByStatusOrderByCreatedAtAsc(ELIGIBLE); proposals.forEach(proposal -> { CardDataResponse cardData = cardsClient.findCardByProposalId(proposal.getId()); Card newCard = cardData.toModel(); cardRepository.save(newCard); proposal.attachTo(newCard); proposalRepository.save(proposal); }); } }
  26. @Component public class AttachCardsToProposalsJob { private CardsClient cardsClient; private CardRepository

    cardRepository; private ProposalRepository proposalRepository; @Transactional @Scheduled(fixedDelay = 60_000) public void execute() { List<Proposal> proposals = proposalRepository.findAllByStatusOrderByCreatedAtAsc(ELIGIBLE); proposals.forEach(proposal -> { CardDataResponse cardData = cardsClient.findCardByProposalId(proposal.getId()); Card newCard = cardData.toModel(); cardRepository.save(newCard); proposal.attachTo(newCard); proposalRepository.save(proposal); }); } }
  27. @Component public class AttachCardsToProposalsJob { private CardsClient cardsClient; private CardRepository

    cardRepository; private ProposalRepository proposalRepository; @Transactional @Scheduled(fixedDelay = 60_000) public void execute() { List<Proposal> proposals = proposalRepository.findAllByStatusOrderByCreatedAtAsc(ELIGIBLE); proposals.forEach(proposal -> { CardDataResponse cardData = cardsClient.findCardByProposalId(proposal.getId()); Card newCard = cardData.toModel(); cardRepository.save(newCard); proposal.attachTo(newCard); proposalRepository.save(proposal); }); } }
  28. @Component public class AttachCardsToProposalsJob { private CardsClient cardsClient; private CardRepository

    cardRepository; private ProposalRepository proposalRepository; @Transactional @Scheduled(fixedDelay = 60_000) public void execute() { List<Proposal> proposals = proposalRepository.findTop50ByStatusOrderByCreatedAtAsc(ELIGIBLE); proposals.forEach(proposal -> { CardDataResponse cardData = cardsClient.findCardByProposalId(proposal.getId()); Card newCard = cardData.toModel(); cardRepository.save(newCard); proposal.attachTo(newCard); proposalRepository.save(proposal); }); } }
  29. @Component public class AttachCardsToProposalsJob { private CardsClient cardsClient; private CardRepository

    cardRepository; private ProposalRepository proposalRepository; @Transactional @Scheduled(fixedDelay = 60_000) public void execute() { List<Proposal> proposals = proposalRepository.findTop50ByStatusOrderByCreatedAtAsc(ELIGIBLE); proposals.forEach(proposal -> { CardDataResponse cardData = cardsClient.findCardByProposalId(proposal.getId()); Card newCard = cardData.toModel(); cardRepository.save(newCard); proposal.attachTo(newCard); proposalRepository.save(proposal); }); } }
  30. @Component public class AttachCardsToProposalsJob { private CardsClient cardsClient; private CardRepository

    cardRepository; private ProposalRepository proposalRepository; @Transactional @Scheduled(fixedDelay = 60_000) public void execute() { List<Proposal> proposals = proposalRepository.findTop50ByStatusOrderByCreatedAtAsc(ELIGIBLE); proposals.forEach(proposal -> { CardDataResponse cardData = cardsClient.findCardByProposalId(proposal.getId()); Card newCard = cardData.toModel(); cardRepository.save(newCard); proposal.attachTo(newCard); proposalRepository.save(proposal); }); } } o loop vai encerrar muito CEDO !
  31. @Component public class AttachCardsToProposalsJob { private CardsClient cardsClient; private CardRepository

    cardRepository; private ProposalRepository proposalRepository; @Transactional @Scheduled(fixedDelay = 60_000) public void execute() { List<Proposal> proposals = proposalRepository.findTop50ByStatusOrderByCreatedAtAsc(ELIGIBLE); proposals.forEach(proposal -> { CardDataResponse cardData = cardsClient.findCardByProposalId(proposal.getId()); Card newCard = cardData.toModel(); cardRepository.save(newCard); proposal.attachTo(newCard); proposalRepository.save(proposal); }); } } Só vai rodar no próximo agendamento!
  32. @Transactional @Scheduled(fixedDelay = 60_000) public void execute() { List<Proposal> proposals

    = proposalRepository.findTop50ByStatusOrderByCreatedAtAsc(…); proposals.forEach(proposal -> { // processa cada proposta }); }
  33. @Transactional @Scheduled(fixedDelay = 60_000) public void execute() { while (true)

    { List<Proposal> proposals = proposalRepository.findTop50ByStatusOrderByCreatedAtAsc(…); if (proposals.isEmpty()) { break; } proposals.forEach(proposal -> { // processa cada proposta }); } }
  34. @Transactional @Scheduled(fixedDelay = 60_000) public void execute() { while (true)

    { List<Proposal> proposals = proposalRepository.findTop50ByStatusOrderByCreatedAtAsc(…); if (proposals.isEmpty()) { break; } proposals.forEach(proposal -> { // processa cada proposta }); } }
  35. @Transactional @Scheduled(fixedDelay = 60_000) public void execute() { while (true)

    { List<Proposal> proposals = proposalRepository.findTop50ByStatusOrderByCreatedAtAsc(…); if (proposals.isEmpty()) { break; } proposals.forEach(proposal -> { // processa cada proposta }); } }
  36. @Transactional @Scheduled(fixedDelay = 60_000) public void execute() { while (true)

    { List<Proposal> proposals = proposalRepository.findTop50ByStatusOrderByCreatedAtAsc(…); if (proposals.isEmpty()) { break; } proposals.forEach(proposal -> { // processa cada proposta }); } }
  37. @Component public class AttachCardsToProposalsJob { // dependências e constantes @Transactional

    @Scheduled(fixedDelay = 60_000) public void execute() { while (true) { List<Proposal> proposals = proposalRepository.findTop50ByStatusOrderByCreatedAtAsc(ELIGIBLE); if (proposals.isEmpty()) { break; } proposals.forEach(proposal -> { CardDataResponse cardData = cardsClient.findCardByProposalId(proposal.getId()); Card newCard = cardData.toModel(); cardRepository.save(newCard); proposal.attachTo(newCard); proposalRepository.save(proposal); }); } } }
  38. @Component public class AttachCardsToProposalsJob { // dependências e constantes @Transactional

    @Scheduled(fixedDelay = 60_000) public void execute() { while (true) { List<Proposal> proposals = proposalRepository.findTop50ByStatusOrderByCreatedAtAsc(ELIGIBLE); if (proposals.isEmpty()) { break; } proposals.forEach(proposal -> { CardDataResponse cardData = cardsClient.findCardByProposalId(proposal.getId()); Card newCard = cardData.toModel(); cardRepository.save(newCard); proposal.attachTo(newCard); proposalRepository.save(proposal); }); } } }
  39. @Component public class AttachCardsToProposalsJob { // dependências e constantes @Transactional

    @Scheduled(fixedDelay = 60_000) public void execute() { while (true) { List<Proposal> proposals = proposalRepository.findTop50ByStatusOrderByCreatedAtAsc(ELIGIBLE); if (proposals.isEmpty()) { break; } proposals.forEach(proposal -> { CardDataResponse cardData = cardsClient.findCardByProposalId(proposal.getId()); Card newCard = cardData.toModel(); cardRepository.save(newCard); proposal.attachTo(newCard); proposalRepository.save(proposal); }); } } } - carregando apenas 50 objetos por vez
  40. @Component public class AttachCardsToProposalsJob { // dependências e constantes @Transactional

    @Scheduled(fixedDelay = 60_000) public void execute() { while (true) { List<Proposal> proposals = proposalRepository.findTop50ByStatusOrderByCreatedAtAsc(ELIGIBLE); if (proposals.isEmpty()) { break; } proposals.forEach(proposal -> { CardDataResponse cardData = cardsClient.findCardByProposalId(proposal.getId()); Card newCard = cardData.toModel(); cardRepository.save(newCard); proposal.attachTo(newCard); proposalRepository.save(proposal); }); } } } - criando nova referência - carregando apenas 50 objetos por vez
  41. @Component public class AttachCardsToProposalsJob { // dependências e constantes @Transactional

    @Scheduled(fixedDelay = 60_000) public void execute() { while (true) { List<Proposal> proposals = proposalRepository.findTop50ByStatusOrderByCreatedAtAsc(ELIGIBLE); if (proposals.isEmpty()) { break; } proposals.forEach(proposal -> { CardDataResponse cardData = cardsClient.findCardByProposalId(proposal.getId()); Card newCard = cardData.toModel(); cardRepository.save(newCard); proposal.attachTo(newCard); proposalRepository.save(proposal); }); } } } - criando nova referência - carregando apenas 50 objetos por vez - saindo do loop na hora certa
  42. @Component public class AttachCardsToProposalsJob { // dependências e constantes @Transactional

    @Scheduled(fixedDelay = 60_000) public void execute() { while (true) { List<Proposal> proposals = proposalRepository.findTop50ByStatusOrderByCreatedAtAsc(ELIGIBLE); if (proposals.isEmpty()) { break; } proposals.forEach(proposal -> { CardDataResponse cardData = cardsClient.findCardByProposalId(proposal.getId()); Card newCard = cardData.toModel(); cardRepository.save(newCard); proposal.attachTo(newCard); proposalRepository.save(proposal); }); } } }
  43. Job

  44. @Component public class AttachCardsToProposalsJob { // dependências e constantes @Transactional

    @Scheduled(fixedDelay = 60_000) public void execute() { while (true) { List<Proposal> proposals = proposalRepository.findTop50ByStatusOrderByCreatedAtAsc(ELIGIBLE); if (proposals.isEmpty()) { break; } proposals.forEach(proposal -> { CardDataResponse cardData = cardsClient.findCardByProposalId(proposal.getId()); Card newCard = cardData.toModel(); cardRepository.save(newCard); proposal.attachTo(newCard); proposalRepository.save(proposal); }); } } }
  45. @Component public class AttachCardsToProposalsJob { // dependências e constantes @Scheduled(fixedDelay

    = 60_000) public void execute() { while (true) { List<Proposal> proposals = proposalRepository.findTop50ByStatusOrderByCreatedAtAsc(ELIGIBLE); if (proposals.isEmpty()) { break; } proposals.forEach(proposal -> { CardDataResponse cardData = cardsClient.findCardByProposalId(proposal.getId()); Card newCard = cardData.toModel(); cardRepository.save(newCard); proposal.attachTo(newCard); proposalRepository.save(proposal); }); } } } inicia e termina uma transação
  46. @Component public class AttachCardsToProposalsJob { // dependências e constantes @Scheduled(fixedDelay

    = 60_000) public void execute() { while (true) { List<Proposal> proposals = proposalRepository.findTop50ByStatusOrderByCreatedAtAsc(ELIGIBLE); if (proposals.isEmpty()) { break; } proposals.forEach(proposal -> { CardDataResponse cardData = cardsClient.findCardByProposalId(proposal.getId()); Card newCard = cardData.toModel(); cardRepository.save(newCard); proposal.attachTo(newCard); proposalRepository.save(proposal); }); } } }
  47. @Component public class AttachCardsToProposalsJob { // dependências e constantes @Scheduled(fixedDelay

    = 60_000) public void execute() { while (true) { List<Proposal> proposals = proposalRepository.findTop50ByStatusOrderByCreatedAtAsc(ELIGIBLE); if (proposals.isEmpty()) { break; } proposals.forEach(proposal -> { CardDataResponse cardData = cardsClient.findCardByProposalId(proposal.getId()); Card newCard = cardData.toModel(); cardRepository.save(newCard); // inicia e comita transação proposal.attachTo(newCard); proposalRepository.save(proposal); // inicia e comita transação }); } } } analogo a 
 auto_commit = true
  48. @Component public class AttachCardsToProposalsJob { // dependências e constantes @Scheduled(fixedDelay

    = 60_000) public void execute() { while (true) { List<Proposal> proposals = proposalRepository.findTop50ByStatusOrderByCreatedAtAsc(ELIGIBLE); if (proposals.isEmpty()) { break; } proposals.forEach(proposal -> { CardDataResponse cardData = cardsClient.findCardByProposalId(proposal.getId()); Card newCard = cardData.toModel(); cardRepository.save(newCard); // inicia e comita transação proposal.attachTo(newCard); proposalRepository.save(proposal); // inicia e comita transação }); } } } Abrimos mão da CONSISTÊNCIA dos dados!
  49. @Component public class AttachCardsToProposalsJob { @Scheduled(fixedDelay = 60_000) public void

    execute() { while (true) { // executa código em escopo transacional } } }
  50. @Component public class AttachCardsToProposalsJob { @Scheduled(fixedDelay = 60_000) public void

    execute() { while (true) { @Transactional.execute(transaction -> { // executa código em escopo transacional }); } } }
  51. @Component public class AttachCardsToProposalsJob { @Scheduled(fixedDelay = 60_000) public void

    execute() { while (true) { @Transactional.execute(transaction -> { // executa código em escopo transacional }); } } }
  52. @Component public class AttachCardsToProposalsJob { @Scheduled(fixedDelay = 60_000) public void

    execute() { while (true) { @Transactional.execute(transaction -> { // executa código em escopo transacional }); } } }
  53. @Component public class AttachCardsToProposalsJob { @Scheduled(fixedDelay = 60_000) public void

    execute() { while (true) { @Transactional.execute(transaction -> { // executa código em escopo transacional }); } } }
  54. @Component public class AttachCardsToProposalsJob { @Scheduled(fixedDelay = 60_000) public void

    execute() { while (true) { @Transactional.execute(transaction -> { // executa código em escopo transacional }); } } }
  55. @Component public class AttachCardsToProposalsJob { @Scheduled(fixedDelay = 60_000) public void

    execute() { while (true) { @Transactional.execute(transaction -> { // executa código em escopo transacional }); } } }
  56. @Component public class AttachCardsToProposalsJob { @Scheduled(fixedDelay = 60_000) public void

    execute() { while (true) { @Transactional.execute(transaction -> { // executa código em escopo transacional }); } } }
  57. @Component public class AttachCardsToProposalsJob { @Scheduled(fixedDelay = 60_000) public void

    execute() { while (true) { transactionManager.execute(transaction -> { // executa código em escopo transacional }); } } }
  58. @Component public class AttachCardsToProposalsJob { private TransactionTemplate transactionManager; @Scheduled(fixedDelay =

    60_000) public void execute() { while (true) { transactionManager.execute(transaction -> { // executa código em escopo transacional }); } } }
  59. @Component public class AttachCardsToProposalsJob { private TransactionTemplate transactionManager; @Scheduled(fixedDelay =

    60_000) public void execute() { while (true) { transactionManager.execute(transaction -> { // executa código em escopo transacional }); } } }
  60. @Autowired private TransactionTemplate transactionManager; @Scheduled(fixedDelay = 60_000) public void execute()

    { boolean pending = true; while (pending) { pending = transactionManager.execute(transactionStatus -> { List<Proposal> proposals = proposalRepository.findTop50ByStatusOrderByCreatedAtAsc(…); if (proposals.isEmpty()) { return false; } proposals.forEach(proposal -> { CardDataResponse cardData = cardsClient.findCardByProposalId(proposal.getId()); Card newCard = cardData.toModel(); cardRepository.save(newCard); proposal.attachTo(newCard); proposalRepository.save(proposal); }); return true; }); } }
  61. @Autowired private TransactionTemplate transactionManager; @Scheduled(fixedDelay = 60_000) public void execute()

    { boolean pending = true; while (pending) { pending = transactionManager.execute(transactionStatus -> { List<Proposal> proposals = proposalRepository.findTop50ByStatusOrderByCreatedAtAsc(…); if (proposals.isEmpty()) { return false; } proposals.forEach(proposal -> { CardDataResponse cardData = cardsClient.findCardByProposalId(proposal.getId()); Card newCard = cardData.toModel(); cardRepository.save(newCard); proposal.attachTo(newCard); proposalRepository.save(proposal); }); return true; }); } }
  62. select p.* from proposal p where p.status = 'ELIGIBLE' order

    by p.created_at asc limit 50 
 for update
  63. 9630 9631 QUEUE ( fi la) producer consumer 9629 produz:

    
 1000 itens/min consume: 
 600 itens/min
  64. 9630 9631 QUEUE ( fi la) producer consumer 9629 produz:

    
 1000 itens/min consumer consume: 
 400 itens/min consume: 
 600 itens/min
  65. 9630 9631 QUEUE ( fi la) producer consumer 9629 produz:

    
 1000 itens/min consumer consume: 
 400 itens/min consume: 
 600 itens/min
  66. @Repository public interface ProposalRepository extends JpaRepository<Proposal, UUID> { @QueryHints({ @QueryHint(

    name = "javax.persistence.lock.timeout", value = LockOptions.SKIP_LOCKED) // org.hibernate.LockOptions }) @Lock(LockModeType.PESSIMISTIC_WRITE) public List<Proposal> findTop50ByStatusOrderByCreatedAtAsc(ProposalStatus status); }
  67. @Repository public interface ProposalRepository extends JpaRepository<Proposal, UUID> { @QueryHints({ @QueryHint(

    name = "javax.persistence.lock.timeout", value = LockOptions.SKIP_LOCKED) // org.hibernate.LockOptions }) @Lock(LockModeType.PESSIMISTIC_WRITE) public List<Proposal> findTop50ByStatusOrderByCreatedAtAsc(ProposalStatus status); }
  68. select p.* from proposal p where p.status = 'ELIGIBLE' order

    by p.created_at asc limit 50 
 for update
  69. select p.* from proposal p where p.status = 'ELIGIBLE' order

    by p.created_at asc limit 50 
 for update skip locked
  70. @Autowired private TransactionTemplate transactionManager; @Scheduled(fixedDelay = 60_000) public void execute()

    { boolean pending = true; while (pending) { pending = transactionManager.execute(transactionStatus -> { List<Proposal> proposals = proposalRepository.findTop50ByStatusOrderByCreatedAtAsc(…); if (proposals.isEmpty()) { return false; } proposals.forEach(proposal -> { CardDataResponse cardData = cardsClient.findCardByProposalId(proposal.getId()); Card newCard = cardData.toModel(); cardRepository.save(newCard); proposal.attachTo(newCard); proposalRepository.save(proposal); }); return true; }); } }
  71. @Autowired private TransactionTemplate transactionManager; @Scheduled(fixedDelay = 60_000) public void execute()

    { boolean pending = true; while (pending) { pending = transactionManager.execute(transactionStatus -> { List<Proposal> proposals = proposalRepository.findTop50ByStatusOrderByCreatedAtAsc(…); if (proposals.isEmpty()) { return false; } proposals.forEach(proposal -> { CardDataResponse cardData = cardsClient.findCardByProposalId(proposal.getId()); Card newCard = cardData.toModel(); cardRepository.save(newCard); proposal.attachTo(newCard); proposalRepository.save(proposal); }); return true; }); } }
  72. @Autowired private TransactionTemplate transactionManager; @Scheduled(fixedDelay = 60_000) public void execute()

    { boolean pending = true; while (pending) { pending = transactionManager.execute(transactionStatus -> { List<Proposal> proposals = proposalRepository.findTop50ByStatusOrderByCreatedAtAsc(…); if (proposals.isEmpty()) { return false; } proposals.forEach(proposal -> { CardDataResponse cardData = cardsClient.findCardByProposalId(proposal.getId()); Card newCard = cardData.toModel(); cardRepository.save(newCard); proposal.attachTo(newCard); proposalRepository.save(proposal); }); return true; }); } }
  73. @Autowired private TransactionTemplate transactionManager; @Scheduled(fixedDelay = 60_000) public void execute()

    { boolean pending = true; while (pending) { pending = transactionManager.execute(transactionStatus -> { List<Proposal> proposals = proposalRepository.findTop50ByStatusOrderByCreatedAtAsc(…); if (proposals.isEmpty()) { return false; } proposals.forEach(proposal -> { CardDataResponse cardData = cardsClient.findCardByProposalId(proposal.getId()); Card newCard = cardData.toModel(); cardRepository.save(newCard); proposal.attachTo(newCard); proposalRepository.save(proposal); }); return true; }); } }
  74. @Autowired private TransactionTemplate transactionManager; @Scheduled(fixedDelay = 60_000) public void execute()

    { boolean pending = true; while (pending) { pending = transactionManager.execute(transactionStatus -> { List<Proposal> proposals = proposalRepository.findTop50ByStatusOrderByCreatedAtAsc(…); if (proposals.isEmpty()) { return false; } proposals.forEach(proposal -> { CardDataResponse cardData = cardsClient.findCardByProposalId(proposal.getId()); Card newCard = cardData.toModel(); cardRepository.save(newCard); proposal.attachTo(newCard); proposalRepository.save(proposal); }); return true; }); } } Insere novo cartão Atualiza proposta com cartão
  75. INSERT INTO card(cardNumber) VALUES ('5260-9991-9040-0001'); UPDATE proposal SET status =

    'ELIGIBLE_WITH_ATTACHED_CARD' WHERE id = 2021; INSERT INTO card(cardNumber) VALUES (' 5513-8141-9261-0002'); UPDATE proposal SET status = 'ELIGIBLE_WITH_ATTACHED_CARD' WHERE id = 2022; 4 roundtrips
  76. INSERT INTO card(cardNumber) VALUES ('5260-9991-9040-0001'); UPDATE proposal SET status =

    'ELIGIBLE_WITH_ATTACHED_CARD' WHERE id = 2021; INSERT INTO card(cardNumber) VALUES (' 5513-8141-9261-0002'); UPDATE proposal SET status = 'ELIGIBLE_WITH_ATTACHED_CARD' WHERE id = 2022; INSERT INTO card(cardNumber) VALUES (' 5599-4154-6354-0003'); UPDATE proposal SET status = 'ELIGIBLE_WITH_ATTACHED_CARD' WHERE id = 2023; 6 roundtrips
  77. INSERT INTO card(cardNumber) VALUES ('5260-9991-9040-0001'); UPDATE proposal SET status =

    'ELIGIBLE_WITH_ATTACHED_CARD' WHERE id = 2021; INSERT INTO card(cardNumber) VALUES (' 5513-8141-9261-0002'); UPDATE proposal SET status = 'ELIGIBLE_WITH_ATTACHED_CARD' WHERE id = 2022; INSERT INTO card(cardNumber) VALUES (' 5599-4154-6354-0003'); UPDATE proposal SET status = 'ELIGIBLE_WITH_ATTACHED_CARD' WHERE id = 2023; INSERT INTO card(cardNumber) VALUES (' 5419-8753-1126-0004'); UPDATE proposal SET status = 'ELIGIBLE_WITH_ATTACHED_CARD' WHERE id = 2024; INSERT INTO ... UPDATE proposal SET ... 100 roundtrips
  78. 2 roundtrips INSERT INTO card(cardNumber) VALUES (?) Params: [ 


    ('5513-8141-9261-0001'), 
 ('5513-8141-9261-0002'), 
 (‘5513-8141-9261-0003'), (‘5513-8141-9261-0004'), ... 
 ] UPDATE proposal SET status = ? WHERE id = ?; Params: [ 
 (‘ELIGIBLE_WITH_ATTACHED_CARD’, 2021), 
 ('ELIGIBLE_WITH_ATTACHED_CARD', 2022), 
 ('ELIGIBLE_WITH_ATTACHED_CARD', 2023), ('ELIGIBLE_WITH_ATTACHED_CARD', 2024), ... 
 ]
  79. 2 roundtrips INSERT INTO card(cardNumber) VALUES (?) Params: [ 


    ('5513-8141-9261-0001'), 
 ('5513-8141-9261-0002'), 
 (‘5513-8141-9261-0003'), (‘5513-8141-9261-0004'), ... 
 ] UPDATE proposal SET status = ? WHERE id = ?; Params: [ 
 (‘ELIGIBLE_WITH_ATTACHED_CARD’, 2021), 
 ('ELIGIBLE_WITH_ATTACHED_CARD', 2022), 
 ('ELIGIBLE_WITH_ATTACHED_CARD', 2023), ('ELIGIBLE_WITH_ATTACHED_CARD', 2024), ... 
 ]
  80. INSERT INTO card(cardNumber) VALUES (?) Params: [ 
 ('5513-8141-9261-0001'), 


    ('5513-8141-9261-0002'), 
 (‘5513-8141-9261-0003'), (‘5513-8141-9261-0004'), ... 
 ] 2 roundtrips UPDATE proposal SET status = ? WHERE id = ?; Params: [ 
 (‘ELIGIBLE_WITH_ATTACHED_CARD’, 2021), 
 ('ELIGIBLE_WITH_ATTACHED_CARD', 2022), 
 ('ELIGIBLE_WITH_ATTACHED_CARD', 2023), ('ELIGIBLE_WITH_ATTACHED_CARD', 2024), ... 
 ]
  81. @Scheduled(...) public void execute() { boolean pending = true; while

    (pending) { pending = transactionManager.execute(txStatus -> { List<Proposal> proposals = proposalRepository.findTop50ByStatusOrderByCreatedAtAsc(…); if (proposals.isEmpty()) { return false; } proposals.forEach(proposal -> { CardDataResponse cardData = cardsClient.findCardByProposalId(proposal.getId()); Card newCard = cardData.toModel(); cardRepository.save(newCard); proposal.attachTo(newCard); proposalRepository.save(proposal); }); return true; }); } }
  82. @Scheduled(...) public void execute() { boolean pending = true; while

    (pending) { pending = transactionManager.execute(txStatus -> { List<Proposal> proposals = proposalRepository.findTop50ByStatusOrderByCreatedAtAsc(…); if (proposals.isEmpty()) { return false; } proposals.forEach(proposal -> { CardDataResponse cardData = cardsClient.findCardByProposalId(proposal.getId()); Card newCard = cardData.toModel(); cardRepository.save(newCard); proposal.attachTo(newCard); proposalRepository.save(proposal); }); return true; }); } }
  83. @Scheduled(...) public void execute() { boolean pending = true; while

    (pending) { pending = transactionManager.execute(txStatus -> { List<Proposal> proposals = proposalRepository.findTop50ByStatusOrderByCreatedAtAsc(…); if (proposals.isEmpty()) { return false; } proposals.forEach(proposal -> { CardDataResponse cardData = cardsClient.findCardByProposalId(proposal.getId()); Card newCard = cardData.toModel(); cardRepository.save(newCard); proposal.attachTo(newCard); proposalRepository.save(proposal); }); return true; }); } }
  84. E SE… E SE… E SE… E SE… E SE…

    E SE… E SE… E SE… E SE… E SE… E SE… E SE E SE… SE… E SE… E SE… E SE… E SE… E SE… E SE… SE… E SE…