$30 off During Our Annual Pro Sale. View Details »

Implementando Mensageria com PostgreSQL

Implementando Mensageria com PostgreSQL

A industria tem feito um marketing agressivo em favor de arquiteturas complexas e muito caras, incluindo microsserviços, brokers de mensageria e bancos NoSQL. Para isso, arquiteturas mais simples e, na maioria das vezes suficientes, tornaram-se os vilões para muitas empresas e profissionais, como monolitos e bancos de dados relacionais. Infelizmente, esse último, há mais de 1 decada tem sido vendido apenas como um simples repositório de dados limitado que não permite escalar para milhões de usuários ou dezenas de milhares de requisições.

Essas falácias sobre bancos relacionais precisam acabar, por esse motivo, nessa talk pretendo apresentar como podemos integrar sistemas e serviços sem abrir mão do mundo relacional, tudo isso na perspectiva de um desenvolvedor(a) de software. Em vez de todo um alto custo e complexidade na adoção de Kafka ou RabbitMQ para implementar mensageria em sistemas, nós abraçaremos recursos nativos do próprio PostgreSQL para implementar troca de eventos via fila de mensagens e comunicação Pub/Sub de forma simples, confiável e escalável.

Você vai se surpreender como esses tipos de soluções de mensageria podem ser resolvidos com algumas linhas de SQL, locking distribuído e algum conhecimento sobre as features oferecidas pelo seu banco de dados relacional. No fim, você vai perceber como PostgreSQL é mais do que um repositório de dados, é uma engine completa e robusta de concorrência.

