{"id":13524975,"url":"https://github.com/fastify/fastify-circuit-breaker","last_synced_at":"2025-05-15T23:07:41.977Z","repository":{"id":29303979,"uuid":"121052432","full_name":"fastify/fastify-circuit-breaker","owner":"fastify","description":"A low overhead circuit breaker for your routes","archived":false,"fork":false,"pushed_at":"2025-05-01T10:16:21.000Z","size":145,"stargazers_count":154,"open_issues_count":1,"forks_count":12,"subscribers_count":15,"default_branch":"main","last_synced_at":"2025-05-05T22:09:45.792Z","etag":null,"topics":["circuit-breaker","fastify","fastify-plugin"],"latest_commit_sha":null,"homepage":"https://npmjs.com/package/@fastify/circuit-breaker","language":"JavaScript","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/fastify.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,"zenodo":null},"funding":{"github":"fastify","open_collective":"fastify"}},"created_at":"2018-02-10T20:41:37.000Z","updated_at":"2025-05-01T10:16:19.000Z","dependencies_parsed_at":"2024-01-23T20:11:26.131Z","dependency_job_id":"fbbc354d-9fe1-4c2a-b626-1bdce71c2151","html_url":"https://github.com/fastify/fastify-circuit-breaker","commit_stats":{"total_commits":136,"total_committers":19,"mean_commits":7.157894736842105,"dds":0.5808823529411764,"last_synced_commit":"dce43da00f6e74d797877e8b170e9a56326a28b0"},"previous_names":[],"tags_count":11,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/fastify%2Ffastify-circuit-breaker","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/fastify%2Ffastify-circuit-breaker/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/fastify%2Ffastify-circuit-breaker/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/fastify%2Ffastify-circuit-breaker/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/fastify","download_url":"https://codeload.github.com/fastify/fastify-circuit-breaker/tar.gz/refs/heads/main","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":254436948,"owners_count":22070947,"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","fastify","fastify-plugin"],"created_at":"2024-08-01T06:01:15.056Z","updated_at":"2025-05-15T23:07:36.505Z","avatar_url":"https://github.com/fastify.png","language":"JavaScript","funding_links":["https://github.com/sponsors/fastify","https://opencollective.com/fastify"],"categories":["JavaScript","\u003ch2 align=\"center\"\u003eAwesome Fastify\u003c/h2\u003e"],"sub_categories":["\u003ch2 align=\"center\"\u003eEcosystem\u003c/h2\u003e"],"readme":"\u003cimg align=\"right\" width=\"350\" height=\"auto\" src=\"https://martinfowler.com/bliki/images/circuitBreaker/state.png\"\u003e\n\n# @fastify/circuit-breaker\n\n[![CI](https://github.com/fastify/fastify-circuit-breaker/actions/workflows/ci.yml/badge.svg?branch=main)](https://github.com/fastify/fastify-circuit-breaker/actions/workflows/ci.yml)\n[![NPM version](https://img.shields.io/npm/v/@fastify/circuit-breaker.svg?style=flat)](https://www.npmjs.com/package/@fastify/circuit-breaker)\n[![neostandard javascript style](https://img.shields.io/badge/code_style-neostandard-brightgreen?style=flat)](https://github.com/neostandard/neostandard)\n\nA low overhead [circuit breaker](https://martinfowler.com/bliki/CircuitBreaker.html) for your routes.\n\n## Install\n```\nnpm i @fastify/circuit-breaker\n```\n\n### Compatibility\n| Plugin version | Fastify version |\n| ---------------|-----------------|\n| `\u003e=4.x`        | `^5.x`          |\n| `^3.x`         | `^4.x`          |\n| `\u003e=1.x \u003c3.x`   | `^3.x`          |\n| `^0.x`         | `^2.x`          |\n| `^0.x`         | `^1.x`          |\n\n\nPlease note that if a Fastify version is out of support, then so are the corresponding versions of this plugin\nin the table above.\nSee [Fastify's LTS policy](https://github.com/fastify/fastify/blob/main/docs/Reference/LTS.md) for more details.\n\n## Usage\nRegister the plugin and, if needed, pass it custom options.\u003cbr\u003e\nThis plugin will add an `onSend` hook and expose a `circuitBreaker` utility.\u003cbr\u003e\nCall `fastify.circuitBreaker()` when declaring the `preHandler` option of a route, in this way you will put that very specific route under the *circuit breaking* check.\n```js\nconst fastify = require('fastify')()\n\nfastify.register(require('@fastify/circuit-breaker'))\n\nfastify.register(function (instance, opts, next) {\n  instance.route({\n    method: 'GET',\n    url: '/',\n    schema: {\n      querystring: {\n        error: { type: 'boolean' },\n        delay: { type: 'number' }\n      }\n    },\n    preHandler: instance.circuitBreaker(),\n    handler: function (req, reply) {\n      setTimeout(() =\u003e {\n        reply.send(\n          req.query.error ? new Error('kaboom') : { hello: 'world' }\n        )\n      }, req.query.delay || 0)\n    }\n  })\n  next()\n})\n\nfastify.listen({ port: 3000 }, err =\u003e {\n  if (err) throw err\n  console.log('Server listening at http://localhost:3000')\n})\n```\n\n### Options\nYou can pass the following options during the plugin registration, this way the values will be used in all routes.\n```js\nfastify.register(require('@fastify/circuit-breaker'), {\n  threshold: 3, // default 5\n  timeout: 5000, // default 10000\n  resetTimeout: 5000, // default 10000\n  onCircuitOpen: async (req, reply) =\u003e {\n    reply.statusCode = 500\n    throw new Error('a custom error')\n  },\n  onTimeout: async (req, reply) =\u003e {\n    reply.statusCode = 504\n    return 'timed out'\n  }\n})\n```\n- `threshold`: the maximum number of failures accepted before opening the circuit.\n- `timeout:` the maximum number of milliseconds you can wait before returning a `TimeoutError`.\n- `resetTimeout`: number of milliseconds before the circuit will move from `open` to `half-open`\n- `onCircuitOpen`: async function that gets called when the circuit is `open` due to errors. It can modify the reply and return a `string` | `Buffer` | `Stream` payload.  If an `Error` is thrown it will be routed to your error handler.\n- `onTimeout`: async function that gets called when the circuit is `open` due to timeouts.  It can modify the reply and return a `string` | `Buffer` | `Stream` | `Error` payload.  If an `Error` is thrown it will be routed to your error handler.\n\nOtherwise, you can customize every single route by passing the same options to the `circuitBreaker` utility:\n```js\nfastify.circuitBreaker({\n  threshold: 3, // default 5\n  timeout: 5000, // default 10000\n  resetTimeout: 5000 // default 10000\n})\n```\nIf you pass the options directly to the utility, it will take precedence over the global configuration.\n\n### Customize error messages\nIf needed you can change the default error message for the *circuit open error* and the *timeout error*:\n```js\nfastify.register(require('@fastify/circuit-breaker'), {\n  timeoutErrorMessage: 'Ronf...', // default 'Timeout'\n  circuitOpenErrorMessage: 'Oh gosh!' // default 'Circuit open'\n})\n```\n\n## Caveats\nSince it is not possible to apply the classic timeout feature of the pattern, in this case the timeout will measure the time that the route takes to execute and **once the route has finished** if the time taken is higher than the timeout it will return an error, even if the route has produced a successful response.\n\nIf you need a classic circuit breaker to wrap around an API call consider using [`easy-breaker`](https://github.com/delvedor/easy-breaker).\n\n## Acknowledgments\nImage courtesy of [Martin Fowler](https://martinfowler.com/bliki/CircuitBreaker.html).\n\n\u003ca name=\"license\"\u003e\u003c/a\u003e\n## License\n\nLicensed under [MIT](./LICENSE).\n\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Ffastify%2Ffastify-circuit-breaker","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Ffastify%2Ffastify-circuit-breaker","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Ffastify%2Ffastify-circuit-breaker/lists"}