Skip to content

Commit 473b263

Browse files
committed
add metricspoller(phystrix-dashboard)
- add badges - fix phystrix-dashboard errors - add apcu libraries - RequestCache support PSR-16 - default command key format changed. App\Phystrix\DummyCommand => App.Phystrix.DummyCommand
1 parent 9a62894 commit 473b263

13 files changed

+802
-105
lines changed

README.md

+16-7
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,13 @@
11
# Modern Phystrix
22

33
[![Build Status](https://travis-ci.org/yupmin/phystrix.svg)](https://travis-ci.org/yupmin/phystrix)
4+
[![Latest Stable Version](https://poser.pugx.org/yupmin/modern-phystrix/v/stable)](https://packagist.org/packages/yupmin/modern-phystrix)
5+
[![Total Downloads](https://poser.pugx.org/yupmin/modern-phystrix/downloads)](https://packagist.org/packages/yupmin/modern-phystrix)
6+
[![License](https://poser.pugx.org/yupmin/modern-phystrix/license)](https://packagist.org/packages/yupmin/modern-phystrix)
7+
[![Coding Standards](https://img.shields.io/badge/cs-PSR--2--R-yellow.svg)](https://github.com/php-fig-rectified/fig-rectified-standards)
48

59
## Requirement
10+
611
* PHP 5.6 above
712
* Modern PHP
813

@@ -14,11 +19,15 @@ Phystrix protects the points of access to remote resources by keeping track of v
1419

1520
In case of a service failing way too often, to not make the situation worse, Phystrix will temporarily stop issuing requests to it. When the service comes back to life, Phystrix allows the client application to access it again.
1621

17-
And I fixed more for Modern PHP
18-
* Use PHP 5.6 above
19-
* Deleted 'Zend DI' and User 'PSR DI'
20-
* DI is optional. (for using Your framework)
21-
* PSR2 is default.
22+
### Differences from [older version(upwork/phystrix)](https://github.com/upwork/phystrix)
23+
24+
* Use PHP 5.6 and PHP 7 above
25+
* Change from 'Zend DI' to 'PSR DI', DI is optional. (for using Your framework)
26+
* Add [phystrix dashboard](https://github.com/upwork/phystrix-dashboard) library, and fix more.
27+
* Add Libraries of APCU
28+
* PSR-2: Coding Style is default.
29+
* PSR-3: Logger Interface(coming soon)
30+
* PSR-16: Common Interface for Caching Libraries
2231

2332
### Understanding Phystrix
2433

@@ -41,8 +50,8 @@ To store and share metrics between requests, Phystrix uses [APC](http://php.net/
4150

4251
### Php 7.2
4352

44-
In php 7 the API for `apcu` changed. You will need to install [apcu-bc](https://github.com/krakjoe/apcu-bc) in addition to `apcu` to use Phystrix.
45-
The backwards compatibility layer extension must be loaded AFTER `apcu`.
53+
In php 7 the API for `apcu` changed. You must use `ApcuStateStorage` and `ApcuMetricsPoller`. ~~You will need to install [apcu-bc](https://github.com/krakjoe/apcu-bc) in addition to `apcu` to use Phystrix.
54+
The backwards compatibility layer extension must be loaded AFTER `apcu`.~~
4655

4756
## Usage
4857

composer.json

+5-2
Original file line numberDiff line numberDiff line change
@@ -13,8 +13,11 @@
1313
},
1414
"require": {
1515
"php": ">=5.6",
16+
"ext-apcu": "*",
17+
"ext-json": "*",
1618
"psr/container": "^1.0",
17-
"zendframework/zend-config": "^3.2"
19+
"zendframework/zend-config": "^3.2",
20+
"psr/simple-cache": "^1.0"
1821
},
1922
"require-dev": {
2023
"php-di/php-di": "~5.4",
@@ -23,7 +26,7 @@
2326
},
2427
"extra": {
2528
"branch-alias": {
26-
"dev-master": "2.0-dev"
29+
"dev-master": "3.0-dev"
2730
}
2831
}
2932
}

library/Odesk/Phystrix/AbstractCommand.php

+11-9
Original file line numberDiff line numberDiff line change
@@ -22,6 +22,7 @@
2222
use Odesk\Phystrix\Exception\FallbackNotAvailableException;
2323
use Odesk\Phystrix\Exception\RuntimeException;
2424
use Psr\Container\ContainerInterface;
25+
use Psr\SimpleCache\CacheInterface;
2526
use Zend\Config\Config;
2627
use Exception;
2728

@@ -69,7 +70,7 @@ abstract class AbstractCommand
6970
protected $container;
7071

7172
/**
72-
* @var RequestCache
73+
* @var CacheInterface
7374
*/
7475
private $requestCache;
7576

@@ -117,9 +118,9 @@ public function getCommandKey()
117118
return $this->commandKey;
118119
} else {
119120
// If the command key hasn't been defined in the class we use the current class name
121+
// but hystrix dashboard not work, because fixed below.
120122
// refs : https://github.com/persevereVon/preq-laravel/blob/master/src/AbstractCommand.php#L100
121-
// return str_replace('\\', '.', get_class($this));
122-
return get_class($this);
123+
return str_replace('\\', '.', get_class($this));
123124
}
124125
}
125126

@@ -146,9 +147,9 @@ public function setCommandMetricsFactory(CommandMetricsFactory $commandMetricsFa
146147
/**
147148
* Sets shared object for request caching
148149
*
149-
* @param RequestCache $requestCache
150+
* @param CacheInterface $requestCache
150151
*/
151-
public function setRequestCache(RequestCache $requestCache)
152+
public function setRequestCache(CacheInterface $requestCache)
152153
{
153154
$this->requestCache = $requestCache;
154155
}
@@ -201,7 +202,7 @@ public function setConfig(Config $config, $merge = true)
201202
*/
202203
private function isRequestCacheEnabled()
203204
{
204-
if (!$this->requestCache) {
205+
if (!$this->requestCache instanceof CacheInterface) {
205206
return false;
206207
}
207208

@@ -215,6 +216,7 @@ private function isRequestCacheEnabled()
215216
* @return mixed
216217
* @throws BadRequestException Re-throws it when the command throws it, without metrics tracking
217218
* @throws Exception
219+
* @throws \Psr\SimpleCache\InvalidArgumentException
218220
*/
219221
public function execute()
220222
{
@@ -227,11 +229,11 @@ public function execute()
227229

228230
// trying from cache first
229231
if ($cacheEnabled) {
230-
$cacheHit = $this->requestCache->exists($this->getCommandKey(), $this->getCacheKey());
232+
$cacheHit = $this->requestCache->has($this->getCommandKey().'.'.$this->getCacheKey());
231233
if ($cacheHit) {
232234
$metrics->markResponseFromCache();
233235
$this->recordExecutionEvent(self::EVENT_RESPONSE_FROM_CACHE);
234-
return $this->requestCache->get($this->getCommandKey(), $this->getCacheKey());
236+
return $this->requestCache->get($this->getCommandKey().'.'.$this->getCacheKey());
235237
}
236238
}
237239
$circuitBreaker = $this->getCircuitBreaker();
@@ -261,7 +263,7 @@ public function execute()
261263

262264
// putting the result into cache
263265
if ($cacheEnabled) {
264-
$this->requestCache->put($this->getCommandKey(), $this->getCacheKey(), $result);
266+
$this->requestCache->set($this->getCommandKey().'.'.$this->getCacheKey(), $result);
265267
}
266268

267269
return $result;
+157
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,157 @@
1+
<?php
2+
/**
3+
* This file is a part of the Phystrix library
4+
*
5+
* Copyright 2013-2014 oDesk Corporation. All Rights Reserved.
6+
*
7+
* This file is licensed under the Apache License, Version 2.0 (the "License");
8+
* you may not use this file except in compliance with the License.
9+
* You may obtain a copy of the License at
10+
*
11+
* http://www.apache.org/licenses/LICENSE-2.0
12+
*
13+
* Unless required by applicable law or agreed to in writing, software
14+
* distributed under the License is distributed on an "AS IS" BASIS,
15+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
16+
* See the License for the specific language governing permissions and
17+
* limitations under the License.
18+
*/
19+
namespace Odesk\Phystrix;
20+
21+
/**
22+
* APCU cache driven storage for Circuit Breaker metrics statistics
23+
*/
24+
class ApcuStateStorage implements StateStorageInterface
25+
{
26+
const BUCKET_EXPIRE_SECONDS = 120;
27+
28+
const CACHE_PREFIX = 'phystrix_cb_';
29+
30+
const OPENED_NAME = 'opened';
31+
32+
const SINGLE_TEST_BLOCKED = 'single_test_blocked';
33+
34+
/**
35+
* Constructor
36+
* @throws Exception\ApcNotLoadedException
37+
*/
38+
public function __construct()
39+
{
40+
if (!extension_loaded('apcu')) {
41+
throw new Exception\ApcNotLoadedException('"apcu" PHP extension is required for Phystrix to work');
42+
}
43+
}
44+
45+
/**
46+
* Prepends cache prefix and filters out invalid characters
47+
*
48+
* @param string $name
49+
* @return string
50+
*/
51+
protected function prefix($name)
52+
{
53+
return self::CACHE_PREFIX . $name;
54+
}
55+
56+
/**
57+
* Returns counter value for the given bucket
58+
*
59+
* @param string $commandKey
60+
* @param string $type
61+
* @param integer $index
62+
* @return integer
63+
*/
64+
public function getBucket($commandKey, $type, $index)
65+
{
66+
$bucketName = $this->prefix($commandKey . '_' . $type . '_' . $index);
67+
return apcu_fetch($bucketName);
68+
}
69+
70+
/**
71+
* Increments counter value for the given bucket
72+
*
73+
* @param string $commandKey
74+
* @param string $type
75+
* @param integer $index
76+
*/
77+
public function incrementBucket($commandKey, $type, $index)
78+
{
79+
$bucketName = $this->prefix($commandKey . '_' . $type . '_' . $index);
80+
if (!apcu_add($bucketName, 1, self::BUCKET_EXPIRE_SECONDS)) {
81+
apcu_inc($bucketName);
82+
}
83+
}
84+
85+
/**
86+
* If the given bucket is found, sets counter value to 0.
87+
*
88+
* @param string $commandKey Circuit breaker key
89+
* @param string $type
90+
* @param integer $index
91+
*/
92+
public function resetBucket($commandKey, $type, $index)
93+
{
94+
$bucketName = $this->prefix($commandKey . '_' . $type . '_' . $index);
95+
if (apcu_exists($bucketName)) {
96+
apcu_store($bucketName, 0, self::BUCKET_EXPIRE_SECONDS);
97+
}
98+
}
99+
100+
/**
101+
* Marks the given circuit as open
102+
*
103+
* @param string $commandKey Circuit key
104+
* @param integer $sleepingWindowInMilliseconds In how much time we should allow a single test
105+
*/
106+
public function openCircuit($commandKey, $sleepingWindowInMilliseconds)
107+
{
108+
$openedKey = $this->prefix($commandKey . self::OPENED_NAME);
109+
$singleTestFlagKey = $this->prefix($commandKey . self::SINGLE_TEST_BLOCKED);
110+
111+
apcu_store($openedKey, true);
112+
// the single test blocked flag will expire automatically in $sleepingWindowInMilliseconds
113+
// thus allowing us a single test. Notice, APC doesn't allow us to use
114+
// expire time less than a second.
115+
$sleepingWindowInSeconds = ceil($sleepingWindowInMilliseconds / 1000);
116+
apcu_add($singleTestFlagKey, true, $sleepingWindowInSeconds);
117+
}
118+
119+
/**
120+
* Whether a single test is allowed
121+
*
122+
* @param string $commandKey Circuit breaker key
123+
* @param integer $sleepingWindowInMilliseconds In how much time we should allow the next single test
124+
* @return boolean
125+
*/
126+
public function allowSingleTest($commandKey, $sleepingWindowInMilliseconds)
127+
{
128+
$singleTestFlagKey = $this->prefix($commandKey . self::SINGLE_TEST_BLOCKED);
129+
// using 'add' enforces thread safety.
130+
$sleepingWindowInSeconds = ceil($sleepingWindowInMilliseconds / 1000);
131+
// another APCU limitation is that within the current request variables will never expire.
132+
return (boolean) apcu_add($singleTestFlagKey, true, $sleepingWindowInSeconds);
133+
}
134+
135+
/**
136+
* Whether a circuit is open
137+
*
138+
* @param string $commandKey Circuit breaker key
139+
* @return boolean
140+
*/
141+
public function isCircuitOpen($commandKey)
142+
{
143+
$openedKey = $this->prefix($commandKey . self::OPENED_NAME);
144+
return (boolean) apcu_fetch($openedKey);
145+
}
146+
147+
/**
148+
* Marks the given circuit as closed
149+
*
150+
* @param string $commandKey Circuit key
151+
*/
152+
public function closeCircuit($commandKey)
153+
{
154+
$openedKey = $this->prefix($commandKey . self::OPENED_NAME);
155+
apcu_store($openedKey, false);
156+
}
157+
}

library/Odesk/Phystrix/CommandFactory.php

+4-3
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,7 @@
1818
*/
1919
namespace Odesk\Phystrix;
2020

21+
use Psr\SimpleCache\CacheInterface;
2122
use ReflectionClass;
2223
use ReflectionException;
2324
use Psr\Container\ContainerInterface;
@@ -50,7 +51,7 @@ class CommandFactory
5051
protected $commandMetricsFactory;
5152

5253
/**
53-
* @var RequestCache
54+
* @var CacheInterface
5455
*/
5556
protected $requestCache;
5657

@@ -65,15 +66,15 @@ class CommandFactory
6566
* @param Config $config
6667
* @param CircuitBreakerFactory $circuitBreakerFactory
6768
* @param CommandMetricsFactory $commandMetricsFactory
68-
* @param RequestCache|null $requestCache
69+
* @param CacheInterface|null $requestCache
6970
* @param RequestLog|null $requestLog
7071
* @param ContainerInterface|null $container
7172
*/
7273
public function __construct(
7374
Config $config,
7475
CircuitBreakerFactory $circuitBreakerFactory,
7576
CommandMetricsFactory $commandMetricsFactory,
76-
RequestCache $requestCache = null,
77+
CacheInterface $requestCache = null,
7778
RequestLog $requestLog = null,
7879
ContainerInterface $container = null
7980
) {

0 commit comments

Comments
 (0)