Merge branch 'master' into 3.0-merge

# Conflicts:
#	.github/workflows/test-components.yml
#	.github/workflows/test.yml
#	src/amqp/src/ConnectionFactory.php
This commit is contained in:
李铭昕 2021-12-20 09:49:29 +08:00
commit 06c3f4867e
13 changed files with 172 additions and 45 deletions

View File

@ -6,7 +6,7 @@ on:
schedule:
- cron: '0 2 * * *'
env:
SW_VERSION: 'v4.8.3'
SW_VERSION: 'v4.8.4'
jobs:
database:
name: Test for Database
@ -132,8 +132,6 @@ jobs:
php link_env.phar show:name -N helloworld
sudo chmod u+x link_env.phar
./link_env.phar show:name -N helloworld
container:
name: Test for Psr Container V1.0 ~ V2.0
runs-on: 'ubuntu-latest'

View File

@ -14,7 +14,7 @@ jobs:
matrix:
os: [ ubuntu-latest ]
php-version: [ '8.0', '8.1' ]
sw-version: [ 'v4.5.11', 'v4.6.7', 'v4.7.1', 'v4.8.3', 'master' ]
sw-version: [ 'v4.5.11', 'v4.6.7', 'v4.7.1', 'v4.8.4', 'master' ]
exclude:
- php-version: '8.1'
sw-version: 'v4.5.11'

View File

