{"id":18677250,"url":"https://github.com/elixir-toniq/regulator","last_synced_at":"2025-12-12T00:23:25.517Z","repository":{"id":45969104,"uuid":"262048674","full_name":"elixir-toniq/regulator","owner":"elixir-toniq","description":"Adaptive concurrency limits for elixir","archived":false,"fork":false,"pushed_at":"2023-11-29T15:37:23.000Z","size":79,"stargazers_count":168,"open_issues_count":0,"forks_count":8,"subscribers_count":6,"default_branch":"main","last_synced_at":"2024-12-09T08:09:56.803Z","etag":null,"topics":[],"latest_commit_sha":null,"homepage":null,"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/elixir-toniq.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,"governance":null}},"created_at":"2020-05-07T12:49:13.000Z","updated_at":"2024-12-08T16:34:31.000Z","dependencies_parsed_at":"2023-11-29T16:44:06.520Z","dependency_job_id":null,"html_url":"https://github.com/elixir-toniq/regulator","commit_stats":{"total_commits":26,"total_committers":4,"mean_commits":6.5,"dds":"0.15384615384615385","last_synced_commit":"9f3697d3e99b0e6d5a11962b02354dd8b42e8d27"},"previous_names":["keathley/regulator"],"tags_count":7,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/elixir-toniq%2Fregulator","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/elixir-toniq%2Fregulator/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/elixir-toniq%2Fregulator/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/elixir-toniq%2Fregulator/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/elixir-toniq","download_url":"https://codeload.github.com/elixir-toniq/regulator/tar.gz/refs/heads/main","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":230388129,"owners_count":18217755,"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-11-07T09:33:09.396Z","updated_at":"2025-12-12T00:23:25.466Z","avatar_url":"https://github.com/elixir-toniq.png","language":"Elixir","funding_links":[],"categories":[],"sub_categories":[],"readme":"# Regulator\n\nRegulator provides adaptive concurrency limits around external resources.\n\n```elixir\nRegulator.install(:service, {Regulator.Limit.AIMD, [timeout: 500]})\n\nRegulator.ask(:service, fn -\u003e\n  Finch.request(:get, \"https://keathley.io\")\nend)\n```\n\n## Why do I need this?\n\nIf you're used to circuit breakers, you can think of Regulator as an adaptive,\ndynamic circuit breaker. Regulator determines if there are errors or potential\nfor errors by measuring the running system. When it detects errors - more specifically\nit detects queueing - it begins to lower the number of concurrent _things_ that\ncan happen in the system.\n\nFor instance, Regulator has determined that it can allow 4 concurrent requests to\na downstream API, and 4 requests are initiated, any further requests will be\nrejected immediately.\n\nRejecting the request allows you, the programmer, to determine what to do if Regulator\nis shedding load. here's an example where we will normally serve requests from\na downstream system, but under load shedding, we return a cached value.\n\n\n```elixir\ndef fetch(id) do\n  case Regulator.ask(:service) do\n    {:ok, token} -\u003e\n      case api_call(id) do\n        {:ok, resp} -\u003e\n          :ok = Regulator.ok(token)\n          :ok = Cache.put(id, resp)\n          {:ok, resp}\n\n        {:error, error} -\u003e\n          Regulator.error(token)\n          {:error, error}\n      end\n\n    :dropped -\u003e\n      case Cache.get(id) do\n        nil -\u003e\n          {:error, :not_found}\n\n        resp -\u003e\n          {:ok, resp}\n      end\n  end)\nend\n```\n\n## Limit algorithms\n\nRegulator provides different limit algorithms for different use cases; AIMD, Gradient, and Static.\n\nAIMD updates the concurrency limit using a technique known as \"additive increase, multiplicative decrease\".\nIf regulator detects that more concurrency tokens are required, no errors have ocured, and the average latency is below the target value,\nRegulator will additively increase the concurrency limit. If there are errors or the average\nlatency begins to rise, than regulator will multiplicatively decrease the limit.\n\nThe Gradient limit algorithm looks at the gradient of change between long term latency and the current average latency.\nIf this gradient of change begins to exceed acceptable bounds, the limiter will\nbegin to decrease the concurrency limit.\n\nThe static limit simply uses a fixed value which is never updated.\n\n## Should I use this\n\nThere are additional tests that need to be added and there may be performance\nimprovements required around concurrency token monitoring. But, this has been\nused heavily in production and has supported 10s of thousands of requests per second.\nI feel confident in saying that you can use this in production at this point.\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Felixir-toniq%2Fregulator","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Felixir-toniq%2Fregulator","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Felixir-toniq%2Fregulator/lists"}