{"id":20674713,"url":"https://github.com/pixelfederation/circuit-breaker-bundle","last_synced_at":"2025-04-19T20:30:39.162Z","repository":{"id":37861437,"uuid":"395702430","full_name":"pixelfederation/circuit-breaker-bundle","owner":"pixelfederation","description":"A Symfony bundle for automatic circuit breaker feature wiring into service classes. Similar to Java Hystrix.","archived":false,"fork":false,"pushed_at":"2024-06-20T11:58:12.000Z","size":1308,"stargazers_count":11,"open_issues_count":2,"forks_count":0,"subscribers_count":5,"default_branch":"master","last_synced_at":"2024-11-15T16:43:39.543Z","etag":null,"topics":["circuit-breaker","ganesha","php","symfony-bundle"],"latest_commit_sha":null,"homepage":"","language":"PHP","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"bsd-3-clause","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/pixelfederation.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":"2021-08-13T15:25:23.000Z","updated_at":"2024-11-02T21:09:34.000Z","dependencies_parsed_at":"2024-05-30T12:16:01.269Z","dependency_job_id":"9d7aa776-ab6c-4944-9b88-1b385ea62bcf","html_url":"https://github.com/pixelfederation/circuit-breaker-bundle","commit_stats":{"total_commits":237,"total_committers":3,"mean_commits":79.0,"dds":"0.13502109704641352","last_synced_commit":"8e56eedfc98575c4b276b1b5e7bb734f5ce79076"},"previous_names":[],"tags_count":8,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/pixelfederation%2Fcircuit-breaker-bundle","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/pixelfederation%2Fcircuit-breaker-bundle/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/pixelfederation%2Fcircuit-breaker-bundle/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/pixelfederation%2Fcircuit-breaker-bundle/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/pixelfederation","download_url":"https://codeload.github.com/pixelfederation/circuit-breaker-bundle/tar.gz/refs/heads/master","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":224850050,"owners_count":17380129,"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","ganesha","php","symfony-bundle"],"created_at":"2024-11-16T21:06:47.272Z","updated_at":"2024-11-16T21:06:47.697Z","avatar_url":"https://github.com/pixelfederation.png","language":"PHP","funding_links":[],"categories":[],"sub_categories":[],"readme":"# Circuit breaker bundle\n\nThis bundle tries to copy the famous java [Hystrix](https://github.com/Netflix/Hystrix) library \nand tries to make the usage of the circuit breaking pattern effortless to the developers. \n\nThe developers can just mark any service as circuit broken, using special annotations \nand this bundle makes all the wiring under the hood automatically.\n\nThe current backend implementation is using [Ganesha](https://github.com/ackintosh/ganesha).\n\n## Installation\n\n```bash\n$ composer require pixelfederation/circuit-breaker-bundle\n```\n\n## Configuration\n\nJust enable the bundle. There are no configuration options for now.\n\n```php\n// in config/bundles.php add this line:\nPixelFederation\\CircuitBreakerBundle\\Bridge\\Symfony\\PixelFederationCircuitBreakerBundle::class\n```\n\n## Usage\n\nTo activate circuit breaking on a given service, the service has to implement \nthe `PixelFederation\\CircuitBreakerBundle\\CircuitBrokenService` interface.\n\nThe class mustn't be marked as `final`, because a proxy class is derived from it under the hood.\n\nTo configure circuit breaking, you can use the class level configuration or method level configuration.\nThe class level configuration is valid for all the circuit-broken methods.\nIt is configured as a class level annotation `@CircuitBreakerService`. To mark a public method as circuit broken, \nthe `@CircuitBreaker` annotation or attribute has to be used:\n\n```php\nuse PixelFederation\\CircuitBreakerBundle\\Annotation\\CircuitBreakerService;\nuse PixelFederation\\CircuitBreakerBundle\\Annotation\\CircuitBreaker;\n\n/**\n * @CircuitBreakerService(\n *    defaultFallback=\"makeDefaultFallbackRequest\", \n *    ignoreExceptions={BadMethodCallException::class}\n * )\n */\nclass Service {\n    /**\n     * @CircuitBreaker() \n     */\n    public function iShouldBeCircuitBroken(): int\n    {\n        return 0;\n    }\n}\n```\n\nor \n\n```php\nuse PixelFederation\\CircuitBreakerBundle\\Annotation\\CircuitBreakerService;\nuse PixelFederation\\CircuitBreakerBundle\\Annotation\\CircuitBreaker;\n\n#[CircuitBreakerService(defaultFallback: 'makeDefaultFallbackRequest', ignoreExceptions: [BadMethodCallException::class])]\nclass Service {\n    #[CircuitBreaker()]\n    public function iShouldBeCircuitBroken(): int\n    {\n        return 0;\n    }\n}\n```\n\nThe configuration options for the `@CircuitBreakerService` are:\n- **defaultFallback**: a public method of the same class which should be called on an exception occurrence, \nif no fallback is configured for a circuit-broken method.\n- **ignoreExceptions**: exception list, which doesn't trigger marking the wrapped service as failing\n\nThe method level annotation `@CircuitBreaker` can override the class level configuration \nwith its own configuration options, which are:\n- **fallbackMethod**: a public method of the same class which should be called on an exception occurrence\n- **ignoreExceptions**: exception list, which doesn't trigger marking the wrapped service as failing\n\n```php\nuse PixelFederation\\CircuitBreakerBundle\\Annotation\\CircuitBreaker;\n\nclass Service {\n    /**\n     * @CircuitBreaker(fallbackMethod=\"makeSpecialFallbackRequest\") \n     */\n    public function iShouldBeCircuitBroken(): int\n    {\n        return 0;\n    }\n}\n```\n\nor \n\n```php\nuse PixelFederation\\CircuitBreakerBundle\\Annotation\\CircuitBreaker;\n\nclass Service {\n    #[CircuitBreaker(fallbackMethod: 'makeSpecialFallbackRequest')]\n    public function iShouldBeCircuitBroken(): int\n    {\n        return 0;\n    }\n}\n```\n\nThe **fallback methods have to be public** as well.\n\n**IMPORTANT:** Fallback methods have to have the same method signature as the fallbackable methods, because fallback\nmethods are being called with the same arguments.\n\n**IMPORTANT:** Doctrine annotations support will be dropped in the future, so it is recommended to use the bundle\nattributes instead.\n\n**NOTICE REGARDING COMPLEX SCENARIOS:** It is also possible to define fallback methods for fallback methods \nin some more complex scenarios. An example of such scenario might be, when there is an API call in the default/fallbackable\nmethod. It's fallback method might have a different call to a different API, which means, that such method could use \na fallback as well. In that case it can have configured a fallback method which tries to load data from some cache.\nSuch a method might also use a fallback method which might return some default value.\n\n## Full example\n\n```php\nuse PixelFederation\\CircuitBreakerBundle\\Annotation\\CircuitBreaker;\nuse PixelFederation\\CircuitBreakerBundle\\Annotation\\CircuitBreakerService;\nuse PixelFederation\\CircuitBreakerBundle\\CircuitBrokenService;\nuse BadMethodCallException;\nuse InvalidArgumentException;\nuse RuntimeException;\n\n/**\n * The class level annotation activates circuit breaking configuration on methods\n * marked with the @CircuitBreaker annotation.\n * In this case, also the default fallback for each circuit broken method is configured\n * (the 'makeDefaultFallbackRequest' method)\n * \n * The ignoreExceptions option sets exceptions, on which occurrence the service won't be marked\n * as failing, e.g. some app/system level exceptions, which don't need to have to do anything \n * with http requests under the hood.\n * \n * @CircuitBreakerService(\n *    defaultFallback=\"makeDefaultFallbackRequest\", \n *    ignoreExceptions={BadMethodCallException::class}\n * )\n */\nclass TestService implements CircuitBrokenService\n{\n    private SomeHttpClient $client;\n\n    public function __construct(SomeHttpClient $client)\n    {\n        $this-\u003eclient = $client;\n    }\n\n    /**\n     * This method is marked to be circuit-broken. It uses the class level configured fallback\n     * and ignores the class level configured exceptions. \n     * \n     * @CircuitBreaker()\n     */\n    public function makeRequest(): int\n    {\n        return $this-\u003eclient-\u003emakeRequest(); // it is important to set http timeouts here\n    }\n\n    /**\n     * This method is marked to be circuit-broken. It uses a different fallback, not the one\n     * configured on class level.\n     * \n     * @CircuitBreaker(fallbackMethod=\"makeSpecialFallbackRequest\")\n     */\n    public function makeRequestWithCustomCircuitBreaker(string $param): int\n    {\n        return $this-\u003eclient-\u003emakeAnotherRequest($param); // it is important to set http timeouts here\n    }\n\n    public function makeDefaultFallbackRequest(): void\n    {\n        return 1; // ideally there is no call to any external dependency in the fallback method\n    }\n    \n    // notice that this fallback method has the same method signature as the method makeRequestWithCustomCircuitBreaker\n    public function makeSpecialFallbackRequest(string $param): void\n    {\n        return 0; // ideally there is no call to any external dependency in the fallback method\n    }\n}\n```\n\nEnjoy ;)\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fpixelfederation%2Fcircuit-breaker-bundle","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fpixelfederation%2Fcircuit-breaker-bundle","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fpixelfederation%2Fcircuit-breaker-bundle/lists"}