{"id":13483610,"url":"https://github.com/TPei/circuit_breaker","last_synced_at":"2025-03-27T14:31:25.957Z","repository":{"id":47494050,"uuid":"59661772","full_name":"TPei/circuit_breaker","owner":"TPei","description":"Implementation of the circuit breaker pattern in crystal","archived":false,"fork":false,"pushed_at":"2023-04-10T13:23:06.000Z","size":54,"stargazers_count":27,"open_issues_count":0,"forks_count":2,"subscribers_count":3,"default_branch":"master","last_synced_at":"2025-03-19T12:11:09.628Z","etag":null,"topics":["circuit-breaker","circuit-breaker-pattern","crystal","design-pattern"],"latest_commit_sha":null,"homepage":null,"language":"Crystal","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"mit","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/TPei.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":"LICENSE","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null}},"created_at":"2016-05-25T12:34:53.000Z","updated_at":"2023-10-17T13:54:07.000Z","dependencies_parsed_at":"2024-05-02T20:12:08.629Z","dependency_job_id":null,"html_url":"https://github.com/TPei/circuit_breaker","commit_stats":null,"previous_names":[],"tags_count":3,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/TPei%2Fcircuit_breaker","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/TPei%2Fcircuit_breaker/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/TPei%2Fcircuit_breaker/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/TPei%2Fcircuit_breaker/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/TPei","download_url":"https://codeload.github.com/TPei/circuit_breaker/tar.gz/refs/heads/master","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":245863099,"owners_count":20684788,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["circuit-breaker","circuit-breaker-pattern","crystal","design-pattern"],"created_at":"2024-07-31T17:01:13.290Z","updated_at":"2025-03-27T14:31:25.676Z","avatar_url":"https://github.com/TPei.png","language":"Crystal","funding_links":[],"categories":["Misc"],"sub_categories":[],"readme":"# circuit_breaker\n\n###### This project is being built weekly with the latest crystal version (works with v1.7.2 🎉)\n\nSimple Implementation of the [circuit breaker pattern](http://martinfowler.com/bliki/CircuitBreaker.html) in Crystal.\n\n## What??!?\n\n\u003e The basic idea behind the circuit breaker is very simple. You wrap a protected function call in a circuit breaker object, which monitors for failures. Once the failures reach a certain threshold, the circuit breaker trips, and all further calls to the circuit breaker return with an error, without the protected call being made at all. Usually you'll also want some kind of monitor alert if the circuit breaker trips. - Martin Fowler\n\nGiven a certain error threshold, timeframe and timeout window, a breaker can be used to monitor criticial command executions. Circuit breakers are usually used to prevent unnecessary requests if a server ressource et al becomes unavailable. This protects the server from additional load and allows it to recover and relieves the client from requests that are doomed to fail.\n\nWrap API calls inside a breaker, if the error rate in a given time frame surpasses a certain threshold, all subsequent calls will fail for a given duration.\n\n## Installation\n\nAdd to your shard.yml\n\n```yaml\ndependencies:\n  circuit_breaker:\n    github: tpei/circuit_breaker\n    branch: master\n```\n\nand then install the library into your project with\n\n```bash\n$ crystal deps\n```\n\n## Usage\n\nCreate a new breaker:\n```crystal\nrequire \"circuit_breaker\"\n\nbreaker = CircuitBreaker.new(\n  threshold: 5, # % of errors before you want to trip the circuit\n  timewindow: 60, # in s: anything older will be ignored in error_rate\n  reenable_after: 300 # after x seconds, the breaker will allow executions again\n)\n```\n\nThen wrap whatever you like:\n```crystal\nbreaker.run do\n  my_rest_call()\nend\n```\n\n### Handling CircuitBreaker trips\n\nThe Breaker will open and throw an CircuitOpenException for all subsequent calls, once the threshold is reached. You can of course catch these exceptions and do whatever you want :D\n```crystal\nbegin\n  breaker.run do\n    my_rest_call()\n  end\nrescue exc : CircuitOpenException\n  log \"happens to the best of us...\"\n  42\nend\n```\n\nAfter the given reenable time, the circuit will transition to \"half open\". This will completely reset the circuit if the next execution succeeds, but reopen the circuit and reset the timer if the next execution fails.\n\n### Handling only certain error types\n\nIf you are feeling really funky, you can also limit the exception classes to monitor. You might want to catch `RandomRestError`, but not `ArgumentError`, so do this:\n```crystal\nbreaker = CircuitBreaker.new(\n  threshold: 5,\n  timewindow: 60,\n  reenable_after: 300,\n  handled_errors: [RandomRestError.new]\n)\n\nbreaker.run\n  raise ArgumentError.new(\"won't count towards the error rate\")\nend\n```\n\n### Ignoring certain error types\n\nConversely, you can also add custom errors to ignore and count all others:\n```crystal\nbreaker = CircuitBreaker.new(\n  threshold: 5,\n  timewindow: 60,\n  reenable_after: 300,\n  ignored_errors: [ArgumentError.new]\n)\n\nbreaker.run\n  raise ArgumentError.new(\"won't count towards the error rate\")\nend\n```\n\nUnfortunately this both won't match against exception subclasses just yet, so at the moment you have to specify the exact class to monitor and can't just use `RestException` to match every subclass like `RestTimeoutException \u003c RestException`...\n\n\n## Thanks\nSpecial thanks goes to Pedro Belo on whose ruby circuit breaker implementation ([CB2](https://github.com/pedro/cb2)) this is loosely based. \n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2FTPei%2Fcircuit_breaker","html_url":"https://awesome.ecosyste.ms/projects/github.com%2FTPei%2Fcircuit_breaker","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2FTPei%2Fcircuit_breaker/lists"}