{"id":17188231,"url":"https://github.com/jclem/ex_break","last_synced_at":"2025-04-13T19:13:20.866Z","repository":{"id":62429055,"uuid":"195747773","full_name":"jclem/ex_break","owner":"jclem","description":"A circuit breaker implementation for Elixir","archived":false,"fork":false,"pushed_at":"2019-07-19T21:07:39.000Z","size":139,"stargazers_count":7,"open_issues_count":0,"forks_count":0,"subscribers_count":1,"default_branch":"master","last_synced_at":"2025-04-10T17:31:09.796Z","etag":null,"topics":[],"latest_commit_sha":null,"homepage":"https://hexdocs.pm/ex_break","language":"Elixir","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/jclem.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":"LICENSE.md","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null}},"created_at":"2019-07-08T06:11:20.000Z","updated_at":"2024-10-21T08:08:02.000Z","dependencies_parsed_at":"2022-11-01T20:02:52.078Z","dependency_job_id":null,"html_url":"https://github.com/jclem/ex_break","commit_stats":null,"previous_names":[],"tags_count":9,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/jclem%2Fex_break","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/jclem%2Fex_break/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/jclem%2Fex_break/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/jclem%2Fex_break/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/jclem","download_url":"https://codeload.github.com/jclem/ex_break/tar.gz/refs/heads/master","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":248766746,"owners_count":21158301,"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":[],"created_at":"2024-10-15T01:08:27.657Z","updated_at":"2025-04-13T19:13:20.837Z","avatar_url":"https://github.com/jclem.png","language":"Elixir","funding_links":[],"categories":[],"sub_categories":[],"readme":"# ExBreak\n\nExBreak is a circuit breaker implementation for Elixir.\n\nWhen making function calls (typically to an external service) that may fail, you may find that you want to stop making those calls for a period of time after an error threshold is hit. This package provides a way to do that.\n\n```elixir\ndefmodule GitHub do\n  @moduledoc \"\"\"\n  Makes calls to the GitHub API\n  \"\"\"\n\n  @base_url \"https://api.github.com\"\n\n  @doc \"\"\"\n  Make a GET request to the GitHub API.\n\n  This request is wrapped in a circuit breaker—after 10 calls that return an\n  error tuple (`{:error, any}`), the circuit breaker will trip, and the\n  function will immediately return `{:error, :circuit_breaker_tripped}` for\n  the next two minutes (120 seconds).\n  \"\"\"\n  def get(path, token: token) do\n    ExBreak.call(\u0026do_get/2, [path, token], threshold: 10, timeout_sec: 120)\n  end\n\n  defp do_get(path, token) do\n    HTTPoison.get(\"#{@base_url}#{path}\", authorization: \"Bearer #{token}\")\n  end\nend\n```\n\nIt is also possible to have more fine-grained control over when a circuit breaker's trip counter is incremented. For example, to ensure that only `RuntimeError`s increment the counter, but not other exceptions, the `match_exception` option can be used.\n\nThe `match_exception` option is a function that will be called with the exception. If it returns `true`, the trip counter will be incremented when an exception occurs. Otherwise, it will not.\n\n```elixir\nExBreak.call(\n  \u0026do_get/2,\n  [path, token],\n  match_exception: fn\n    %RuntimeError{} -\u003e true\n    _ -\u003e false\n  end\n)\n```\n\nLikewise, `match_return` can be used to designate what return values increment the trip counter. This option is a function that is called with the return value of the function passed to `call/3`. If it returns `true`, the trip counter will be incremented. Otherwise, it will not.\n\n```elixir\nExBreak.call(\n  \u0026do_get/2,\n  [path, token],\n  match_return: fn\n    {:error, :service_unavailable} -\u003e true\n    _ -\u003e false\n  end\n)\n```\n\nIf you need to do some sort of alerting when a breaker trips, you can use the `on_trip` option, which is a function that will receive the tripped breaker as its argument. This function is called via [`spawn_link/1`](https://hexdocs.pm/elixir/Kernel.html#spawn_link/1) in the breaker's process.\n\n```elixir\nExBreak.call(\n  \u0026do_get/2,\n  [path, token],\n  on_trip: fn breaker -\u003e\n    Logger.error(\"Breaker tripped after #{breaker.break_count} breaks\")\n  end\n)\n```\n\n## Installation\n\nIf [available in Hex](https://hex.pm/docs/publish), the package can be installed by adding `ex_break` to your list of dependencies in `mix.exs`:\n\n```elixir\ndef deps do\n  [\n    {:ex_break, \"~\u003e 0.1.0\"}\n  ]\nend\n```\n\n## Architecture\n\n![](https://raw.githubusercontent.com/jclem/ex_break/master/architecture.png)\n\nWhen a call `ExBreak.call/3` happens, the `ExBreak` module asks the `ExBreak.Registry` to get an `ExBreak.Breaker` state agent for the function passed to `call/3`. If an agent already exists, the registry returns it. Otherwise, it starts a new one using `ExBreak.BreakerSupervisor` and monitors it.\n\nIf the breaker has already been tripped and the tripped state has not expired, the function passed to `call/3` is never called and the value `{:error, :circuit_breaker_tripped}` is returned, instead.\n\nIf, however, the breaker has not been tripped (or its tripped state has expired), the function passed to `call/3` is called. If an exception is raised when calling the function, or if the return value of the function matches the pattern `{:error, _}`, a counter in the breaker's internal state is incremented, and either the exception is re-raised or the return value is returned.\n\nIf the counter in the breaker's internal state meets a configured threshold, the breaker is marked as \"tripped\", and subsequent calls to `call/3` with the same function will return `{:error, :circuit_breaker_tripped}` immediately until the tripped state expires once again.\n\n### [ExBreak.Application](https://github.com/jclem/ex_break/blob/master/lib/ex_break/application.ex)\n\nThis module is an [`Application`](https://hexdocs.pm/elixir/Application.html) which will start when you include `ex_break` in your application's dependencies. Its only responsibility is to start the `ExBreak.Supervisor`.\n\n### [ExBreak.Supervisor](https://github.com/jclem/ex_break/blob/master/lib/ex_break/supervisor.ex)\n\nThis is a [`Supervisor`](https://hexdocs.pm/elixir/Supervisor.html) which starts `ExBreak.DynamicSupervisor` and `ExBreak.Registry`.\n\n### [ExBreak.BreakerSupervisor](https://github.com/jclem/ex_break/blob/master/lib/ex_break/supervisor.ex#L10)\n\nThis module is a [`DynamicSupervisor`](https://hexdocs.pm/elixir/DynamicSupervisor.html) that dynamically supervises `ExBreak.Breaker` agents on demand as they're needed.\n\n### [ExBreak.Registry](https://github.com/jclem/ex_break/blob/master/lib/ex_break/registry.ex)\n\nThis module is a registry of `ExBreak.Breaker` agents. When a call to `ExBreak.call/3` happens, the registry finds or creates the `ExBreak.Breaker` registered for the given function call and returns it to the `ExBreak` module for use.\n\nWhen an `ExBreak.Breaker` process exits, it is de-registered.\n\n### [ExBreak.Breaker](https://github.com/jclem/ex_break/blob/master/lib/ex_break/breaker.ex)\n\nThis module is an [`Agent`](https://hexdocs.pm/elixir/Agent.html) which stores internal state about an individual circuit breaker.\n\nDocumentation can be generated with [ExDoc](https://github.com/elixir-lang/ex_doc) and published on [HexDocs](https://hexdocs.pm). Once published, the docs can be found at [https://hexdocs.pm/ex_break](https://hexdocs.pm/ex_break).\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fjclem%2Fex_break","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fjclem%2Fex_break","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fjclem%2Fex_break/lists"}