(GRAVAÇÃO: https://www.youtube.com/watch?v=FF6Am0N6eq4&t=840s&ab_channel=Zup)

Rafael Ponte

August 26, 2022
Tweet

More Decks by Rafael Ponte

Other Decks in Technology

Transcript

  1. Mensageria com PostgreSQL
    Escalando sua aplicação com seu banco de dados relacional

    View Slide

  2. View Slide

  3. View Slide

  4. View Slide

  5. Hype-Driven Development
    https://blog.daftcode.pl/hype-driven-development-3469fc2e9b22

    View Slide

  6. View Slide

  7. CACHE

    View Slide

  8. PROCESSAMENTO
    ASSINCRONO
    CACHE

    View Slide

  9. BALANCEAMENTO
    DE CARGA
    CACHE
    PROCESSAMENTO
    ASSINCRONO

    View Slide

  10. CACHE
    BALANCEAMENTO
    DE CARGA
    PROCESSAMENTO
    ASSINCRONO

    View Slide

  11. a idéia é simples…

    View Slide

  12. servidor

    View Slide

  13. db
    servidor

    View Slide

  14. navegador db
    servidor

    View Slide

  15. navegador db
    servidor
    requisição

    View Slide

  16. navegador db
    servidor
    requisição
    resposta

    View Slide

  17. e funciona muito
    bem…

    View Slide

  18. db
    servidor
    requisição
    resposta

    View Slide

  19. db
    servidor
    requisição
    resposta

    View Slide

  20. db
    servidor
    requisição
    resposta

    View Slide

  21. db
    servidor
    requisição
    resposta

    View Slide

  22. db
    servidor
    requisição
    resposta

    View Slide

  23. calma!

    View Slide

  24. navegador db
    servidor
    requisição
    resposta

    View Slide

  25. navegador db
    servidor
    requisição
    resposta
    ???

    View Slide

  26. navegador db
    servidor
    requisição
    resposta

    View Slide

  27. navegador db
    servidor
    requisição
    resposta
    fi
    la

    View Slide

  28. navegador db
    servidor
    requisição
    resposta
    fi
    la
    consumidor

    View Slide

  29. navegador db
    servidor
    requisição
    resposta
    fi
    la
    consumidor

    View Slide

  30. navegador db
    servidor
    requisição
    resposta
    fi
    la
    consumidor

    View Slide

  31. mas qual broker?

    View Slide

  32. View Slide

  33. View Slide

  34. View Slide

  35. View Slide

  36. mas qual o custo?

    View Slide

  37. mas qual o custo?
    Segurança Backup
    Replicação
    Monitoramento
    Upgrade
    Recovery
    Fail-over
    Alta-disponibilidade
    Hardware
    Contratar

    especialistas

    View Slide

  38. E agora?

    View Slide

  39. View Slide

  40. Não!

    View Slide

  41. Que tal…

    View Slide

  42. Banco de dados

    relacional

    View Slide

  43. “Use o banco apenas
    como repositório de
    dados.”

    View Slide

  44. Mas sempre tem aqueles…

    View Slide

  45. View Slide

  46. View Slide

  47. View Slide

  48. Diga-me teu
    throughput e te
    direis quem és…

    View Slide

  49. Como escalar seu
    sistema usando seu
    BANCO DE DADOS

    View Slide

  50. Rafael Ponte


    @rponte

    View Slide

  51. View Slide

  52. Fortaleza - Terra do Sol

    View Slide

  53. View Slide

  54. Mensageria com PostgreSQL
    Escalando sua aplicação o seu MELHOR banco de dados relacional

    View Slide

  55. nosso problema

    View Slide

  56. Loja Virtual

    View Slide

  57. View Slide

  58. View Slide

  59. View Slide

  60. @RestController


    class FinalizaPedidoController {


    @Transactional


    @PostMapping(“/api/pedidos/finaliza”)


    public PedidoResponse finaliza(@RequestBody PedidoRequest request) {



    // efetua pagamento no gateway


    // dá baixa no estoque


    // atualiza pedido


    // envia email de confirmação


    // gera nota fiscal


    return new PedidoResponse(pedido, Status.CONFIRMADO);


    }


    }

    View Slide

  61. @RestController


    class FinalizaPedidoController {


    @Transactional


    @PostMapping(“/api/pedidos/finaliza”)


    public PedidoResponse finaliza(@RequestBody PedidoRequest request) {



    // efetua pagamento no gateway


    // dá baixa no estoque


    // atualiza pedido


    // envia email de confirmação


    // gera nota fiscal


    return new PedidoResponse(pedido, Status.CONFIRMADO);


    }


    }

    View Slide

  62. @RestController


    class FinalizaPedidoController {


    @Transactional


    @PostMapping(“/api/pedidos/finaliza”)


    public PedidoResponse finaliza(@RequestBody PedidoRequest request) {



    // efetua pagamento no gateway


    // dá baixa no estoque


    // atualiza pedido


    // envia email de confirmação


    // gera nota fiscal


    return new PedidoResponse(pedido, Status.CONFIRMADO);


    }


    }

    View Slide

  63. @RestController


    class FinalizaPedidoController {


    @Transactional


    @PostMapping(“/api/pedidos/finaliza”)


    public PedidoResponse finaliza(@RequestBody PedidoRequest request) {



    // efetua pagamento no gateway


    // dá baixa no estoque


    // atualiza pedido


    // envia email de confirmação


    // gera nota fiscal


    return new PedidoResponse(pedido, Status.CONFIRMADO);


    }


    }

    View Slide

  64. @RestController


    class FinalizaPedidoController {


    @Transactional


    @PostMapping(“/api/pedidos/finaliza”)


    public PedidoResponse finaliza(@RequestBody PedidoRequest request) {



    // efetua pagamento no gateway


    // dá baixa no estoque


    // atualiza pedido


    // envia email de confirmação


    // gera nota fiscal


    return new PedidoResponse(pedido, Status.CONFIRMADO);


    }


    }

    View Slide

  65. @RestController


    class FinalizaPedidoController {


    @Transactional


    @PostMapping(“/api/pedidos/finaliza”)


    public PedidoResponse finaliza(@RequestBody PedidoRequest request) {



    // efetua pagamento no gateway


    // dá baixa no estoque


    // atualiza pedido


    // envia email de confirmação


    // gera nota fiscal


    return new PedidoResponse(pedido, Status.CONFIRMADO);


    }


    }

    View Slide

  66. @RestController


    class FinalizaPedidoController {


    @Transactional


    @PostMapping(“/api/pedidos/finaliza”)


    public PedidoResponse finaliza(@RequestBody PedidoRequest request) {



    // efetua pagamento no gateway


    // dá baixa no estoque


    // atualiza pedido


    // envia email de confirmação


    // gera nota fiscal


    return new PedidoResponse(pedido, Status.CONFIRMADO);


    }


    }

    View Slide

  67. @RestController


    class FinalizaPedidoController {


    @Transactional


    @PostMapping(“/api/pedidos/finaliza”)


    public PedidoResponse finaliza(@RequestBody PedidoRequest request) {



    // efetua pagamento no gateway


    // dá baixa no estoque


    // atualiza pedido


    // envia email de confirmação


    // gera nota fiscal


    return new PedidoResponse(pedido, Status.CONFIRMADO);


    }


    }

    View Slide

  68. @RestController


    class FinalizaPedidoController {


    @Transactional


    @PostMapping(“/api/pedidos/finaliza”)


    public PedidoResponse finaliza(@RequestBody PedidoRequest request) {



    // efetua pagamento no gateway


    // dá baixa no estoque


    // atualiza pedido


    // envia email de confirmação


    // gera nota fiscal


    return new PedidoResponse(pedido, Status.CONFIRMADO);


    }


    }

    View Slide

  69. @RestController


    class FinalizaPedidoController {


    @Transactional


    @PostMapping(“/api/pedidos/finaliza”)


    public PedidoResponse finaliza(@RequestBody PedidoRequest request) {



    // efetua pagamento no gateway


    // dá baixa no estoque


    // atualiza pedido


    // envia email de confirmação


    // gera nota fiscal


    return new PedidoResponse(pedido, Status.CONFIRMADO);


    }


    }

    View Slide

  70. @RestController


    class FinalizaPedidoController {


    @Transactional


    @PostMapping(“/api/pedidos/finaliza”)


    public PedidoResponse finaliza(@RequestBody PedidoRequest request) {



    // efetua pagamento no gateway


    // dá baixa no estoque


    // atualiza pedido


    // envia email de confirmação


    // gera nota fiscal


    return new PedidoResponse(pedido, Status.CONFIRMADO);


    }


    }

    View Slide

  71. @RestController


    class FinalizaPedidoController {


    @Transactional


    @PostMapping(“/api/pedidos/finaliza”)


    public PedidoResponse finaliza(@RequestBody PedidoRequest request) {



    // efetua pagamento no gateway


    // dá baixa no estoque


    // atualiza pedido


    // envia email de confirmação


    // gera nota fiscal


    return new PedidoResponse(pedido, Status.CONFIRMADO);


    }


    }

    View Slide

  72. @RestController


    class FinalizaPedidoController {


    @Transactional


    @PostMapping(“/api/pedidos/finaliza”)


    public PedidoResponse finaliza(@RequestBody PedidoRequest request) {



    // efetua pagamento no gateway


    // dá baixa no estoque


    // atualiza pedido


    // envia email de confirmação


    // gera nota fiscal


    return new PedidoResponse(pedido, Status.CONFIRMADO);


    }


    }

    View Slide

  73. @RestController


    class FinalizaPedidoController {


    @Transactional


    @PostMapping(“/api/pedidos/finaliza”)


    public PedidoResponse finaliza(@RequestBody PedidoRequest request) {



    // efetua pagamento no gateway


    // dá baixa no estoque


    // atualiza pedido


    // envia email de confirmação


    // gera nota fiscal


    return new PedidoResponse(pedido, Status.CONFIRMADO);


    }


    }

    View Slide

  74. @RestController


    class FinalizaPedidoController {


    @Transactional


    @PostMapping(“/api/pedidos/finaliza”)


    public PedidoResponse finaliza(@RequestBody PedidoRequest request) {



    // efetua pagamento no gateway


    // dá baixa no estoque


    // atualiza pedido


    // envia email de confirmação


    // gera nota fiscal


    return new PedidoResponse(pedido, Status.CONFIRMADO);


    }


    }

    View Slide

  75. @RestController


    class FinalizaPedidoController {


    @Transactional


    @PostMapping(“/api/pedidos/finaliza”)


    public PedidoResponse finaliza(@RequestBody PedidoRequest request) {



    // efetua pagamento no gateway


    // dá baixa no estoque


    // atualiza pedido


    // envia email de confirmação


    // gera nota fiscal


    return new PedidoResponse(pedido, Status.CONFIRMADO);


    }


    }

    View Slide

  76. @RestController


    View Slide

  77. navegador
    servidor db

    View Slide

  78. navegador
    servidor db

    View Slide

  79. navegador
    servidor db

    View Slide

  80. se a execução é custosa então
    ela é um possível gargalo…

    View Slide

  81. View Slide

  82. CACHE

    View Slide

  83. PROCESSAMENTO
    ASSINCRONO
    CACHE

    View Slide

  84. BALANCEAMENTO
    DE CARGA
    CACHE
    PROCESSAMENTO
    ASSINCRONO

    View Slide

  85. CACHE
    BALANCEAMENTO
    DE CARGA
    PROCESSAMENTO
    ASSINCRONO

    View Slide

  86. “a gente
    joga numa
    FILA ! ”

    View Slide

  87. Quando falamos de
    fi
    la…

    View Slide

  88. 4 3 2
    QUEUE (
    fi
    la)

    View Slide

  89. 4 3 2
    5
    QUEUE (
    fi
    la)

    View Slide

  90. 4 3 2
    5
    enqueue
    QUEUE (
    fi
    la)

    View Slide

  91. 4 3 2
    5
    1
    enqueue
    QUEUE (
    fi
    la)

    View Slide

  92. 4 3 2
    5
    1
    enqueue
    dequeue
    QUEUE (
    fi
    la)

    View Slide

  93. 4 3 2
    5
    1
    enqueue
    dequeue
    QUEUE (
    fi
    la)
    FIFO: First-in, First-out

    View Slide

  94. No mundo enterprise…

    View Slide

  95. QUEUE
    (no mundo enterprise)

    View Slide

  96. 1002 1001
    QUEUE
    (no mundo enterprise)

    View Slide

  97. 1002 1001
    (message queue)
    QUEUE
    (no mundo enterprise)

    View Slide

  98. 1002 1001
    3506
    QUEUE
    (no mundo enterprise)
    (message queue)

    View Slide

  99. 1002 1001
    3506
    QUEUE
    (no mundo enterprise)
    (message)
    (message queue)

    View Slide

  100. 1002 1001
    producer
    QUEUE
    (no mundo enterprise)
    (message queue)

    View Slide

  101. 1002 1001
    producer
    1000
    QUEUE
    (no mundo enterprise)
    (message queue)

    View Slide

  102. 1002 1001
    producer
    consumer
    QUEUE
    (no mundo enterprise)
    (message queue)

    View Slide

  103. Ou seja…

    View Slide

  104. navegador
    servidor db

    View Slide

  105. navegador
    servidor db
    X

    View Slide

  106. navegador
    servidor db
    fi
    la

    View Slide

  107. navegador
    servidor db
    fi
    la

    View Slide

  108. navegador
    servidor db
    fi
    la

    View Slide

  109. navegador
    servidor db
    fi
    la

    View Slide

  110. navegador
    servidor db
    fi
    la

    View Slide

  111. Banco de dados

    relacional

    View Slide

  112. precisamos de
    uma tabela…

    View Slide

  113. Pedidos

    View Slide

  114. Para isso…

    View Slide

  115. @RestController


    class FinalizaPedidoController {


    @Transactional


    @PostMapping(“/api/pedidos/finaliza”)


    public PedidoResponse finaliza(@RequestBody PedidoRequest request) {



    // efetua pagamento no gateway


    // dá baixa no estoque


    // atualiza pedido


    // envia email de confirmação


    // gera nota fiscal


    return new PedidoResponse(pedido, Status.CONFIRMADO);


    }


    }

    View Slide

  116. @RestController


    class FinalizaPedidoController {


    @Transactional


    @PostMapping(“/api/pedidos/finaliza”)


    public PedidoResponse finaliza(@RequestBody PedidoRequest request) {



    // efetua pagamento no gateway


    // dá baixa no estoque


    // atualiza pedido


    // envia email de confirmação


    // gera nota fiscal


    return new PedidoResponse(pedido, Status.CONFIRMADO);


    }


    }

    View Slide

  117. @RestController


    class FinalizaPedidoController {


    private PedidoRepository repository;


    @Transactional


    @PostMapping(“/api/pedidos/finaliza”)


    public PedidoResponse finaliza(@RequestBody PedidoRequest request) {


    Pedido pedido = request.toModel();


    pedido.setStatus(Status.PENDENTE);



    repository.save(pedido);



    return new PedidoResponse(request, Status.PENDENTE);


    }


    }

    View Slide

  118. @RestController


    class FinalizaPedidoController {


    private PedidoRepository repository;


    @Transactional


    @PostMapping(“/api/pedidos/finaliza”)


    public PedidoResponse finaliza(@RequestBody PedidoRequest request) {


    Pedido pedido = request.toModel();


    pedido.setStatus(Status.PENDENTE);



    repository.save(pedido);



    return new PedidoResponse(request, Status.PENDENTE);


    }


    }

    View Slide

  119. @RestController


    class FinalizaPedidoController {


    private PedidoRepository repository;


    @Transactional


    @PostMapping(“/api/pedidos/finaliza”)


    public PedidoResponse finaliza(@RequestBody PedidoRequest request) {


    Pedido pedido = request.toModel();


    pedido.setStatus(Status.PENDENTE);



    repository.save(pedido);



    return new PedidoResponse(request, Status.PENDENTE);


    }


    }

    View Slide

  120. @RestController


    class FinalizaPedidoController {


    private PedidoRepository repository;


    @Transactional


    @PostMapping(“/api/pedidos/finaliza”)


    public PedidoResponse finaliza(@RequestBody PedidoRequest request) {


    Pedido pedido = request.toModel();


    pedido.setStatus(Status.PENDENTE);



    repository.save(pedido);



    return new PedidoResponse(request, Status.PENDENTE);


    }


    }

    View Slide

  121. @RestController


    class FinalizaPedidoController {


    private PedidoRepository repository;


    @Transactional


    @PostMapping(“/api/pedidos/finaliza”)


    public PedidoResponse finaliza(@RequestBody PedidoRequest request) {


    Pedido pedido = request.toModel();


    pedido.setStatus(Status.PENDENTE);



    repository.save(pedido);



    return new PedidoResponse(request, Status.PENDENTE);


    }


    }

    View Slide

  122. @RestController


    class FinalizaPedidoController {


    private PedidoRepository repository;


    @Transactional


    @PostMapping(“/api/pedidos/finaliza”)


    public PedidoResponse finaliza(@RequestBody PedidoRequest request) {


    Pedido pedido = request.toModel();


    pedido.setStatus(Status.PENDENTE);



    repository.save(pedido);



    return new PedidoResponse(request, Status.PENDENTE);


    }


    }
    “Estamos processando
    seu pedido"

    View Slide

  123. @RestController


    class FinalizaPedidoController {


    private PedidoRepository repository;


    @Transactional


    @PostMapping(“/api/pedidos/finaliza”)


    public PedidoResponse finaliza(@RequestBody PedidoRequest request) {


    Pedido pedido = request.toModel();


    pedido.setStatus(Status.PENDENTE);



    repository.save(pedido);



    return new PedidoResponse(request, Status.PENDENTE);


    }


    }

    View Slide

  124. db
    servidor
    navegador

    View Slide

  125. db
    servidor
    navegador
    fi
    la

    View Slide

  126. db
    servidor
    navegador
    fi
    la

    View Slide

  127. db
    servidor
    navegador
    requisição
    fi
    la

    View Slide

  128. db
    servidor
    navegador
    requisição
    INSERT
    fi
    la

    View Slide

  129. db
    servidor
    navegador
    requisição
    INSERT
    fi
    la
    resposta

    View Slide

  130. e em algum momento um
    processo consumiria a
    fi
    la…

    View Slide

  131. db
    servidor
    navegador
    requisição
    INSERT
    fi

    View Slide

  132. quem executa?
    db
    servidor
    navegador
    requisição
    INSERT
    fi

    View Slide

  133. View Slide

  134. db
    servidor
    navegador
    requisição
    INSERT
    fi
    la

    View Slide

  135. db
    servidor
    navegador
    requisição
    INSERT
    fi
    la

    View Slide

  136. db
    servidor
    navegador
    requisição
    INSERT
    fi
    la

    View Slide

  137. db
    servidor
    navegador
    requisição
    INSERT
    fi
    la

    View Slide

  138. e a vantagem?

    View Slide

  139. db
    servidor
    navegador
    requisição
    INSERT
    fi
    la

    View Slide

  140. db
    servidor
    requisição
    INSERT
    fi
    la

    View Slide

  141. db
    servidor
    requisição
    INSERT
    fi
    la

    View Slide

  142. db
    servidor
    requisição
    INSERT
    fi
    la

    View Slide

  143. db
    servidor
    requisição
    INSERT
    x

    View Slide

  144. INSERT

    View Slide

  145. INSERT

    View Slide

  146. Mas antes…

    View Slide

  147. Como agendar
    tarefas com
    Spring Boot?

    View Slide

  148. @Component


    public class OneJob {


    @Scheduled(fixedDelay = 60_000)


    public void runQuiteOften() {


    // lógica do job vai aqui


    }


    }

    View Slide

  149. @Component


    public class OneJob {


    @Scheduled(fixedDelay = 60_000)


    public void runQuiteOften() {


    // lógica do job vai aqui


    }


    }

    View Slide

  150. @Component


    public class OneJob {


    @Scheduled(fixedDelay = 60_000)


    public void runQuiteOften() {


    // lógica do job vai aqui


    }


    }

    View Slide

  151. @Component


    public class OneJob {


    @Scheduled(fixedDelay = 60_000)


    public void runQuiteOften() {


    // lógica do job vai aqui


    }


    }

    View Slide

  152. @Component


    public class OneJob {




    public void runQuiteOften() {


    // lógica do job vai aqui


    }


    }

    View Slide

  153. @Component


    public class OneJob {


    @Scheduled


    public void runQuiteOften() {


    // lógica do job vai aqui


    }


    }

    View Slide

  154. @Component


    public class OneJob {


    @Scheduled(fixedDelay = 60_000)


    public void runQuiteOften() {


    // lógica do job vai aqui


    }


    }

    View Slide

  155. @Component


    public class OneJob {


    @Scheduled(fixedDelay = 60_000)


    public void runQuiteOften() {


    // lógica do job vai aqui


    }


    }

    View Slide

  156. E nossa tarefa?

    View Slide

  157. db
    servidor
    requisição
    INSERT

    View Slide

  158. db
    servidor
    requisição
    INSERT
    x

    View Slide

  159. @Component


    public class FinalizaPedidoJob {


    private PedidoRepository repository;


    @Scheduled(fixedDelay = 60_000)


    public void execute() {


    List pedidos = repository.findAllByStatus(Status.PENDENTE);


    pedidos.forEach(pedido -> {


    // efetua pagamento no gateway


    // dá baixa no estoque


    // atualiza pedido


    // envia email de confirmação


    // gera nota fiscal


    pedido.setStatus(Status.CONFIRMADO);


    repository.save(pedido);


    });


    }


    }

    View Slide

  160. @Component


    public class FinalizaPedidoJob {


    private PedidoRepository repository;


    @Scheduled(fixedDelay = 60_000)


    public void execute() {


    List pedidos = repository.findAllByStatus(Status.PENDENTE);


    pedidos.forEach(pedido -> {


    // efetua pagamento no gateway


    // dá baixa no estoque


    // atualiza pedido


    // envia email de confirmação


    // gera nota fiscal


    pedido.setStatus(Status.CONFIRMADO);


    repository.save(pedido);


    });


    }


    }

    View Slide

  161. @Component


    public class FinalizaPedidoJob {


    private PedidoRepository repository;


    @Scheduled(fixedDelay = 60_000)


    public void execute() {


    List pedidos = repository.findAllByStatus(Status.PENDENTE);


    pedidos.forEach(pedido -> {


    // efetua pagamento no gateway


    // dá baixa no estoque


    // atualiza pedido


    // envia email de confirmação


    // gera nota fiscal


    pedido.setStatus(Status.CONFIRMADO);


    repository.save(pedido);


    });


    }


    }

    View Slide

  162. @Component


    public class FinalizaPedidoJob {


    private PedidoRepository repository;


    @Scheduled(fixedDelay = 60_000)


    public void execute() {


    List pedidos = repository.findAllByStatus(Status.PENDENTE);


    pedidos.forEach(pedido -> {


    // efetua pagamento no gateway


    // dá baixa no estoque


    // atualiza pedido


    // envia email de confirmação


    // gera nota fiscal


    pedido.setStatus(Status.CONFIRMADO);


    repository.save(pedido);


    });


    }


    }

    View Slide

  163. @Component


    public class FinalizaPedidoJob {


    private PedidoRepository repository;


    @Scheduled(fixedDelay = 60_000)


    public void execute() {


    List pedidos = repository.findAllByStatus(Status.PENDENTE);


    pedidos.forEach(pedido -> {


    // efetua pagamento no gateway


    // dá baixa no estoque


    // atualiza pedido


    // envia email de confirmação


    // gera nota fiscal


    pedido.setStatus(Status.CONFIRMADO);


    repository.save(pedido);


    });


    }


    }

    View Slide

  164. @Component


    public class FinalizaPedidoJob {


    private PedidoRepository repository;


    @Scheduled(fixedDelay = 60_000)


    public void execute() {


    List pedidos = repository.findAllByStatus(Status.PENDENTE);


    pedidos.forEach(pedido -> {


    // efetua pagamento no gateway


    // dá baixa no estoque


    // atualiza pedido


    // envia email de confirmação


    // gera nota fiscal


    pedido.setStatus(Status.CONFIRMADO);


    repository.save(pedido);


    });


    }


    }

    View Slide

  165. @Component


    public class FinalizaPedidoJob {


    private PedidoRepository repository;


    @Scheduled(fixedDelay = 60_000)


    public void execute() {


    List pedidos = repository.findAllByStatus(Status.PENDENTE);


    pedidos.forEach(pedido -> {


    // efetua pagamento no gateway


    // dá baixa no estoque


    // atualiza pedido


    // envia email de confirmação


    // gera nota fiscal


    pedido.setStatus(Status.CONFIRMADO);


    repository.save(pedido);


    });


    }


    }

    View Slide

  166. @Repository


    public interface PedidoRepository extends JpaRepository {


    public List findAllByStatus(Status status);


    }

    View Slide

  167. @Repository


    public interface PedidoRepository extends JpaRepository {


    public List findAllByStatus(Status status);


    }

    View Slide

  168. select p.*


    from pedido p


    where p.status = 'PENDENTE'


    order by p.criado_em asc


    View Slide

  169. ID STATUS
    1001 PENDENTE
    1002 PENDENTE
    1003 PENDENTE
    1004 PENDENTE

    View Slide

  170. INSERT

    View Slide

  171. ID STATUS
    1001 CONFIRMADO
    1002 CONFIRMADO
    1003 CONFIRMADO
    1004 CONFIRMADO

    View Slide

  172. Uhuull!

    View Slide

  173. E SE…

    View Slide

  174. …rodarmos a
    aplicação em
    cluster?

    View Slide

  175. View Slide

  176. View Slide

  177. View Slide

  178. View Slide

  179. ID STATUS
    1001 PENDENTE
    1002 PENDENTE
    1003 PENDENTE
    1004 PENDENTE

    View Slide

  180. ID STATUS
    1001 PENDENTE
    1002 PENDENTE
    1003 PENDENTE
    1004 PENDENTE

    View Slide

  181. ID STATUS
    1001 PENDENTE
    1002 PENDENTE
    1003 PENDENTE
    1004 PENDENTE

    View Slide

  182. ID STATUS
    1001 CONFIRMADO
    1002 PENDENTE
    1003 PENDENTE
    1004 PENDENTE

    View Slide

  183. ID STATUS
    1001 CONFIRMADO
    1002 PENDENTE
    1003 PENDENTE
    1004 PENDENTE

    View Slide

  184. ID STATUS
    1001 CONFIRMADO
    1002 CONFIRMADO
    1003 PENDENTE
    1004 PENDENTE

    View Slide

  185. ID STATUS
    1001 CONFIRMADO
    1002 CONFIRMADO
    1003 PENDENTE
    1004 PENDENTE

    View Slide

  186. ID STATUS
    1001 CONFIRMADO
    1002 CONFIRMADO
    1003 CONFIRMADO
    1004 PENDENTE

    View Slide

  187. ID STATUS
    1001 CONFIRMADO
    1002 CONFIRMADO
    1003 CONFIRMADO
    1004 PENDENTE

    View Slide

  188. ID STATUS
    1001 CONFIRMADO
    1002 CONFIRMADO
    1003 CONFIRMADO
    1004 CONFIRMADO

    View Slide

  189. ID STATUS
    1001 CONFIRMADO
    1002 CONFIRMADO
    1003 CONFIRMADO
    1004 CONFIRMADO

    View Slide

  190. View Slide

  191. ID STATUS
    1001 PENDENTE
    1002 PENDENTE
    1003 PENDENTE
    1004 PENDENTE

    View Slide

  192. ID STATUS
    1001 PENDENTE
    1002 PENDENTE
    1003 PENDENTE
    1004 PENDENTE

    View Slide

  193. ID STATUS
    1001 CONFIRMADO
    1002 PENDENTE
    1003 PENDENTE
    1004 PENDENTE

    View Slide

  194. ID STATUS
    1001 CONFIRMADO
    1002 PENDENTE
    1003 PENDENTE
    1004 PENDENTE
    2x

    View Slide

  195. ID STATUS
    1001 CONFIRMADO
    1002 CONFIRMADO
    1003 PENDENTE
    1004 PENDENTE
    2x

    View Slide

  196. ID STATUS
    1001 CONFIRMADO
    1002 CONFIRMADO
    1003 PENDENTE
    1004 PENDENTE
    2x
    2x

    View Slide

  197. ID STATUS
    1001 CONFIRMADO
    1002 CONFIRMADO
    1003 CONFIRMADO
    1004 PENDENTE
    2x
    2x

    View Slide

  198. ID STATUS
    1001 CONFIRMADO
    1002 CONFIRMADO
    1003 CONFIRMADO
    1004 PENDENTE
    2x
    2x
    2x

    View Slide

  199. ID STATUS
    1001 CONFIRMADO
    1002 CONFIRMADO
    1003 CONFIRMADO
    1004 CONFIRMADO
    2x
    2x
    2x

    View Slide

  200. ID STATUS
    1001 CONFIRMADO
    1002 CONFIRMADO
    1003 CONFIRMADO
    1004 CONFIRMADO
    2x
    2x
    2x
    2x

    View Slide

  201. Oops!

    View Slide

  202. o desenho da solução
    deve ser pensado para
    multi-threaded
    * desenho e implementação
    *

    View Slide

  203. “Fácil! Vamos

    LOCKAR o
    método do Job”

    View Slide

  204. Synchronized?

    View Slide

  205. @Component


    public class FinalizaPedidoJob {


    @Scheduled(...)


    public void execute() {


    // executa lógica aqui


    }


    }

    View Slide

  206. @Component


    public class FinalizaPedidoJob {


    @Scheduled(...)


    public synchronized void execute() {


    // executa lógica aqui


    }


    }

    View Slide

  207. View Slide

  208. View Slide

  209. View Slide

  210. View Slide

  211. @Component


    View Slide

  212. Distributed Lock?

    View Slide

  213. @Scheduled(...)


    public void execute() {


    if (isLeader()) {


    // executa lógica aqui


    }


    }

    View Slide

  214. @Scheduled(...)


    public void execute() {


    if (isLeader()) {


    // executa lógica aqui


    }


    }

    View Slide

  215. View Slide

  216. View Slide

  217. View Slide

  218. View Slide

  219. View Slide

  220. View Slide

  221. View Slide

  222. View Slide

  223. View Slide

  224. View Slide

  225. View Slide

  226. Não!

    View Slide

  227. Que tal…

    View Slide

  228. Banco de dados

    relacional

    View Slide

  229. View Slide

  230. @Repository


    public interface PedidoRepository extends JpaRepository {




    public List findAllByStatus(Status status);


    }

    View Slide

  231. @Repository


    public interface PedidoRepository extends JpaRepository {


    @Lock(LockModeType.PESSIMISTIC_WRITE)


    public List findAllByStatus(Status status);


    }

    View Slide

  232. select p.*


    from pedido p


    where p.status = 'PENDENTE'


    order by p.criado_em asc

    View Slide

  233. select p.*


    from pedido p


    where p.status = 'PENDENTE'


    order by p.criado_em asc

    for update

    View Slide

  234. ID STATUS
    1001 PENDENTE
    1002 PENDENTE
    1003 PENDENTE
    ... ...

    View Slide

  235. ID STATUS
    1001 PENDENTE
    1002 PENDENTE
    1003 PENDENTE
    ... ...

    View Slide

  236. ID STATUS
    1001 PENDENTE
    1002 PENDENTE
    1003 PENDENTE
    ... ...

    View Slide

  237. ID STATUS
    1001 PENDENTE
    1002 PENDENTE
    1003 PENDENTE
    ... ...

    View Slide

  238. ID STATUS
    1001 CONFIRMADO
    1002 PENDENTE
    1003 PENDENTE
    ... ...

    View Slide

  239. ID STATUS
    1001 CONFIRMADO
    1002 PENDENTE
    1003 PENDENTE
    ... ...

    View Slide

  240. ID STATUS
    1001 CONFIRMADO
    1002 PENDENTE
    1003 PENDENTE
    ... ...

    View Slide

  241. ID STATUS
    1001 CONFIRMADO
    1002 PENDENTE
    1003 PENDENTE
    ... ...

    View Slide

  242. ID STATUS
    1001 CONFIRMADO
    1002 PENDENTE
    1003 PENDENTE
    ... ...

    View Slide

  243. ID STATUS
    1001 CONFIRMADO
    1002 PENDENTE
    1003 PENDENTE
    ... ...

    View Slide

  244. ID STATUS
    1001 CONFIRMADO
    1002 CONFIRMADO
    1003 PENDENTE
    ... ...

    View Slide

  245. ID STATUS
    1001 CONFIRMADO
    1002 CONFIRMADO
    1003 PENDENTE
    ... ...

    View Slide

  246. ID STATUS
    1001 CONFIRMADO
    1002 CONFIRMADO
    1003 PENDENTE
    ... ...

    View Slide

  247. ID STATUS
    1001 CONFIRMADO
    1002 CONFIRMADO
    1003 PENDENTE
    ... ...

    View Slide

  248. ID STATUS
    1001 CONFIRMADO
    1002 CONFIRMADO
    1003 CONFIRMADO
    ... ...

    View Slide

  249. SIM!

    View Slide

  250. MAS…

    View Slide

  251. O problema do
    FOR UPDATE é
    que não escala!

    View Slide

  252. View Slide

  253. View Slide

  254. View Slide

  255. Quando queremos…

    View Slide

  256. View Slide

  257. Para isso…

    View Slide

  258. 9630 9631
    QUEUE (
    fi
    la)
    9629

    View Slide

  259. 9630 9631
    QUEUE (
    fi
    la)
    producer
    9629
    produz:

    1000 itens/min

    View Slide

  260. 9630 9631
    QUEUE (
    fi
    la)
    producer
    consumer
    9629
    produz:

    1000 itens/min consume:

    600 itens/min

    View Slide

  261. 9630 9631
    QUEUE (
    fi
    la)
    producer
    consumer
    9629
    produz:

    1000 itens/min
    consumer
    consume:

    400 itens/min
    consume:

    600 itens/min

    View Slide

  262. 9630 9631
    QUEUE (
    fi
    la)
    producer
    consumer
    9629
    produz:

    1000 itens/min
    consumer
    consume:

    400 itens/min
    consume:

    600 itens/min

    View Slide

  263. View Slide

  264. Não!

    View Slide

  265. Que tal…

    View Slide

  266. Banco de dados

    relacional

    View Slide

  267. @Repository


    public interface PedidoRepository extends JpaRepository {


    @QueryHints({


    @QueryHint(


    name = "javax.persistence.lock.timeout",


    value = LockOptions.SKIP_LOCKED) // org.hibernate.LockOptions


    })


    @Lock(LockModeType.PESSIMISTIC_WRITE)


    public List findAllByStatus(Status status);


    }

    View Slide

  268. @Repository


    public interface PedidoRepository extends JpaRepository {


    @QueryHints({


    @QueryHint(


    name = "javax.persistence.lock.timeout",


    value = LockOptions.SKIP_LOCKED) // org.hibernate.LockOptions


    })


    @Lock(LockModeType.PESSIMISTIC_WRITE)


    public List findAllByStatus(Status status);


    }

    View Slide

  269. select p.*


    from pedido p


    where p.status = 'PENDENTE'


    order by p.criado_em asc

    for update

    View Slide

  270. select p.*


    from pedido p


    where p.status = 'PENDENTE'


    order by p.criado_em asc

    for update skip locked

    View Slide

  271. ID STATUS
    1001 PENDENTE
    1002 PENDENTE
    1003 PENDENTE
    ... ...

    View Slide

  272. ID STATUS
    1001 PENDENTE
    1002 PENDENTE
    1003 PENDENTE
    ... ...

    View Slide

  273. ID STATUS
    1001 PENDENTE
    1002 PENDENTE
    1003 PENDENTE
    ... ...

    View Slide

  274. ID STATUS
    1001 PENDENTE
    1002 PENDENTE
    1003 PENDENTE
    ... ...

    View Slide

  275. ID STATUS
    1001 PENDENTE
    1002 PENDENTE
    1003 PENDENTE
    ... ...

    View Slide

  276. ID STATUS
    1001 PENDENTE
    1002 PENDENTE
    1003 PENDENTE
    ... ...

    View Slide

  277. ID STATUS
    1001 PENDENTE
    1002 PENDENTE
    1003 PENDENTE
    ... ...

    View Slide

  278. ID STATUS
    1001 CONFIRMADO
    1002 CONFIRMADO
    1003 PENDENTE
    ... ...

    View Slide

  279. ID STATUS
    1001 CONFIRMADO
    1002 CONFIRMADO
    1003 PENDENTE
    ... ...

    View Slide

  280. ID STATUS
    1001 CONFIRMADO
    1002 CONFIRMADO
    1003 PENDENTE
    ... ...

    View Slide

  281. ID STATUS
    1001 CONFIRMADO
    1002 CONFIRMADO
    1003 PENDENTE
    ... ...

    View Slide

  282. ID STATUS
    1001 CONFIRMADO
    1002 CONFIRMADO
    1003 PENDENTE
    ... ...

    View Slide

  283. ID STATUS
    1001 CONFIRMADO
    1002 CONFIRMADO
    1003 PENDENTE
    ... ...

    View Slide

  284. ID STATUS
    1001 CONFIRMADO
    1002 CONFIRMADO
    1003 PENDENTE
    ... ...

    View Slide

  285. ID STATUS
    1001 CONFIRMADO
    1002 CONFIRMADO
    1003 PENDENTE
    ... ...

    View Slide

  286. Ou seja…

    View Slide

  287. ID STATUS
    1001 PENDENTE
    1002 PENDENTE
    1003 PENDENTE
    1004 PENDENTE

    View Slide

  288. ID STATUS
    1001 PENDENTE
    1002 PENDENTE
    1003 PENDENTE
    1004 PENDENTE

    View Slide

  289. SIM!

    View Slide

  290. E isso escala?

    View Slide

  291. single-threaded funciona bem…

    View Slide

  292. single-threaded funciona bem…
    https://www.pgcon.org/2016/schedule/track/Applications/929.en.html

    View Slide

  293. multi-threaded com FOR UPDATE…

    View Slide

  294. multi-threaded com FOR UPDATE…
    https://www.pgcon.org/2016/schedule/track/Applications/929.en.html

    View Slide

  295. multi-threaded com SKIP LOCKED…

    View Slide

  296. multi-threaded com SKIP LOCKED…
    https://www.pgcon.org/2016/schedule/track/Applications/929.en.html

    View Slide

  297. UFA!

    View Slide

  298. Mas calma ae que tem mais…

    View Slide

  299. Listen / Notify

    View Slide

  300. View Slide

  301. View Slide

  302. View Slide

  303. View Slide

  304. View Slide

  305. View Slide

  306. View Slide

  307. View Slide

  308. View Slide

  309. View Slide

  310. View Slide

  311. View Slide

  312. View Slide

  313. View Slide

  314. View Slide

  315. View Slide

  316. Publisher

    View Slide

  317. Publisher
    Subscriber

    View Slide

  318. Publisher
    Subscriber
    Topic

    View Slide

  319. Broker
    Publisher
    Subscriber
    Topic

    View Slide

  320. Pub/Sub

    View Slide

  321. View Slide

  322. View Slide

  323. View Slide

  324. View Slide

  325. View Slide

  326. View Slide

  327. View Slide

  328. View Slide

  329. View Slide

  330. View Slide

  331. View Slide

  332. Não!

    View Slide

  333. Que tal…

    View Slide

  334. Banco de dados

    relacional

    View Slide

  335. Listen
    Notify

    View Slide

  336. View Slide

  337. View Slide

  338. View Slide

  339. View Slide

  340. Para enviar uma
    mensagem…

    View Slide

  341. pg_notify()
    NOTIFY is a utility command for sending noti
    fi
    cations to other sessions
    connected to the same database listening on a channel speci
    fi
    ed with
    the LISTEN command.

    View Slide

  342. pg_notify(, )

    View Slide

  343. pg_notify(, )

    View Slide

  344. pg_notify(, )

    View Slide

  345. pg_notify(, )

    View Slide

  346. pg_notify(

    ‘pedidos-finalizados’,


    ‘{“id”: 42, “nome”: “iPhone 13”}’

    )

    View Slide

  347. pg_notify(

    ‘pedidos-finalizados’,


    ‘{“id”: 42, “nome”: “iPhone 13”}’

    )

    View Slide

  348. pg_notify(

    ‘pedidos-finalizados’,


    ‘{“id”: 42, “nome”: “iPhone 13”}’

    )

    View Slide

  349. Enquanto para
    receber as
    mensagens…

    View Slide

  350. LISTEN
    LISTEN is a utility command which registers the current session as a
    listener on the named channel.

    View Slide

  351. LISTEN

    View Slide

  352. LISTEN

    View Slide

  353. LISTEN

    View Slide

  354. LISTEN ‘pedidos-finalizados’

    View Slide

  355. LISTEN ‘pedidos-finalizados’

    View Slide

  356. E onde ele pode
    ser útil?

    View Slide

  357. @Component


    public class FinalizaPedidoJob {


    private PedidoRepository repository;


    @Scheduled(fixedDelay = 60_000)


    public void execute() {


    List pedidos = repository.findAllByStatus(Status.PENDENTE);


    pedidos.forEach(pedido -> {


    // efetua pagamento no gateway


    // dá baixa no estoque


    // atualiza pedido


    // envia email de confirmação


    // gera nota fiscal




    pedido.setStatus(Status.CONFIRMADO);


    repository.save(pedido);


    });


    }


    }

    View Slide

  358. @Component


    public class FinalizaPedidoJob {


    private PedidoRepository repository;


    @Scheduled(fixedDelay = 60_000)


    public void execute() {


    List pedidos = repository.findAllByStatus(Status.PENDENTE);


    pedidos.forEach(pedido -> {


    // efetua pagamento no gateway


    // dá baixa no estoque


    // atualiza pedido


    // envia email de confirmação


    // gera nota fiscal




    pedido.setStatus(Status.CONFIRMADO);


    repository.save(pedido);


    });


    }


    }

    View Slide

  359. @Component


    public class FinalizaPedidoJob {


    private PedidoRepository repository;


    @Scheduled(fixedDelay = 60_000)


    public void execute() {


    List pedidos = repository.findAllByStatus(Status.PENDENTE);


    pedidos.forEach(pedido -> {


    // efetua pagamento no gateway


    // dá baixa no estoque


    // atualiza pedido


    // envia email de confirmação


    // gera nota fiscal




    pedido.setStatus(Status.CONFIRMADO);


    repository.save(pedido);


    });


    }


    }

    View Slide

  360. @Component


    public class FinalizaPedidoJob {


    private PedidoRepository repository;


    @Scheduled(fixedDelay = 60_000)


    public void execute() {


    List pedidos = repository.findAllByStatus(Status.PENDENTE);


    pedidos.forEach(pedido -> {


    // efetua pagamento no gateway


    // dá baixa no estoque


    // atualiza pedido


    // envia email de confirmação


    // gera nota fiscal




    pedido.setStatus(Status.CONFIRMADO);


    repository.save(pedido);


    });


    }


    }

    View Slide

  361. View Slide

  362. INSERT
    PENDENTE
    PENDENTE
    PENDENTE

    View Slide

  363. INSERT
    PENDENTE
    PENDENTE
    PENDENTE

    View Slide

  364. INSERT
    PENDENTE
    PENDENTE
    PENDENTE

    View Slide

  365. INSERT
    PENDENTE
    PENDENTE
    PENDENTE

    View Slide

  366. INSERT
    CONFIRMADO
    CONFIRMADO
    PENDENTE

    View Slide

  367. INSERT
    CONFIRMADO
    CONFIRMADO
    PENDENTE

    View Slide

  368. @Component


    public class FinalizaPedidoJob {


    private PedidoRepository repository;


    @Scheduled(fixedDelay = 60_000)


    public void execute() {


    List pedidos = repository.findAllByStatus(Status.PENDENTE);


    pedidos.forEach(pedido -> {


    // efetua pagamento no gateway


    // dá baixa no estoque


    // atualiza pedido


    // envia email de confirmação


    // gera nota fiscal




    pedido.setStatus(Status.CONFIRMADO);


    repository.save(pedido);


    });


    }


    }

    View Slide

  369. @Component


    public class FinalizaPedidoJob {


    private PedidoRepository repository;


    @Scheduled(fixedDelay = 60_000)


    public void execute() {


    List pedidos = repository.findAllByStatus(Status.PENDENTE);


    pedidos.forEach(pedido -> {


    // efetua pagamento no gateway


    // dá baixa no estoque


    // atualiza pedido


    // envia email de confirmação


    // gera nota fiscal




    pedido.setStatus(Status.CONFIRMADO);


    repository.save(pedido);


    });


    }


    }

    View Slide

  370. @Component


    public class FinalizaPedidoJob {


    private PedidoRepository repository;


    @Scheduled(fixedDelay = 60_000)


    public void execute() {


    List pedidos = repository.findAllByStatus(Status.PENDENTE);


    pedidos.forEach(pedido -> {


    // efetua pagamento no gateway


    // dá baixa no estoque


    // atualiza pedido


    repository

    .pgNotify("pedidos-finalizados", pedido.toJson());




    pedido.setStatus(Status.CONFIRMADO);


    repository.save(pedido);


    });


    }


    }

    View Slide

  371. @Component


    public class FinalizaPedidoJob {


    private PedidoRepository repository;


    @Scheduled(fixedDelay = 60_000)


    public void execute() {


    List pedidos = repository.findAllByStatus(Status.PENDENTE);


    pedidos.forEach(pedido -> {


    // efetua pagamento no gateway


    // dá baixa no estoque


    // atualiza pedido


    repository

    .pgNotify("pedidos-finalizados", pedido.toJson());




    pedido.setStatus(Status.CONFIRMADO);


    repository.save(pedido);


    });


    }


    }

    View Slide

  372. @Component


    public class FinalizaPedidoJob {


    private PedidoRepository repository;


    @Scheduled(fixedDelay = 60_000)


    public void execute() {


    List pedidos = repository.findAllByStatus(Status.PENDENTE);


    pedidos.forEach(pedido -> {


    // efetua pagamento no gateway


    // dá baixa no estoque


    // atualiza pedido


    repository

    .pgNotify("pedidos-finalizados", pedido.toJson());




    pedido.setStatus(Status.CONFIRMADO);


    repository.save(pedido);


    });


    }


    }

    View Slide

  373. Para isso dar
    certo…

    View Slide

  374. INSERT
    PENDENTE
    PENDENTE
    PENDENTE

    View Slide

  375. INSERT
    PENDENTE
    PENDENTE
    PENDENTE

    View Slide

  376. INSERT
    PENDENTE
    PENDENTE
    PENDENTE

    View Slide

  377. INSERT
    PENDENTE
    PENDENTE
    PENDENTE

    View Slide

  378. INSERT
    PENDENTE
    PENDENTE
    PENDENTE

    View Slide

  379. INSERT
    PENDENTE
    LISTEN ‘pedidos-finalizados’
    LISTEN ‘pedidos-finalizados’
    PENDENTE
    PENDENTE

    View Slide

  380. INSERT
    PENDENTE
    LISTEN ‘pedidos-finalizados’
    LISTEN ‘pedidos-finalizados’
    pg_notify(

    ‘pedidos-finalizados’,


    ‘{“id”: 42, “nome”: ... }’

    )
    PENDENTE
    PENDENTE

    View Slide

  381. INSERT
    CONFIRMADO
    CONFIRMADO
    PENDENTE
    LISTEN ‘pedidos-finalizados’
    LISTEN ‘pedidos-finalizados’
    pg_notify(

    ‘pedidos-finalizados’,


    ‘{“id”: 42, “nome”: ... }’

    )

    View Slide

  382. E quem precisar
    escutar?

    View Slide

  383. INSERT
    CONFIRMADO
    CONFIRMADO
    PENDENTE
    LISTEN ‘pedidos-finalizados’
    LISTEN ‘pedidos-finalizados’
    pg_notify(

    View Slide

  384. try (Connection cn = new org.postgresql.Driver().connect(url, properties)) {


    cn.createStatement().execute(“LISTEN ‘pedidos-finalizados’");


    for (;;) {


    PGNotification[] ns = ((PGConnection) cn).getNotifications(0);


    if (ns != null) {


    for (PGNotification n : ns) {


    System.out.println("pid=%s, event=%s, payload=%s".formatted(

    n.getPID(), n.getName(), n.getParameter()


    ));


    // invoca logica de negocio


    }


    }


    break;


    }


    }

    View Slide

  385. try (Connection cn = new org.postgresql.Driver().connect(url, properties)) {


    cn.createStatement().execute(“LISTEN ‘pedidos-finalizados’");


    for (;;) {


    PGNotification[] ns = ((PGConnection) cn).getNotifications(0);


    if (ns != null) {


    for (PGNotification n : ns) {


    System.out.println("pid=%s, event=%s, payload=%s".formatted(

    n.getPID(), n.getName(), n.getParameter()


    ));


    // invoca logica de negocio


    }


    }


    break;


    }


    }

    View Slide

  386. try (Connection cn = new org.postgresql.Driver().connect(url, properties)) {


    cn.createStatement().execute(“LISTEN ‘pedidos-finalizados’");


    for (;;) {


    PGNotification[] ns = ((PGConnection) cn).getNotifications(0);


    if (ns != null) {


    for (PGNotification n : ns) {


    System.out.println("pid=%s, event=%s, payload=%s".formatted(

    n.getPID(), n.getName(), n.getParameter()


    ));


    // invoca logica de negocio


    }


    }


    break;


    }


    }

    View Slide

  387. try (Connection cn = new org.postgresql.Driver().connect(url, properties)) {


    cn.createStatement().execute(“LISTEN ‘pedidos-finalizados’");


    for (;;) {


    PGNotification[] ns = ((PGConnection) cn).getNotifications(0);


    if (ns != null) {


    for (PGNotification n : ns) {


    System.out.println("pid=%s, event=%s, payload=%s".formatted(

    n.getPID(), n.getName(), n.getParameter()


    ));


    // invoca logica de negocio


    }


    }


    break;


    }


    }
    Ouvindo um topico!

    View Slide

  388. try (Connection cn = new org.postgresql.Driver().connect(url, properties)) {


    cn.createStatement().execute(“LISTEN ‘pedidos-finalizados’");


    for (;;) {


    PGNotification[] ns = ((PGConnection) cn).getNotifications(0);


    if (ns != null) {


    for (PGNotification n : ns) {


    System.out.println("pid=%s, event=%s, payload=%s".formatted(

    n.getPID(), n.getName(), n.getParameter()


    ));


    // invoca logica de negocio


    }


    }


    break;


    }


    }

    View Slide

  389. try (Connection cn = new org.postgresql.Driver().connect(url, properties)) {


    cn.createStatement().execute(“LISTEN ‘pedidos-finalizados’");


    for (;;) {


    PGNotification[] ns = ((PGConnection) cn).getNotifications(0);


    if (ns != null) {


    for (PGNotification n : ns) {


    System.out.println("pid=%s, event=%s, payload=%s".formatted(

    n.getPID(), n.getName(), n.getParameter()


    ));


    // invoca logica de negocio


    }


    }


    break;


    }


    }

    View Slide

  390. try (Connection cn = new org.postgresql.Driver().connect(url, properties)) {


    cn.createStatement().execute(“LISTEN ‘pedidos-finalizados’");


    for (;;) {


    PGNotification[] ns = ((PGConnection) cn).getNotifications(0);


    if (ns != null) {


    for (PGNotification n : ns) {


    System.out.println("pid=%s, event=%s, payload=%s".formatted(

    n.getPID(), n.getName(), n.getParameter()


    ));


    // invoca logica de negocio


    }


    }


    break;


    }


    }
    Bloqueia

    FOREVER até receber
    novos eventos

    View Slide

  391. try (Connection cn = new org.postgresql.Driver().connect(url, properties)) {


    cn.createStatement().execute(“LISTEN ‘pedidos-finalizados’");


    for (;;) {


    PGNotification[] ns = ((PGConnection) cn).getNotifications(0);


    if (ns != null) {


    for (PGNotification n : ns) {


    System.out.println("pid=%s, event=%s, payload=%s".formatted(

    n.getPID(), n.getName(), n.getParameter()


    ));


    // invoca logica de negocio


    }


    }


    break;


    }


    }

    View Slide

  392. try (Connection cn = new org.postgresql.Driver().connect(url, properties)) {


    cn.createStatement().execute(“LISTEN ‘pedidos-finalizados’");


    for (;;) {


    PGNotification[] ns = ((PGConnection) cn).getNotifications(0);


    if (ns != null) {


    for (PGNotification n : ns) {


    System.out.println("pid=%s, event=%s, payload=%s".formatted(

    n.getPID(), n.getName(), n.getParameter()


    ));


    // invoca logica de negocio


    }


    }


    break;


    }


    }

    View Slide

  393. try (Connection cn = new org.postgresql.Driver().connect(url, properties)) {


    cn.createStatement().execute(“LISTEN ‘pedidos-finalizados’");


    for (;;) {


    PGNotification[] ns = ((PGConnection) cn).getNotifications(0);


    if (ns != null) {


    for (PGNotification n : ns) {


    System.out.println("pid=%s, event=%s, payload=%s".formatted(

    n.getPID(), n.getName(), n.getParameter()


    ));


    // invoca logica de negocio


    }


    }


    break;


    }


    }

    View Slide

  394. try (Connection cn = new org.postgresql.Driver().connect(url, properties)) {


    cn.createStatement().execute(“LISTEN ‘pedidos-finalizados’");


    for (;;) {


    PGNotification[] ns = ((PGConnection) cn).getNotifications(0);


    if (ns != null) {


    for (PGNotification n : ns) {


    System.out.println("pid=%s, event=%s, payload=%s".formatted(

    n.getPID(), n.getName(), n.getParameter()


    ));


    // invoca logica de negocio


    }


    }


    break;


    }


    }

    View Slide

  395. try (Connection cn = new org.postgresql.Driver().connect(url, properties)) {


    cn.createStatement().execute(“LISTEN ‘pedidos-finalizados’");


    for (;;) {


    PGNotification[] ns = ((PGConnection) cn).getNotifications(0);


    if (ns != null)


    for (PGNotification n : ns) {


    System.out.println("pid=%s, event=%s, payload=%s".formatted(

    n.getPID(), n.getName(), n.getParameter()


    ));


    // invoca logica de negocio


    }


    break;


    }


    }

    View Slide

  396. A vantagem
    desse modelo…

    View Slide

  397. INSERT
    CONFIRMADO
    CONFIRMADO
    PENDENTE
    LISTEN ‘pedidos-finalizados’
    LISTEN ‘pedidos-finalizados’
    pg_notify(

    View Slide

  398. INSERT
    CONFIRMADO
    CONFIRMADO
    PENDENTE
    LISTEN ‘pedidos-finalizados’
    LISTEN ‘pedidos-finalizados’
    pg_notify(

    View Slide

  399. INSERT
    CONFIRMADO
    CONFIRMADO
    PENDENTE
    LISTEN ‘pedidos-finalizados’
    LISTEN ‘pedidos-finalizados’
    pg_notify(

    View Slide

  400. INSERT
    CONFIRMADO
    CONFIRMADO
    PENDENTE
    LISTEN ‘pedidos-finalizados’
    LISTEN ‘pedidos-finalizados’
    pg_notify(

    View Slide

  401. Recapitulando…

    View Slide

  402. View Slide

  403. CACHE
    BALANCEAMENTO
    DE CARGA
    PROCESSAMENTO
    ASSINCRONO

    View Slide

  404. INSERT
    CONFIRMADO
    CONFIRMADO
    PENDENTE
    LISTEN ‘pedidos-finalizados’
    LISTEN ‘pedidos-finalizados’
    pg_notify(

    ‘pedidos-finalizados’,


    ‘{“id”: 42, “nome”: ... }’

    )

    View Slide

  405. INSERT
    CONFIRMADO
    CONFIRMADO
    PENDENTE
    LISTEN ‘pedidos-finalizados’
    LISTEN ‘pedidos-finalizados’
    pg_notify(

    ‘pedidos-finalizados’,


    ‘{“id”: 42, “nome”: ... }’

    )

    View Slide

  406. INSERT
    CONFIRMADO
    CONFIRMADO
    PENDENTE
    LISTEN ‘pedidos-finalizados’
    LISTEN ‘pedidos-finalizados’
    pg_notify(

    ‘pedidos-finalizados’,


    ‘{“id”: 42, “nome”: ... }’

    )
    Queue

    View Slide

  407. INSERT
    CONFIRMADO
    CONFIRMADO
    PENDENTE
    LISTEN ‘pedidos-finalizados’
    LISTEN ‘pedidos-finalizados’
    pg_notify(

    ‘pedidos-finalizados’,


    ‘{“id”: 42, “nome”: ... }’

    )
    Pub/Sub

    View Slide

  408. Banco de dados

    relacional

    View Slide

  409. CONCLUINDO

    View Slide

  410. View Slide

  411. View Slide

  412. Não!

    View Slide

  413. View Slide

  414. View Slide

  415. View Slide

  416. “Use o banco apenas
    como repositório de
    dados.”

    View Slide

  417. “Use o banco apenas
    como repositório de
    dados.”
    Não!

    View Slide

  418. @rponte
    Rafael Ponte

    View Slide