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

Circuit Breakers em Ruby

5a90a67fa1a92e6a4b605cfd8da5e375?s=47 Lucas Mazza
November 19, 2016

Circuit Breakers em Ruby

5a90a67fa1a92e6a4b605cfd8da5e375?s=128

Lucas Mazza

November 19, 2016
Tweet

Transcript

  1. Circuit Breakers em Ruby

  2. @lucasmazza http://afterhours.io/

  3. None
  4. None
  5. https://sp.femug.com https://github.com/femug/femug

  6. Circuit Breakers em Ruby

  7. None
  8. None
  9. None
  10. None
  11. None
  12. None
  13. rescue_from StandardError do render text: 'oops' end

  14. rescue_from StandardError do render text: 'oops' end ❓❓❓❓❓❓❓❓❓ ❓❓❓❓❓❓❓❓❓

  15. “You wrap a protected function call in a circuit breaker

    object, which monitors for failures.” http://martinfowler.com/bliki/CircuitBreaker.html
  16. https://pragprog.com/book/mnee/release-it

  17. None
  18. None
  19. None
  20. None
  21. None
  22. None
  23. None
  24. None
  25. Estado + transições

  26. ✓ Timeouts

  27. ✓ Timeouts ✓ Downtimes

  28. ✓ Timeouts ✓ Downtimes ✓ Picos de erros

  29. ✓ Timeouts ✓ Downtimes ✓ Picos de erros ✓ Má

    configuração
  30. ★ Limite de falhas

  31. ★ Limite de falhas ★ Tempo para reset

  32. ★ Limite de falhas ★ Tempo para reset ★ Erros

    a ignorar
  33. None
  34. ❓API pública ❓Gestão do estado ❓Concorrência

  35. jnunemaker/resilient

  36. require 'resilient/circuit_breaker' circuit_breaker = Resilient::CircuitBreaker.get('acme-co-api') if circuit_breaker.allow_request? begin # API

    Call circuit_breaker.success rescue => boom circuit_breaker.failure # do fallback end else # do fallback end
  37. circuit_breaker = Resilient::CircuitBreaker.get('example', { # at what percentage of errors

    should we open the circuit error_threshold_percentage: 50, # do not try request again for 5 seconds sleep_window_seconds: 5, # do not open circuit until at least 5 requests have happened request_volume_threshold: 5, }) # etc etc etc
  38. ✅ Boa API pública ⚠ Não é distribuído ⚠ Não

    é concorrente
  39. ✅ Instrumentação & Métricas

  40. shopify/semian

  41. gem 'semian', require: %w(semian semian/redis) def fetch_user User.find(session[:user_id]) rescue Redis::CannotConnectError

    nil end
  42. Semian.register(:mysql_shard0, timeout: 0.5, error_threshold: 3, error_timeout: 10) Semian[:mysql_shard0].acquire do #

    Perform a MySQL query here end
  43. “Semian is not a trivial library to understand, introduces complexity

    and thus should be introduced with care.” https://github.com/shopify/semian#do-i-need-semian
  44. “It is paramount that you understand Semian before including it

    in production as you may otherwise be surprised by its behaviour.” https://github.com/shopify/semian#do-i-need-semian
  45. ⚠ Monkeypatch ⚠ estado por host ✅ Concorrente

  46. ✅ Suporte a instrumentação ✅ Battle tested

  47. orgsync/stoplight

  48. light = Stoplight('acme-co-api') { do_api_call } .with_fallback { do_fallback }

    .with_threshold(3) # => Stoplight::Light light.color #=> 'green', 'yellow' ou 'red' light.run
  49. require 'redis' redis = Redis.new data_store = Stoplight::DataStore::Redis.new(redis) Stoplight::Light.default_data_store =

    data_store slack = Slack::Notifier.new('http://www.example.com/webhook-url') notifier = Stoplight::Notifier::Slack.new(slack) Stoplight::Light.default_notifiers += [notifier] notifier = Stoplight::Notifier::Logger.new(Rails.logger) Stoplight::Light.default_notifiers += [notifier]
  50. ⚠ API não idiomática ✅ Distribuído ✅ Concorrente

  51. ✅ Implementação bem legível

  52. netflix/hystrix

  53. None
  54. orgsync/stoplight

  55. class CircuitBreaker def initialize(client, name) @client = client @name =

    name end def method_missing(method, *args, &block) Stoplight(@name) { @client.public_send(method, *args, &block) }.run end end
  56. gh_client = GitHub::Client.new('acme-co-oauth2-token') client = CircuitBreaker.new(gh_client, 'client-acme-co') # Requests feito

    dentro do Circuit Breaker client.repo('plataformatec/devise') client.repo('plataformatec/simple_form') client.repo('plataformatec/faraday-http-cache')
  57. Pattern + Gem Você!

  58. ❓Monitoramento

  59. Métricas

  60. StatsD Librato NewRelic AppSignal …

  61. Notificações

  62. Notificações

  63. Reset manual

  64. ❓Fallback vs raise

  65. Escrita vs leitura sync vs async

  66. Executar uma operação em background Retry + backoff

  67. Ler dados de uma API Fallback e/ou cache

  68. None
  69. Obrigado! @lucasmazza