diff --git a/README.md b/README.md index d015e54..fca6c53 100644 --- a/README.md +++ b/README.md @@ -23,6 +23,7 @@ the circuit breaker: * the **failures**: define how much times we try to access the service; * the **timeout**: define how much time we wait before consider the service unreachable; +* the **striped timeout**: define how much time we wait before consider the service unreachable, once we're in half open state; * the **threshold**: define how much time we wait before trying to access again the service; We also need to define which (HTTP) client will be used to call the service. @@ -37,9 +38,10 @@ use Resiliency\SimpleCircuitBreakerFactory; $circuitBreakerFactory = new SimpleCircuitBreakerFactory(); $circuitBreaker = $circuitBreakerFactory->create( [ - 'closed' => [2, 0.1, 0.1], - 'open' => [0, 0.0, 10.0], - 'half_open' => [1, 0.2, 0.0], + 'failures' => 2, + 'timeout' => 0.1, + 'stripped_timeout' => 0.2, + 'threshold' => 10.0, 'client' => [ 'proxy' => '192.168.16.1:10', 'method' => 'POST', diff --git a/src/Contracts/CircuitBreaker.php b/src/Contracts/CircuitBreaker.php index 2ded73e..5d2426b 100644 --- a/src/Contracts/CircuitBreaker.php +++ b/src/Contracts/CircuitBreaker.php @@ -17,9 +17,9 @@ public function getState(): string; /** * The function that execute the service. * - * @param string $service the service to call - * @param array $serviceParameters the service parameters - * @param callable $fallback if the service is unavailable, rely on the fallback + * @param string $service the service to call + * @param array $serviceParameters the service parameters + * @param callable $fallback if the service is unavailable, rely on the fallback * * @return string */ diff --git a/src/Contracts/Client.php b/src/Contracts/Client.php index be0f0da..f52d716 100644 --- a/src/Contracts/Client.php +++ b/src/Contracts/Client.php @@ -15,7 +15,7 @@ interface Client /** * @param string $resource the URI of the service to be reached - * @param array $options the options if needed + * @param array $options the options if needed * * @return string */ diff --git a/src/Contracts/Storage.php b/src/Contracts/Storage.php index 5a2f442..bf4b28e 100644 --- a/src/Contracts/Storage.php +++ b/src/Contracts/Storage.php @@ -13,8 +13,8 @@ interface Storage /** * Save the CircuitBreaker transaction. * - * @param string $service The service name - * @param Transaction $transaction the transaction + * @param string $service The service name + * @param Transaction $transaction The transaction * * @return bool */ diff --git a/src/Contracts/TransitionDispatcher.php b/src/Contracts/TransitionDispatcher.php index 8264f36..4c40ade 100644 --- a/src/Contracts/TransitionDispatcher.php +++ b/src/Contracts/TransitionDispatcher.php @@ -12,9 +12,9 @@ interface TransitionDispatcher * Dispatch a Circuit Breaker transition. * * @param CircuitBreaker $circuitBreaker the Circuit Breaker - * @param string $transition the Circuit Breaker transition name - * @param string $service the URI service called - * @param array $parameters the service parameters + * @param string $transition the Circuit Breaker transition name + * @param string $service the URI service called + * @param array $parameters the service parameters */ public function dispatch(CircuitBreaker $circuitBreaker, $transition, $service, array $parameters): void; } diff --git a/src/Events/TransitionEvent.php b/src/Events/TransitionEvent.php index 0ae95bf..d379c97 100644 --- a/src/Events/TransitionEvent.php +++ b/src/Events/TransitionEvent.php @@ -28,9 +28,9 @@ class TransitionEvent extends Event private $parameters; /** - * @param string $eventName the transition name - * @param string $service the Service URI - * @param array $parameters the Service parameters + * @param string $eventName the transition name + * @param string $service the Service URI + * @param array $parameters the Service parameters */ public function __construct(CircuitBreaker $circuitBreaker, $eventName, $service, array $parameters) { diff --git a/src/Exceptions/InvalidPlace.php b/src/Exceptions/InvalidPlace.php index bb1ae63..3816174 100644 --- a/src/Exceptions/InvalidPlace.php +++ b/src/Exceptions/InvalidPlace.php @@ -9,8 +9,8 @@ final class InvalidPlace extends Exception implements ResiliencyException { /** - * @param mixed $failures the failures - * @param mixed $timeout the timeout + * @param mixed $failures the failures + * @param mixed $timeout the timeout * @param mixed $threshold the threshold * * @return self @@ -20,8 +20,7 @@ public static function invalidSettings($failures, $timeout, $threshold): self $exceptionMessage = 'Invalid settings for Place' . PHP_EOL . ErrorFormatter::format('failures', $failures, 'isPositiveInteger', 'a positive integer') . ErrorFormatter::format('timeout', $timeout, 'isPositiveValue', 'a float') . - ErrorFormatter::format('threshold', $threshold, 'isPositiveInteger', 'a positive integer') - ; + ErrorFormatter::format('threshold', $threshold, 'isPositiveInteger', 'a positive integer'); return new self($exceptionMessage); } diff --git a/src/Exceptions/InvalidSystem.php b/src/Exceptions/InvalidSystem.php new file mode 100644 index 0000000..d913422 --- /dev/null +++ b/src/Exceptions/InvalidSystem.php @@ -0,0 +1,34 @@ +client->request( $service, - array_merge($parameters, [ - 'connect_timeout' => $this->currentPlace->getTimeout(), - 'timeout' => $this->currentPlace->getTimeout(), - ]) + array_merge( + $parameters, + [ + 'connect_timeout' => $this->currentPlace->getTimeout(), + 'timeout' => $this->currentPlace->getTimeout(), + ] + ) ); } @@ -229,8 +232,8 @@ private function request(string $service, array $parameters = []): string * Helper to dispatch transition events. * * @param string $transition the transition name - * @param string $service the URI service called - * @param array $parameters the service parameters + * @param string $service the URI service called + * @param array $parameters the service parameters */ private function dispatch($transition, $service, array $parameters): void { @@ -240,7 +243,6 @@ private function dispatch($transition, $service, array $parameters): void $transition, $service, $parameters - ) - ; + ); } } diff --git a/src/Places/AbstractPlace.php b/src/Places/AbstractPlace.php index 81139a1..e07bd58 100644 --- a/src/Places/AbstractPlace.php +++ b/src/Places/AbstractPlace.php @@ -24,8 +24,8 @@ abstract class AbstractPlace implements Place private $threshold; /** - * @param int $failures the Place failures - * @param float $timeout the Place timeout + * @param int $failures the Place failures + * @param float $timeout the Place timeout * @param float $threshold the Place threshold */ public function __construct(int $failures, float $timeout, float $threshold) @@ -81,8 +81,8 @@ public static function fromArray(array $settings): self /** * Ensure the place is valid * - * @param int $failures the failures should be a positive value - * @param float $timeout the timeout should be a positive value + * @param int $failures the failures should be a positive value + * @param float $timeout the timeout should be a positive value * @param float $threshold the threshold should be a positive value * * @throws InvalidPlace @@ -93,8 +93,7 @@ private function validate(int $failures, float $timeout, float $threshold): bool { $assertionsAreValid = Assert::isPositiveInteger($failures) && Assert::isPositiveValue($timeout) - && Assert::isPositiveValue($threshold) - ; + && Assert::isPositiveValue($threshold); if ($assertionsAreValid) { return true; diff --git a/src/Places/ClosedPlace.php b/src/Places/ClosedPlace.php index 9779fb1..0a854a9 100644 --- a/src/Places/ClosedPlace.php +++ b/src/Places/ClosedPlace.php @@ -6,6 +6,16 @@ final class ClosedPlace extends AbstractPlace { + /** + * @param int $failures the Place failures + * @param float $timeout the Place timeout + * @param float $threshold the Place threshold + */ + public function __construct(int $failures, float $timeout, float $threshold) + { + parent::__construct($failures, $timeout, 0.0); + } + /** * {@inheritdoc} */ diff --git a/src/Places/HalfOpenPlace.php b/src/Places/HalfOpenPlace.php index c11dfa8..9c83d01 100644 --- a/src/Places/HalfOpenPlace.php +++ b/src/Places/HalfOpenPlace.php @@ -6,6 +6,16 @@ final class HalfOpenPlace extends AbstractPlace { + /** + * @param int $failures the Place failures + * @param float $timeout the Place timeout + * @param float $threshold the Place threshold + */ + public function __construct(int $failures, float $timeout, float $threshold) + { + parent::__construct(0, $timeout, 0.0); + } + /** * {@inheritdoc} */ diff --git a/src/Places/OpenPlace.php b/src/Places/OpenPlace.php index 6572168..010d268 100644 --- a/src/Places/OpenPlace.php +++ b/src/Places/OpenPlace.php @@ -6,6 +6,16 @@ final class OpenPlace extends AbstractPlace { + /** + * @param int $failures the Place failures + * @param float $timeout the Place timeout + * @param float $threshold the Place threshold + */ + public function __construct(int $failures, float $timeout, float $threshold) + { + parent::__construct(0, 0, $threshold); + } + /** * {@inheritdoc} */ diff --git a/src/Systems/MainSystem.php b/src/Systems/MainSystem.php index 18bbfae..e07e430 100644 --- a/src/Systems/MainSystem.php +++ b/src/Systems/MainSystem.php @@ -2,12 +2,13 @@ namespace Resiliency\Systems; +use Resiliency\States; use Resiliency\Contracts\Place; use Resiliency\Contracts\System; +use Resiliency\Places\OpenPlace; use Resiliency\Places\ClosedPlace; use Resiliency\Places\HalfOpenPlace; -use Resiliency\Places\OpenPlace; -use Resiliency\States; +use Resiliency\Exceptions\InvalidSystem; /** * Implement the system described by the documentation. @@ -19,15 +20,21 @@ final class MainSystem implements System { /** - * @var Place[] + * @param int $failures the number of allowed failures + * @param float $timeout the timeout in milliseconds + * @param float $strippedTimeout the timeout in milliseconds when trying again + * @param float $threshold the timeout in milliseconds before trying again */ - private $places; - public function __construct( - Place $closedPlace, - Place $halfOpenPlace, - Place $openPlace + int $failures, + float $timeout, + float $strippedTimeout, + float $threshold ) { + $closedPlace = new ClosedPlace($failures, $timeout, 0); + $halfOpenPlace = new HalfOpenPlace(0, $strippedTimeout, 0); + $openPlace = new OpenPlace(0, 0, $threshold); + $this->places = [ $closedPlace->getState() => $closedPlace, $halfOpenPlace->getState() => $halfOpenPlace, @@ -58,10 +65,19 @@ public function getPlaces(): array */ public static function createFromArray(array $settings): self { - $openPlace = OpenPlace::fromArray((array) $settings['open']); - $halfOpenPlace = HalfOpenPlace::fromArray((array) $settings['half_open']); - $closedPlace = ClosedPlace::fromArray((array) $settings['closed']); + if (array_key_exists('failures', $settings) + && array_key_exists('timeout', $settings) + && array_key_exists('stripped_timeout', $settings) + && array_key_exists('threshold', $settings) + ) { + return new self( + $settings['failures'], + $settings['timeout'], + $settings['stripped_timeout'], + $settings['threshold'] + ); + } - return new self($closedPlace, $halfOpenPlace, $openPlace); + throw InvalidSystem::missingSettings($settings); } } diff --git a/src/Transactions/SimpleTransaction.php b/src/Transactions/SimpleTransaction.php index da24043..3d907d4 100644 --- a/src/Transactions/SimpleTransaction.php +++ b/src/Transactions/SimpleTransaction.php @@ -34,10 +34,10 @@ final class SimpleTransaction implements Transaction private $thresholdDateTime; /** - * @param string $service the service URI - * @param int $failures the allowed failures - * @param string $state the circuit breaker state/place - * @param float $threshold the place threshold + * @param string $service the service URI + * @param int $failures the allowed failures + * @param string $state the circuit breaker state/place + * @param float $threshold the place threshold */ public function __construct(string $service, int $failures, string $state, float $threshold) { @@ -94,7 +94,7 @@ public function incrementFailures(): bool /** * Helper to create a transaction from the Place. * - * @param Place $place the Circuit Breaker place + * @param Place $place the Circuit Breaker place * @param string $service the service URI * * @return self @@ -129,10 +129,10 @@ private function initThresholdDateTime(float $threshold): void /** * Ensure the transaction is valid. * - * @param string $service the service URI - * @param int $failures the failures should be a positive value - * @param string $state the Circuit Breaker state - * @param float $threshold the threshold should be a positive value + * @param string $service the service URI + * @param int $failures the failures should be a positive value + * @param string $state the Circuit Breaker state + * @param float $threshold the threshold should be a positive value * * @return bool * @@ -143,8 +143,7 @@ private function validate($service, $failures, $state, $threshold): bool $assertionsAreValid = Assert::isURI($service) && Assert::isPositiveInteger($failures) && Assert::isString($state) - && Assert::isPositiveValue($threshold) - ; + && Assert::isPositiveValue($threshold); if ($assertionsAreValid) { return true; diff --git a/src/Utils/Assert.php b/src/Utils/Assert.php index ba9dd77..4cb62fb 100644 --- a/src/Utils/Assert.php +++ b/src/Utils/Assert.php @@ -39,8 +39,7 @@ public static function isURI($value): bool return null !== $value && !is_numeric($value) && !\is_bool($value) - && false !== filter_var($value, FILTER_SANITIZE_URL) - ; + && false !== filter_var($value, FILTER_SANITIZE_URL); } /** diff --git a/src/Utils/ErrorFormatter.php b/src/Utils/ErrorFormatter.php index 56eb796..6b8aca3 100644 --- a/src/Utils/ErrorFormatter.php +++ b/src/Utils/ErrorFormatter.php @@ -12,9 +12,9 @@ final class ErrorFormatter /** * Format error message. * - * @param string $parameter the parameter to evaluate - * @param mixed $value the value to format - * @param string $function the validation function + * @param string $parameter the parameter to evaluate + * @param mixed $value the value to format + * @param string $function the validation function * @param string $expectedType the expected type * * @return string diff --git a/tests/CircuitBreakerTestCase.php b/tests/CircuitBreakerTestCase.php index a8990be..13f907a 100644 --- a/tests/CircuitBreakerTestCase.php +++ b/tests/CircuitBreakerTestCase.php @@ -44,9 +44,10 @@ protected function getSystem(): MainSystem { return MainSystem::createFromArray( [ - 'open' => [0, 0.0, 1.0], // threshold 1.0s - 'half_open' => [1, 0.4, 0.0], // timeout 0.4s to test the service with a better timeout - 'closed' => [2, 0.2, 0.0], // 2 failures allowed, 0.2s timeout + 'failures' => 2, + 'timeout' => 0.2, + 'stripped_timeout' => 0.4, + 'threshold' => 1.0, ] ); } diff --git a/tests/SimpleCircuitBreakerFactoryTest.php b/tests/SimpleCircuitBreakerFactoryTest.php index 13bfe96..63707d9 100644 --- a/tests/SimpleCircuitBreakerFactoryTest.php +++ b/tests/SimpleCircuitBreakerFactoryTest.php @@ -42,17 +42,21 @@ public function getSettings(): array return [ [ [ - 'closed' => [2, 0.1, 0], - 'open' => [0, 0, 10], - 'half_open' => [1, 0.2, 0], + 'failures' => 2, + 'timeout' => 0.1, + 'stripped_timeout' => 0.2, + 'threshold' => 10, ], ], [ [ - 'closed' => [2, 0.1, 0], - 'open' => [0, 0, 10], - 'half_open' => [1, 0.2, 0], - 'client' => ['proxy' => '192.168.16.1:10'], + 'failures' => 2, + 'timeout' => 0.1, + 'stripped_timeout' => 0.2, + 'threshold' => 1.0, + 'client' => [ + 'proxy' => '192.168.16.1:10', + ], ], ], ];