Skip to content

Commit

Permalink
新增支持 Async 异步执行注解 (#174)
Browse files Browse the repository at this point in the history
  • Loading branch information
Yurunsoft authored Oct 9, 2021
1 parent 0f113ba commit 90da4c7
Show file tree
Hide file tree
Showing 6 changed files with 187 additions and 0 deletions.
39 changes: 39 additions & 0 deletions src/Async/SwooleHandler.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,39 @@
<?php

declare(strict_types=1);

namespace Imi\Swoole\Async;

use Imi\Async\Contract\IAsyncHandler;
use Imi\Async\Contract\IAsyncResult;
use Swoole\Coroutine\Channel;

class SwooleHandler implements IAsyncHandler
{
/**
* 执行.
*/
public function exec(callable $callable): IAsyncResult
{
$channel = new Channel();
$result = new SwooleResult($channel);
imigo(function () use ($callable, $channel) {
try
{
$channel->push([
'result' => $callable(),
'exception' => false,
]);
}
catch (\Throwable $th)
{
$channel->push([
'result' => $th,
'exception' => true,
]);
}
});

return $result;
}
}
42 changes: 42 additions & 0 deletions src/Async/SwooleResult.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,42 @@
<?php

declare(strict_types=1);

namespace Imi\Swoole\Async;

use Imi\Async\Contract\IAsyncResult;
use Imi\Async\Exception\AsyncTimeoutException;
use Swoole\Coroutine\Channel;

class SwooleResult implements IAsyncResult
{
private Channel $channel;

public function __construct(Channel $channel)
{
$this->channel = $channel;
}

/**
* 获取异步返回结果.
*
* 默认不超时无限等待,超时则会抛出异常
*
* @return mixed
*/
public function get(?float $timeout = null)
{
$channel = $this->channel;
$result = $channel->pop($timeout ?? -1);
if (false === $result && \SWOOLE_CHANNEL_TIMEOUT === $channel->errCode)
{
throw new AsyncTimeoutException();
}
if ($result['exception'])
{
throw $result['result'];
}

return $result['result'];
}
}
1 change: 1 addition & 0 deletions src/SwooleApp.php
Original file line number Diff line number Diff line change
Expand Up @@ -36,6 +36,7 @@ class SwooleApp extends CliApp
protected array $appConfig = [
'RequestContext' => CoroutineContextManager::class,
'Timer' => SwooleTimer::class,
'Async' => \Imi\Swoole\Async\SwooleHandler::class,
'beans' => [
'ServerUtil' => \Imi\Swoole\Server\Util\LocalServerUtil::class,
],
Expand Down
60 changes: 60 additions & 0 deletions tests/unit/Component/Async/AsyncTester.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,60 @@
<?php

declare(strict_types=1);

namespace Imi\Swoole\Test\Component\Async;

use Imi\Async\Annotation\Async;
use Imi\Async\AsyncResult;
use Imi\Async\Contract\IAsyncResult;
use Imi\Bean\Annotation\Bean;

/**
* @Bean("AsyncTester")
*/
class AsyncTester
{
/**
* @Async
*/
public function test1(): void
{
sleep(1);
}

/**
* @Async
*/
public function test2(float $a, float $b): IAsyncResult
{
return new AsyncResult($a + $b);
}

/**
* @Async
*
* @return float|IAsyncResult
*/
public function test3(float $a, float $b)
{
return $a + $b;
}

/**
* @Async
*/
public function test4(): IAsyncResult
{
sleep(1);

return new AsyncResult(true);
}

/**
* @Async
*/
public function testException(): IAsyncResult
{
throw new \RuntimeException('gg');
}
}
44 changes: 44 additions & 0 deletions tests/unit/Component/Tests/AsyncTest.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,44 @@
<?php

declare(strict_types=1);

namespace Imi\Swoole\Test\Component\Tests;

use Imi\App;
use Imi\Async\Exception\AsyncTimeoutException;
use Imi\Swoole\Test\BaseTest;
use Imi\Swoole\Test\Component\Async\AsyncTester;

class AsyncTest extends BaseTest
{
public function test(): void
{
/** @var AsyncTester $asyncTester */
$asyncTester = App::getBean('AsyncTester');

$time = microtime(true);
$asyncTester->test1();
$this->assertLessThanOrEqual(1, microtime(true) - $time);

$this->assertEquals(3, $asyncTester->test2(1, 2)->get());
$this->assertEquals(3, $asyncTester->test3(1, 2)->get());
}

public function testTimeout(): void
{
/** @var AsyncTester $asyncTester */
$asyncTester = App::getBean('AsyncTester');

$this->expectException(AsyncTimeoutException::class);
$asyncTester->test4()->get(0.001);
}

public function testException(): void
{
/** @var AsyncTester $asyncTester */
$asyncTester = App::getBean('AsyncTester');

$this->expectException(\RuntimeException::class);
$asyncTester->testException()->get();
}
}
1 change: 1 addition & 0 deletions tests/unit/Component/config/config.php
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@
'Imi\Swoole\Test\Component\Db',
'Imi\Swoole\Test\Component\Lock',
'Imi\Swoole\Test\Component\Tests',
'Imi\Swoole\Test\Component\Async',
],
'ignoreNamespace' => [
],
Expand Down

0 comments on commit 90da4c7

Please sign in to comment.