Merge branch 'master' into pr/873

This commit is contained in:
李铭昕 2019-11-07 09:33:27 +08:00
commit 0bc87fc7f1
12 changed files with 174 additions and 20 deletions

View File

@ -5,20 +5,21 @@
- [#812](https://github.com/hyperf/hyperf/pull/812) Added singleton crontab task support.
- [#832](https://github.com/hyperf/hyperf/pull/832) Added `Hyperf\Utils\Codec\Json`.
- [#833](https://github.com/hyperf/hyperf/pull/833) Added `Hyperf\Utils\Backoff`.
- [#852](https://github.com/hyperf/hyperf/pull/852) Added method `clear` for Parallel to clear callbacks.
- [#852](https://github.com/hyperf/hyperf/pull/852) Added a `clear()` method for `Hyperf\Utils\Parallel` to clear adde callbacks.
- [#873](https://github.com/hyperf/hyperf/pull/873) Added redis cluster.
## Fixed
- [#831](https://github.com/hyperf/hyperf/pull/831) Fixed Redis client can not reconnect the server after the Redis server restarted.
- [#835](https://github.com/hyperf/hyperf/pull/835) Fixed `Request::inputs` default value does not works.
- [#841](https://github.com/hyperf/hyperf/pull/841) Fixed migration does not take effect under multiple data sources.
- [#844](https://github.com/hyperf/hyperf/pull/844) Fixed the composer.json reader support root namespace.
- [#844](https://github.com/hyperf/hyperf/pull/844) Fixed the reader of `composer.json` does not support the root namespace.
- [#850](https://github.com/hyperf/hyperf/pull/850) Fixed logger group does not works when the name is same.
## Optimized
- [#832](https://github.com/hyperf/hyperf/pull/832) Optimized that response will throw a exception when json format failed.
- [#840](https://github.com/hyperf/hyperf/pull/840) Use swoole timer function from namespace.
- [#840](https://github.com/hyperf/hyperf/pull/840) Use `\Swoole\Timer::*` to instead of `swoole_timer_*` functions.
# v1.1.4 - 2019-10-31

View File

@ -36,12 +36,35 @@ class ConfigProvider
'commands' => [],
// 与 commands 类似
'listeners' => [],
// 亦可继续定义其它配置,最终都会何必到与 ConfigInterface 对应的配置储存器中
// 组件默认配置文件,即执行命令后会把 source 的对应的文件复制为 destination 对应的的文件
'publish' => [
[
'id' => 'config',
'description' => 'description of this config file.', // 描述
// 建议默认配置放在 publish 文件夹中,文件命名和组件名称相同
'source' => __DIR__ . '/../publish/file.php', // 对应的配置文件路径
'destination' => BASE_PATH . '/config/autoload/file.php', // 复制为这个路径下的该文件
],
],
// 亦可继续定义其它配置,最终都会合并到与 ConfigInterface 对应的配置储存器中
];
}
}
```
## 默认配置文件说明
`ConfigProvider` 中定义好 `publish` 后,可以使用如下命令快速生成配置文件
```bash
php bin/hyperf.php vendor:publish 包名称
```
如包名称为 `hyperf/amqp`,可执行命令来生成 `amqp` 默认的配置文件
```bash
php bin/hyperf.php vendor:publish hyperf/amqp
```
只创建一个类并不会被 Hyperf 自动的加载,您仍需在组件的 `composer.json` 添加一些定义,告诉 Hyperf 这是一个 ConfigProvider 类需要被加载,您需要在组件内的 `composer.json` 文件内增加 `extra.hyperf.config` 配置,并指定对应的 `ConfigProvider` 类的命名空间,如下所示:
```json

View File

@ -27,4 +27,4 @@ php bin/hyperf.php
gen:process Create a new process class
vendor
vendor:publish Publish any publishable configs from vendor packages.
```x
```

View File

@ -1,19 +1,32 @@
# Swoole Tracker
[Swoole Tracker](https://www.swoole-cloud.com/tracker.html) 作为 `Swoole` 官方出品的一整套企业级 `PHP``Swoole`分析调试工具更专一、更专业。曾命名Swoole Enterprise
[Swoole Tracker](https://www.swoole-cloud.com/tracker.html)是 Swoole 官方推出的一整套企业级包括 PHP 和 Swoole 分析调试工具以及应用性能管理APM平台针对常规的 FPM 和 Swoole 常驻进程的业务提供全面的性能监控、分析和调试的解决方案。曾命名Swoole Enterprise
Swoole Tracker 能够帮助企业自动分析并汇总统计关键系统调用并智能准确的定位到具体的 PHP 业务代码,实现业务应用性能最优化、强大的调试工具链为企业业务保驾护航、提高 IT 生产效率。
- 时刻掌握应用架构模型
> 自动发现应用依赖拓扑结构和展示,时刻掌握应用的架构模型
- 分布式跨应用链路追踪
> 支持无侵入的分布式跨应用链路追踪,让每个请求一目了然,全面支持协程/非协程环境,数据实时可视化
- 全面分析报告服务状况
> 各种维度统计服务上报的调用信息, 比如总流量、平均耗时、超时率等,并全面分析报告服务状况
- 拥有强大的调试工具链
> 本系统支持远程调试,可在系统后台远程开启检测内存泄漏、阻塞检测和代码性能分析
> 本系统支持远程调试,可在系统后台远程开启检测内存泄漏、阻塞检测、代码性能分析和查看调用栈;也支持手动埋点进行调试,后台统一查看结果
- 同时支持FPM和Swoole
> 完美支持PHP-FPM环境不仅限于在Swoole中使用
- 完善的系统监控
> 支持完善的系统监控零成本部署监控机器的CPU、内存、网络、磁盘等资源可以很方便的集成到现有报警系统
- 零成本接入系统
> 本系统的客户端提供脚本可一键部署服务端可在Docker环境中运行简单快捷
- 一键安装和零成本接入
> 规避与减小整体投资风险本系统的客户端提供脚本可一键部署服务端可在Docker环境中运行简单快捷
- 提高各部门生产效率
> 在复杂系统中追踪服务及代码层级性能瓶颈帮助IT、开发等部门提升工作效率将重点聚焦在核心工作中
## 安装
@ -46,7 +59,7 @@ extension=/opt/swoole_tracker.so
apm.enable=1 #打开总开关
apm.sampling_rate=100 #采样率 例如100%
# 支持远程调试;需要手动埋点时再添加
# 开启内存泄漏检测时需要添加
apm.enable_memcheck=1 #开启内存泄漏检测 默认0 关闭状态
```

View File

@ -64,6 +64,7 @@ class ConnectionResolver implements ConnectionResolverInterface
if (! $connection instanceof ConnectionInterface) {
$pool = $this->factory->getPool($name);
// When Mysql connect failed, it will be catched by `Hyperf\Database\Connectors\ConnectionFactory`.
$connection = $pool->get()->getConnection();
Context::set($id, $connection);
if (Coroutine::inCoroutine()) {

View File

@ -0,0 +1,10 @@
<?php
namespace Hyperf\Redis\Exception;
class InvalidRedisConnectionException
{
}

View File

@ -39,6 +39,7 @@ class Redis
$connection = $this->getConnection($hasContextConnection);
try {
$connection = $connection->getConnection();
// Execute the command with the arguments.
$result = $connection->{$name}(...$arguments);
} finally {
@ -88,7 +89,7 @@ class Redis
}
if (! $connection instanceof RedisConnection) {
$pool = $this->factory->getPool($this->poolName);
$connection = $pool->get()->getConnection();
return $pool->get();
}
return $connection;
}

View File

@ -13,6 +13,7 @@ declare(strict_types=1);
namespace Hyperf\Redis;
use Hyperf\Contract\ConnectionInterface;
use Hyperf\Contract\StdoutLoggerInterface;
use Hyperf\Pool\Connection as BaseConnection;
use Hyperf\Pool\Exception\ConnectionException;
use Hyperf\Pool\Pool;
@ -61,7 +62,13 @@ class RedisConnection extends BaseConnection implements ConnectionInterface
public function __call($name, $arguments)
{
return $this->connection->{$name}(...$arguments);
try {
$result = $this->connection->{$name}(...$arguments);
} catch (\Throwable $exception) {
$result = $this->retry($name, $arguments, $exception);
}
return $result;
}
public function getActiveConnection()
@ -154,4 +161,20 @@ class RedisConnection extends BaseConnection implements ConnectionInterface
return $redis;
}
protected function retry($name, $arguments, \Throwable $exception)
{
$logger = $this->container->get(StdoutLoggerInterface::class);
$logger->warning(sprintf('Redis::__call failed, bacause ' . $exception->getMessage()));
try {
$this->reconnect();
$result = $this->connection->{$name}(...$arguments);
} catch (\Throwable $exception) {
$this->lastUseTime = 0.0;
throw $exception;
}
return $result;
}
}

View File

@ -15,10 +15,15 @@ namespace HyperfTest\Redis;
use Hyperf\Config\Config;
use Hyperf\Contract\ConfigInterface;
use Hyperf\Di\Container;
use Hyperf\Pool\Channel;
use Hyperf\Pool\PoolOption;
use Hyperf\Redis\Frequency;
use Hyperf\Redis\Pool\PoolFactory;
use Hyperf\Redis\Pool\RedisPool;
use Hyperf\Redis\Redis;
use Hyperf\Utils\ApplicationContext;
use Hyperf\Utils\Context;
use HyperfTest\Redis\Stub\RedisPoolFailedStub;
use HyperfTest\Redis\Stub\RedisPoolStub;
use Mockery;
use PHPUnit\Framework\TestCase;
@ -32,6 +37,7 @@ class RedisTest extends TestCase
public function tearDown()
{
Mockery::close();
Context::set('redis.connection.default', null);
}
public function testRedisConnect()
@ -68,9 +74,38 @@ class RedisTest extends TestCase
$this->assertSame('db:0 name:get argument:xxxx', $res[0]);
}
public function testRedisReuseAfterThrowable()
{
$container = $this->getContainer();
$pool = new RedisPoolFailedStub($container, 'default');
$container->shouldReceive('make')->once()->with(RedisPool::class, ['name' => 'default'])->andReturn($pool);
$factory = new PoolFactory($container);
$redis = new Redis($factory);
try {
$redis->set('xxxx', 'yyyy');
} catch (\Throwable $exception) {
$this->assertSame('Get connection failed.', $exception->getMessage());
}
$this->assertSame(1, $pool->getConnectionsInChannel());
$this->assertSame(1, $pool->getCurrentConnections());
}
private function getRedis()
{
$container = $this->getContainer();
$pool = new RedisPoolStub($container, 'default');
$container->shouldReceive('make')->once()->with(RedisPool::class, ['name' => 'default'])->andReturn($pool);
$factory = new PoolFactory($container);
return new Redis($factory);
}
private function getContainer()
{
$container = Mockery::mock(Container::class);
ApplicationContext::setContainer($container);
$container->shouldReceive('get')->once()->with(ConfigInterface::class)->andReturn(new Config([
'redis' => [
'default' => [
@ -89,13 +124,13 @@ class RedisTest extends TestCase
],
],
]));
$pool = new RedisPoolStub($container, 'default');
$container->shouldReceive('make')->once()->with(RedisPool::class, ['name' => 'default'])->andReturn($pool);
ApplicationContext::setContainer($container);
$factory = new PoolFactory($container);
return new Redis($factory);
$container->shouldReceive('make')->with(Frequency::class, Mockery::any())->andReturn(new Frequency());
$container->shouldReceive('make')->with(PoolOption::class, Mockery::any())->andReturnUsing(function ($class, $args) {
return new PoolOption(...array_values($args));
});
$container->shouldReceive('make')->with(Channel::class, Mockery::any())->andReturnUsing(function ($class, $args) {
return new Channel($args['size']);
});
return $container;
}
}

View File

@ -0,0 +1,21 @@
<?php
declare(strict_types=1);
/**
* This file is part of Hyperf.
*
* @link https://www.hyperf.io
* @document https://doc.hyperf.io
* @contact group@hyperf.io
* @license https://github.com/hyperf/hyperf/blob/master/LICENSE
*/
namespace HyperfTest\Redis\Stub;
class RedisConnectionFailedStub extends RedisConnectionStub
{
public function getConnection()
{
throw new \Exception('Get connection failed.');
}
}

View File

@ -39,6 +39,8 @@ class RedisConnectionStub extends RedisConnection
$this->db = $this->config['db'];
$this->timeout = $this->config['timeout'];
$this->lastUseTime = microtime(true);
return true;
}

View File

@ -0,0 +1,24 @@
<?php
declare(strict_types=1);
/**
* This file is part of Hyperf.
*
* @link https://www.hyperf.io
* @document https://doc.hyperf.io
* @contact group@hyperf.io
* @license https://github.com/hyperf/hyperf/blob/master/LICENSE
*/
namespace HyperfTest\Redis\Stub;
use Hyperf\Contract\ConnectionInterface;
use Hyperf\Redis\Pool\RedisPool;
class RedisPoolFailedStub extends RedisPool
{
protected function createConnection(): ConnectionInterface
{
return new RedisConnectionFailedStub($this->container, $this, $this->config);
}
}