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

Construindo Sistemas Resilientes com Circuit Br...

Sponsored · SiteGround - Reliable hosting with speed, security, and support you can count on. →

Construindo Sistemas Resilientes com Circuit Breaker

Avatar for Guilherme Cavalcanti

Guilherme Cavalcanti

July 28, 2014

More Decks by Guilherme Cavalcanti

Other Decks in Programming

Transcript

  1. ELOQUENT (latim eloquens, -entis) 1. Que sabe (falando) dominar o

    ânimo de quem o ouve 2. [Figurado] Expressivo, convincente, que prova.
  2. – Release It! “A resilient system keeps processing transactions, even

    when there are transient impulses, persistent stresses, or component failures disrupting normal processing.”
  3. Transactions { Não são transações de DB Processo de checkout

    Signup de usuário Comunicação com serviços de terceiros
  4. KEEPS Processing { Falhas em uma transação não afetam outras

    Falhas em serviços não afetam os componentes que não dependem dele
  5. Release It • Michael Nygard — @mtnygard • ResiliênciA •

    Capacidade • Deployment e monitoramento
  6. Circuit Breaker • Cada vez mais comum a necessidade de

    se comunicar via Rede com software que funciona em processos ou máquinas diferentes • Chamadas a serviços externos irão falhar • Quando muitos componentes dependem de um mesmo serviço podemos gerar falhas em cadeia
  7. Inicialização class CircuitBreaker! ! def initialize(options = {})! @timeout =

    options.fetch(:timeout, 0.01)! @failure_threshold = options.fetch(:failure_threshold, 5)! @silent = false! @failure_count = 0! end
  8. #handle • Recebe um bloco com a estratégia de comunicação

    • Baseado no estado do circuito • Tenta executar e captura falhas def handle(&block)! case state! when :closed then try_to_execute &block! when :open then handle_open! end! end
  9. #try to… • Conta quantidade de falhas • Dispara timeout

    • Reseta o contador def try_to_execute(&block)! begin! yield_with_timeout(&block)! reset! rescue Timeout::Error! record_failure! raise $!! end! end! ! def yield_with_timeout(&b)! Timeout::timeout(@timeout, &b)! end! ! def reset! @failure_count = 0! end! ! def record_failure! @failure_count += 1! end!
  10. Uso require "circuit_breaker"! ! circuit = CircuitBreaker.new! conn = Faraday.new!

    ! circuit.handle do! conn.get('http://api.foo.com/me.json')! end! ! circuit.handle do! conn.get('http://api.foo.com/accounts.json')! end
  11. .new class CircuitBreaker! ! def initialize(options = {})! @invocation_timeout =

    options.fetch(:timeout, 0.01)! @failure_threshold = options.fetch(:failure_threshold, 5)! @silent = false! @failure_count = 0! @reset_timeout = 0.1! @last_failure = nil ! end
  12. Mudanças • Tenta executar nos estados closed e half_open •

    Grava o momento da última falha • Limpa última falha no #reset def handle(&b)! case state! when :closed, :half_open! try_to_execute &b! when :open then handle_open! end! end! ! def try_to_execute(&block)! begin! yield_with_timeout(&block)! reset! rescue Timeout::Error! record_failure! raise $!! end! end! ! def yield_with_timeout(&b)! Timeout::timeout(@timeout, &b)! end! ! def reset! @failure_count = 0! @last_failure_time = nil! end! ! def record_failure! @last_failure_time = Time.now! @failure_count += 1! end!
  13. #STate def state! case! when (@failure_count >= @failure_threshold) &&! (Time.now

    - @last_failure_time) > @reset_timeout! :half_open! when (@failure_count >= @failure_threshold)! :open! else! :closed! end! end
  14. Pontos de Melhoria • Utilizar o AAsm ou Statesman para

    gerenciar estados • Adicionar monitoramento através de dependency injection • Circuit breaker distribuido • Detectar outros erros além do timeout