Skip to content

Commit

Permalink
Add basic readme
Browse files Browse the repository at this point in the history
  • Loading branch information
stfndamjanovic committed Dec 4, 2023
1 parent ca808f3 commit c7b6792
Show file tree
Hide file tree
Showing 6 changed files with 90 additions and 53 deletions.
32 changes: 19 additions & 13 deletions README.md
Original file line number Diff line number Diff line change
@@ -1,32 +1,38 @@
# This is my package circuit-breaker
# Circuit breaker in PHP

[![Latest Version on Packagist](https://img.shields.io/packagist/v/stfndamjanovic/circuit-breaker.svg?style=flat-square)](https://packagist.org/packages/stfndamjanovic/circuit-breaker)
[![Tests](https://img.shields.io/github/actions/workflow/status/stfndamjanovic/circuit-breaker/run-tests.yml?branch=main&label=tests&style=flat-square)](https://github.com/stfndamjanovic/circuit-breaker/actions/workflows/run-tests.yml)
[![Total Downloads](https://img.shields.io/packagist/dt/stfndamjanovic/circuit-breaker.svg?style=flat-square)](https://packagist.org/packages/stfndamjanovic/circuit-breaker)

This is where your description should go. Try and limit it to a paragraph or two. Consider adding a small example.

## Support us

[<img src="https://github-ads.s3.eu-central-1.amazonaws.com/circuit-breaker.jpg?t=1" width="419px" />](https://spatie.be/github-ad-click/circuit-breaker)

We invest a lot of resources into creating [best in class open source packages](https://spatie.be/open-source). You can support us by [buying one of our paid products](https://spatie.be/open-source/support-us).

We highly appreciate you sending us a postcard from your hometown, mentioning which of our package(s) you are using. You'll find our address on [our contact page](https://spatie.be/about-us). We publish all received postcards on [our virtual postcard wall](https://spatie.be/open-source/postcards).
This is implementation of circuit breaker in PHP.

## Installation

You can install the package via composer:

```bash
composer require stfndamjanovic/circuit-breaker
composer require stfndamjanovic/php-circuit-breaker
```

## Usage

```php
$skeleton = new Stfn\CircuitBreaker();
echo $skeleton->echoPhrase('Hello, Stfn!');
use Stfn\CircuitBreaker\CircuitBreaker;
use Stfn\CircuitBreaker\Stores\RedisStore;
use Redis;
use Stfn\CircuitBreaker\Config;

$redis = new Redis('127.0.0.1');
$redis->connect();

$store = new RedisStore($redis);

$config = new Config("unique-service-name");

$circuitBreaker = new CircuitBreaker($config, $store);
$circuitBreaker->run(function () {
// Your function that could fail
});
```

## Testing
Expand Down
6 changes: 3 additions & 3 deletions src/CircuitBreaker.php
Original file line number Diff line number Diff line change
Expand Up @@ -62,7 +62,7 @@ public function isOpen()
return $this->store->state() != CircuitState::Closed;
}

public function shouldBecomeHalfOpen()
public function shouldBecomeHalfOpen(): bool
{
$lastChange = $this->store->lastChangedDateUtc();

Expand All @@ -79,7 +79,7 @@ public function shouldBecomeHalfOpen()
return false;
}

public function handleFailure(\Exception $exception)
public function handleFailure(\Exception $exception): void
{
// Log exception

Expand All @@ -91,7 +91,7 @@ public function handleFailure(\Exception $exception)
}
}

public function openCircuit()
public function openCircuit(): void
{
$this->store->open();
$this->store->reset();
Expand Down
30 changes: 24 additions & 6 deletions src/Config.php
Original file line number Diff line number Diff line change
@@ -1,7 +1,11 @@
<?php

declare(strict_types=1);

namespace Stfn\CircuitBreaker;

use Stfn\CircuitBreaker\Utilities\Str;

class Config
{
public string $service;
Expand All @@ -14,39 +18,53 @@ class Config

public float $percentOfFailures = 0;

public function __construct($service)
public function __construct(string $service)
{
$this->service = $service;
}

public function getServiceName()
public function getServiceName(): string
{
return $this->service;
}

public function setMaxNumberOfFailures($maxNumberOfFailures)
public function setMaxNumberOfFailures(int $maxNumberOfFailures): static
{
$this->maxNumberOfFailures = $maxNumberOfFailures;

return $this;
}

public function setOpenToHalfOpenWaitTime($openToHalfOpenWaitTime)
public function setOpenToHalfOpenWaitTime(int $openToHalfOpenWaitTime): static
{
$this->openToHalfOpenWaitTime = $openToHalfOpenWaitTime;

return $this;
}

public function setNumberOfSuccessToCloseState($numberOfSuccessToCloseState)
public function setNumberOfSuccessToCloseState(int $numberOfSuccessToCloseState): static
{
$this->numberOfSuccessToCloseState = $numberOfSuccessToCloseState;

return $this;
}

public function setPercentOfFailures(float $percent)
public function setPercentOfFailures(float $percent): void
{
$this->percentOfFailures = $percent;
}

public static function make(string $service, array $config = []): Config
{
$object = new self($service);

foreach ($config as $property => $value) {
$property = Str::camelize($property);
if (property_exists($object, $property)) {
$object->{$property} = $value;
}
}

return $object;
}
}
12 changes: 6 additions & 6 deletions src/Counter.php
Original file line number Diff line number Diff line change
Expand Up @@ -7,32 +7,32 @@ class Counter
protected int $numberOfFailures = 0;
protected int $numberOfSuccess = 0;

public function getNumberOfFailures()
public function getNumberOfFailures(): int
{
return $this->numberOfFailures;
}

public function getNumberOfSuccess()
public function getNumberOfSuccess(): int
{
return $this->numberOfSuccess;
}

public function success()
public function success(): void
{
$this->numberOfSuccess++;
}

public function failure()
public function failure(): void
{
$this->numberOfFailures++;
}

public function failurePercent()
public function failurePercent(): float
{
return round($this->numberOfFailures / $this->totalTries(), 2);
}

public function totalTries()
public function totalTries(): int
{
return $this->numberOfSuccess + $this->numberOfFailures;
}
Expand Down
11 changes: 11 additions & 0 deletions src/Utilities/Str.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
<?php

namespace Stfn\CircuitBreaker\Utilities;

class Str
{
public static function camelize(string $input, string $separator = '_'): string
{
return lcfirst(str_replace($separator, '', ucwords($input, $separator)));
}
}
52 changes: 27 additions & 25 deletions tests/CircuitBreakerTest.php
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@ class CircuitBreakerTest extends TestCase
{
public function test_if_it_can_handle_function_success()
{
$circuitBreaker = new CircuitBreaker($this->getDefaultConfig(), $this->getStoreInstance());
$circuitBreaker = new CircuitBreaker($this->getDefaultConfig(), new InMemoryStore());

$result = $circuitBreaker->run(function () {
return true;
Expand All @@ -33,7 +33,7 @@ public function test_if_it_can_handle_function_success()

public function test_if_it_will_throw_an_exception_if_circuit_breaker_is_open()
{
$store = $this->getStoreInstance();
$store = new InMemoryStore();
$store->state = CircuitState::Open;

$circuitBreaker = new CircuitBreaker($this->getDefaultConfig(), $store);
Expand All @@ -47,7 +47,7 @@ public function test_if_it_will_throw_an_exception_if_circuit_breaker_is_open()

public function test_if_it_will_record_every_success()
{
$store = $this->getStoreInstance();
$store = new InMemoryStore();

$circuitBreaker = new CircuitBreaker($this->getDefaultConfig(), $store);

Expand All @@ -69,9 +69,11 @@ public function test_if_it_will_record_every_success()

public function test_if_it_will_record_every_failure()
{
$store = $this->getStoreInstance();
$config = $this->getDefaultConfig();
$config->setMaxNumberOfFailures(4);
$store = new InMemoryStore();

$config = Config::make('test', [
'max_number_of_failures' => 4,
]);

$circuitBreaker = new CircuitBreaker($config, $store);

Expand All @@ -97,10 +99,11 @@ public function test_if_it_will_record_every_failure()

public function test_if_it_will_open_circuit_after_failure_threshold()
{
$store = $this->getStoreInstance();
$store = new InMemoryStore();

$config = $this->getDefaultConfig();
$config->setMaxNumberOfFailures(3);
$config = Config::make('test-service', [
'max_number_of_failures' => 3,
]);

$circuitBreaker = new CircuitBreaker($config, $store);

Expand All @@ -125,9 +128,11 @@ public function test_if_it_will_open_circuit_after_failure_threshold()

public function test_if_counter_is_reset_after_circuit_change_state_from_close_to_open()
{
$store = $this->getStoreInstance();
$config = $this->getDefaultConfig();
$config->setMaxNumberOfFailures(3);
$store = new InMemoryStore();

$config = Config::make('test-service', [
'max_number_of_failures' => 3,
]);

$circuitBreaker = new CircuitBreaker($config, $store);

Expand All @@ -153,14 +158,15 @@ public function test_if_counter_is_reset_after_circuit_change_state_from_close_t

public function test_if_it_will_close_circuit_after_success_calls()
{
$store = $this->getStoreInstance();
$store = new InMemoryStore();
$store->open();

Carbon::setTestNow(Carbon::yesterday());

$config = $this->getDefaultConfig();
$config->setNumberOfSuccessToCloseState(3)
->setOpenToHalfOpenWaitTime(0);
$config = Config::make('service-test', [
'open_to_half_open_wait_time' => 0,
'number_of_success_to_close_state' => 3,
]);

$circuitBreaker = new CircuitBreaker($config, $store);

Expand All @@ -181,14 +187,15 @@ public function test_if_it_will_close_circuit_after_success_calls()

public function test_if_it_will_transit_back_to_closed_state_after_first_fail()
{
$store = $this->getStoreInstance();
$store = new InMemoryStore();
$store->state = CircuitState::Open;

Carbon::setTestNow(Carbon::yesterday());

$config = $this->getDefaultConfig();
$config->setNumberOfSuccessToCloseState(3)
->setOpenToHalfOpenWaitTime(0);
$config = Config::make('service-test', [
'number_of_success_to_close_state' => 3,
'open_to_half_open_wait_time' => 0,
]);

$circuitBreaker = new CircuitBreaker($config, $store);

Expand Down Expand Up @@ -224,11 +231,6 @@ public function getDefaultConfig()
return new Config("test-service");
}

private function getStoreInstance()
{
return new InMemoryStore();
}

// public function test_if_it_will_fail_after_percentage_threshold_for_failure()
// {
//
Expand Down

0 comments on commit c7b6792

Please sign in to comment.