{"id":31707137,"url":"https://github.com/postcon/resilience","last_synced_at":"2025-10-08T23:50:50.171Z","repository":{"id":57043868,"uuid":"211922111","full_name":"Postcon/resilience","owner":"Postcon","description":null,"archived":false,"fork":false,"pushed_at":"2021-08-04T11:49:56.000Z","size":24,"stargazers_count":0,"open_issues_count":0,"forks_count":1,"subscribers_count":4,"default_branch":"master","last_synced_at":"2025-08-02T05:08:30.510Z","etag":null,"topics":[],"latest_commit_sha":null,"homepage":null,"language":"PHP","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/Postcon.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}},"created_at":"2019-09-30T18:00:59.000Z","updated_at":"2021-08-04T11:33:43.000Z","dependencies_parsed_at":"2022-08-24T01:21:04.533Z","dependency_job_id":null,"html_url":"https://github.com/Postcon/resilience","commit_stats":null,"previous_names":[],"tags_count":5,"template":false,"template_full_name":null,"purl":"pkg:github/Postcon/resilience","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/Postcon%2Fresilience","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/Postcon%2Fresilience/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/Postcon%2Fresilience/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/Postcon%2Fresilience/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/Postcon","download_url":"https://codeload.github.com/Postcon/resilience/tar.gz/refs/heads/master","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/Postcon%2Fresilience/sbom","scorecard":null,"host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":279000733,"owners_count":26082862,"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","status":"online","status_checked_at":"2025-10-08T02:00:06.501Z","response_time":56,"last_error":null,"robots_txt_status":"success","robots_txt_updated_at":"2025-07-24T06:49:26.215Z","robots_txt_url":"https://github.com/robots.txt","online":true,"can_crawl_api":true,"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":"2025-10-08T23:50:46.439Z","updated_at":"2025-10-08T23:50:50.166Z","avatar_url":"https://github.com/Postcon.png","language":"PHP","funding_links":[],"categories":[],"sub_categories":[],"readme":"# Resilience library\n\n[![Build Status](https://api.travis-ci.org/Postcon/resilience.svg)](https://travis-ci.org/Postcon/resilience)\n\nA collection of reusable resilience pattern implementations. Currently implemented:\n\n* [circuit breaker](https://martinfowler.com/bliki/CircuitBreaker.html)\n\n## Installation\n\nUsing [composer](https://getcomposer.org/download/):\n\n```\ncomposer require postcon/resilience\n```\n\n## Simple usage\n\n```php\n$redis = new \\Redis();\n\n$circuitBreaker = new \\Postcon\\Resilience\\RedisCircuitBreaker($redis, 'system', 120, 3);\n$circuitBreaker-\u003ereportSuccess();\n\n$circuitBreaker-\u003eisAvailable(); // should be true\n$circuitBreaker-\u003ereportFailure();\n$circuitBreaker-\u003eisAvailable(); // ... still true\n$circuitBreaker-\u003ereportFailure();\n$circuitBreaker-\u003eisAvailable(); // ... still true\n$circuitBreaker-\u003ereportFailure();\n$circuitBreaker-\u003eisAvailable(); // ... now it is false\n\n$circuitBreaker-\u003echeck(); // throws CircuitBreakerTripped exception, if 'system' is not available.\n```\n\n## State transitions\n\nThe circuit breaker can be on one of three states: CLOSED (system is available), HALF OPEN (system is still available)\nand OPEN (system is not available).\n\nThe _normal_ state of the circuit breaker is CLOSED; i.e. the system is working correctly. If a failure is reported,\nthe state changes to HALF OPEN. If either a success is reported, or a defined time exceeds (_lifetime_), the state\nbecomes CLOSED again. If failure is reported repeatedly (_maxErrors_), the state changes from HALF OPEN to OPEN\n(_the circuit breaker is tripped_).\n\nThe OPEN state changes back to CLOSED, after exceeding a defined time. Depending on the usage of this circuit breaker\nimplementation, a reported success could change the OPEN state to be CLOSED as well.\n\n```\n --------------------------      ::reportSuccess()        ---------------------------\n|          CLOSED          | \u003c-------------------------- |            OPEN           |\n| ::isAvailable() === true |    exceeding lifetime       | ::isAvailable() === false |\n --------------------------                               ---------------------------\n       ^      |                                                                 ^\n       |      |   ::reportFailure()                                             |\n       |       -------------------------                                        |\n       |                                |                                       |\n       |                                v                                       |\n       |  ::reportSuccess()   --------------------------                        |\n        -------------------- |         HALF OPEN        | ----------------------\n         exceeding lifetime  | ::isAvailable() === true |  rpt. ::reportFailure()\n                              --------------------------\n```\n\n\n## Examples\n\nThis circuit breaker implementation can be used to [decorate](examples/CircuitBreakerClientDecorator.php) e.g. [guzzle http client](https://github.com/guzzle/guzzle/): \n\n```php\nuse GuzzleHttp\\ClientInterface;\nuse GuzzleHttp\\Exception\\ClientException;\nuse GuzzleHttp\\Exception\\ConnectException;\nuse GuzzleHttp\\Exception\\GuzzleException;\nuse GuzzleHttp\\Exception\\ServerException;\nuse Postcon\\Resilience\\CircuitBreakerInterface;\nuse Postcon\\Resilience\\CircuitBreakerTripped;\nuse Psr\\Http\\Message\\RequestInterface;\n\nclass CircuitBreakerClientDecorator implements ClientInterface\n{\n    /** @var ClientInterface */\n    private $baseClient;\n\n    /** @var CircuitBreakerInterface */\n    private $circuitBreaker;\n\n    public function __construct(ClientInterface $baseClient, CircuitBreakerInterface $circuitBreaker)\n    {\n        $this-\u003ebaseClient     = $baseClient;\n        $this-\u003ecircuitBreaker = $circuitBreaker;\n    }\n\n    /**\n     * @inheritdoc\n     *\n     * @throws CircuitBreakerTripped\n     */\n    public function send(RequestInterface $request, array $options = [])\n    {\n        return $this-\u003echeck(function () use ($request, $options) {\n            $this-\u003ebaseClient-\u003esend($request, $options);\n        });\n    }\n\n    // ...\n\n    /**\n     * @throws GuzzleException\n     * @throws CircuitBreakerTripped\n     */\n    private function check(callable $function)\n    {\n        $this-\u003ecircuitBreaker-\u003echeck();\n\n        try {\n            $result = $function();\n\n            $this-\u003ecircuitBreaker-\u003ereportSuccess();\n\n            return $result;\n        } catch (ConnectException $e) {\n            $this-\u003ecircuitBreaker-\u003ereportFailure();\n            throw $e;\n        } catch (ServerException $e) {\n            $this-\u003ecircuitBreaker-\u003ereportFailure();\n            throw $e;\n        } catch (ClientException $e) {\n            $this-\u003ecircuitBreaker-\u003ereportSuccess();\n            throw $e;\n        }\n    }\n}\n```\n\n## Implementation details\n\nCurrently, there is a [redis](https://redis.io/) [implementation](lib/RedisCircuitBreaker.php) of the circuit\nbreaker pattern. An instance of a circuit breaker is persisted as the respective failure counter, where the redis key\nis the circuit breaker name.\n\nTo implement the lifetime feature (automatic state transition to CLOSED after some time), the redis [EXPIRE command](https://redis.io/commands/expire) is used.\n\n## License\n\nAll contents of this package are licensed under the [MIT license](LICENSE).\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fpostcon%2Fresilience","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fpostcon%2Fresilience","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fpostcon%2Fresilience/lists"}