@ -1,8 +1,11 @@
# v2.2.21 - TBD
# v2.2.22 - TBD
# v2.2.21 - 2021-12-20
## Fixed
- [#4347](https://github.com/hyperf/hyperf/pull/4347) Fixed bug that amqp io has been bound to more than one coroutine when out of buffer.
- [#4373](https://github.com/hyperf/hyperf/pull/4373) Fixed the metadata generation error caused by switching coroutine for snowflake.
## Added
@ -12,6 +15,7 @@
## Optimized
- [#4350](https://github.com/hyperf/hyperf/pull/4350) Optimized the error message for `swoole.use_shortname`.
- [#4360](https://github.com/hyperf/hyperf/pull/4360) No longer uses `Swoole\Coroutine\Client`, but uses `Swoole\Coroutine\Socket`, which is more stable and has better performance in `Hyperf\Amqp\IO\SwooleIO`.
# v2.2.20 - 2021-12-13

View File

@ -1,5 +1,22 @@
# 版本更新记录
# v2.2.21 - 2021-12-20
## 修复
- [#4347](https://github.com/hyperf/hyperf/pull/4347) 修复使用 `AMQP` 组件时,如果连接缓冲区溢出,会导致连接被绑定到多个协程从而报错的问题。
- [#4373](https://github.com/hyperf/hyperf/pull/4373) 修复使用 `Snowflake` 组件时,由于 `getWorkerId()` 中存在 `IO` 操作进而导致协程切换,最终导致元数据生成重复的问题。
## 新增
- [#4344](https://github.com/hyperf/hyperf/pull/4344) 新增事件 `Hyperf\Crontab\Event\FailToExecute`,此事件会在 `Crontab` 任务执行失败时触发。
- [#4348](https://github.com/hyperf/hyperf/pull/4348) 支持使用 `gen:*` 命令创建文件时,自动吊起对应的 `IDE`,并打开当前文件。
## 优化
- [#4350](https://github.com/hyperf/hyperf/pull/4350) 优化了未开启 `swoole.use_shortname` 时的错误信息。
- [#4360](https://github.com/hyperf/hyperf/pull/4360) 将 `Hyperf\Amqp\IO\SwooleIO` 进行重构,使用更加稳定和高效的 `Swoole\Coroutine\Socket` 而非 `Swoole\Coroutine\Client`
# v2.2.20 - 2021-12-13
## 修复

View File

@ -169,3 +169,15 @@ http2 => enabled
如果没有,需要重新编译 Swoole 并增加 `--enable-http2` 参数。
2. 检查 [server.php](/zh-cn/config?id=serverphp-配置说明) 文件中 `open_http2_protocol` 选项是否为 `true`
## Command 无法正常关闭
在 Command 中使用 AMQP 等多路复用技术后,会导致无法正常关闭,碰到这种情况只需要在执行逻辑最后增加以下代码即可。
```php
<?php
use Hyperf\Utils\Coordinator\CoordinatorManager;
use Hyperf\Utils\Coordinator\Constants;
CoordinatorManager::until(Constants::WORKER_EXIT)->resume();
```

View File

@ -1,5 +1,22 @@
# 版本更新記錄
# v2.2.21 - 2021-12-20
## 修復
- [#4347](https://github.com/hyperf/hyperf/pull/4347) 修復使用 `AMQP` 組件時,如果連接緩衝區溢出,會導致連接被綁定到多個協程從而報錯的問題。
- [#4373](https://github.com/hyperf/hyperf/pull/4373) 修復使用 `Snowflake` 組件時,由於 `getWorkerId()` 中存在 `IO` 操作進而導致協程切換,最終導致元數據生成重複的問題。
## 新增
- [#4344](https://github.com/hyperf/hyperf/pull/4344) 新增事件 `Hyperf\Crontab\Event\FailToExecute`,此事件會在 `Crontab` 任務執行失敗時觸發。
- [#4348](https://github.com/hyperf/hyperf/pull/4348) 支持使用 `gen:*` 命令創建文件時,自動吊起對應的 `IDE`,並打開當前文件。
## 優化
- [#4350](https://github.com/hyperf/hyperf/pull/4350) 優化了未開啟 `swoole.use_shortname` 時的錯誤信息。
- [#4360](https://github.com/hyperf/hyperf/pull/4360) 將 `Hyperf\Amqp\IO\SwooleIO` 進行重構,使用更加穩定和高效的 `Swoole\Coroutine\Socket` 而非 `Swoole\Coroutine\Client`
# v2.2.20 - 2021-12-13
## 修復

View File

@ -169,3 +169,15 @@ http2 => enabled
如果沒有,需要重新編譯 Swoole 並增加 `--enable-http2` 參數。
2. 檢查 [server.php](/zh-hk/config?id=serverphp-配置説明) 文件中 `open_http2_protocol` 選項是否為 `true`
## Command 無法正常關閉
在 Command 中使用 AMQP 等多路複用技術後,會導致無法正常關閉,碰到這種情況只需要在執行邏輯最後增加以下代碼即可。
```php
<?php
use Hyperf\Utils\Coordinator\CoordinatorManager;
use Hyperf\Utils\Coordinator\Constants;
CoordinatorManager::until(Constants::WORKER_EXIT)->resume();
```

View File

@ -1,5 +1,22 @@
# 版本更新記錄
# v2.2.21 - 2021-12-20
## 修復
- [#4347](https://github.com/hyperf/hyperf/pull/4347) 修復使用 `AMQP` 元件時,如果連線緩衝區溢位,會導致連線被繫結到多個協程從而報錯的問題。
- [#4373](https://github.com/hyperf/hyperf/pull/4373) 修復使用 `Snowflake` 元件時,由於 `getWorkerId()` 中存在 `IO` 操作進而導致協程切換,最終導致元資料生成重複的問題。
## 新增
- [#4344](https://github.com/hyperf/hyperf/pull/4344) 新增事件 `Hyperf\Crontab\Event\FailToExecute`,此事件會在 `Crontab` 任務執行失敗時觸發。
- [#4348](https://github.com/hyperf/hyperf/pull/4348) 支援使用 `gen:*` 命令建立檔案時,自動吊起對應的 `IDE`,並開啟當前檔案。
## 優化
- [#4350](https://github.com/hyperf/hyperf/pull/4350) 優化了未開啟 `swoole.use_shortname` 時的錯誤資訊。
- [#4360](https://github.com/hyperf/hyperf/pull/4360) 將 `Hyperf\Amqp\IO\SwooleIO` 進行重構,使用更加穩定和高效的 `Swoole\Coroutine\Socket` 而非 `Swoole\Coroutine\Client`
# v2.2.20 - 2021-12-13
## 修復

View File

@ -169,3 +169,15 @@ http2 => enabled
如果沒有,需要重新編譯 Swoole 並增加 `--enable-http2` 引數。
2. 檢查 [server.php](/zh-tw/config?id=serverphp-配置說明) 檔案中 `open_http2_protocol` 選項是否為 `true`
## Command 無法正常關閉
在 Command 中使用 AMQP 等多路複用技術後,會導致無法正常關閉,碰到這種情況只需要在執行邏輯最後增加以下程式碼即可。
```php
<?php
use Hyperf\Utils\Coordinator\CoordinatorManager;
use Hyperf\Utils\Coordinator\Constants;
CoordinatorManager::until(Constants::WORKER_EXIT)->resume();
```

View File

@ -27,7 +27,8 @@ class IOFactory implements IOFactoryInterface
'Swoole' => new SwooleIO(
$host,
$port,
$params->getConnectionTimeout()
$params->getConnectionTimeout(),
$params->getReadWriteTimeout()
),
default => throw new NotSupportedException()
};

View File

@ -15,8 +15,7 @@ use PhpAmqpLib\Exception\AMQPConnectionClosedException;
use PhpAmqpLib\Exception\AMQPRuntimeException;
use PhpAmqpLib\Wire\AMQPWriter;
use PhpAmqpLib\Wire\IO\AbstractIO;
use Swoole\Coroutine\Client;
use const SWOOLE_SOCK_TCP;
use Swoole\Coroutine\Socket;
class SwooleIO extends AbstractIO
{
@ -32,37 +31,27 @@ class SwooleIO extends AbstractIO
*/
protected $port;
/**
* @var int
*/
protected $connectionTimeout;
/**
* @var int
*/
protected $heartbeat;
/**
* @var null|Client
* @var null|Socket
*/
private $sock;
/**
* @var string
*/
private $buffer = '';
/**
* @throws \InvalidArgumentException when readWriteTimeout argument does not 2x the heartbeat
*/
public function __construct(
string $host,
int $port,
int $connectionTimeout
protected int $connectionTimeout,
protected int $readWriteTimeout = 3
) {
$this->host = $host;
$this->port = $port;
$this->connectionTimeout = $connectionTimeout;
}
/**
@ -77,34 +66,21 @@ class SwooleIO extends AbstractIO
public function read($len)
{
while (true) {
if ($len <= strlen($this->buffer)) {
$data = substr($this->buffer, 0, $len);
$this->buffer = substr($this->buffer, $len);
return $data;
}
if (! $this->sock->isConnected()) {
throw new AMQPConnectionClosedException('Broken pipe or closed connection. ' . $this->sock->errMsg);
}
$buffer = $this->sock->recv(-1);
if ($buffer === '') {
throw new AMQPConnectionClosedException('Connection is closed. The reason is ' . $this->sock->errMsg);
}
$this->buffer .= $buffer;
$data = $this->sock->recvAll($len, $this->readWriteTimeout);
if ($data === false || strlen($data) !== $len) {
throw new AMQPConnectionClosedException('Read data failed, The reason is ' . $this->sock->errMsg);
}
return $data;
}
public function write($data)
{
$buffer = $this->sock->send($data);
$len = $this->sock->sendAll($data, $this->readWriteTimeout);
if ($buffer === false) {
throw new AMQPConnectionClosedException('Error sending data');
/* @phpstan-ignore-next-line */
if ($data === false || strlen($data) !== $len) {
throw new AMQPConnectionClosedException('Send data failed, The reason is ' . $this->sock->errMsg);
}
}
@ -134,7 +110,7 @@ class SwooleIO extends AbstractIO
protected function makeClient()
{
$sock = new Client(SWOOLE_SOCK_TCP);
$sock = new Socket(AF_INET, SOCK_STREAM, 0);
if (! $sock->connect($this->host, $this->port, $this->connectionTimeout)) {
throw new AMQPRuntimeException(
sprintf('Error Connecting to server: %s ', $sock->errMsg),

View File

@ -55,8 +55,9 @@ abstract class MetaGenerator implements MetaGeneratorInterface
}
$this->lastTimestamp = $timestamp;
$sequence = $this->sequence;
return new Meta($this->getDataCenterId(), $this->getWorkerId(), $this->sequence, $timestamp, $this->beginTimestamp);
return new Meta($this->getDataCenterId(), $this->getWorkerId(), $sequence, $timestamp, $this->beginTimestamp);
}
public function getBeginTimestamp(): int

View File

@ -0,0 +1,60 @@
<?php
declare(strict_types=1);
/**
* This file is part of Hyperf.
*
* @link https://www.hyperf.io
* @document https://hyperf.wiki
* @contact group@hyperf.io
* @license https://github.com/hyperf/hyperf/blob/master/LICENSE
*/
namespace HyperfTest\Snowflake;
use Hyperf\Snowflake\Configuration;
use Hyperf\Snowflake\MetaGenerator;
use PHPUnit\Framework\TestCase;
/**
* @internal
* @coversNothing
*/
class MetaGeneratorTest extends TestCase
{
public function testGenerate()
{
$class = new class(new Configuration(), 0) extends MetaGenerator {
public function getDataCenterId(): int
{
return 1;
}
public function getWorkerId(): int
{
usleep(1000);
return 1;
}
public function getTimestamp(): int
{
return 0;
}
public function getNextTimestamp(): int
{
return 1;
}
};
$callbacks = [];
for ($i = 0; $i < 10; ++$i) {
$callbacks[] = static function () use ($class) {
return $class->generate()->getSequence();
};
}
$res = parallel($callbacks);
ksort($res);
$this->assertSame([1, 2, 3, 4, 5, 6, 7, 8, 9, 10], $res);
}
}