mirror of
https://gitee.com/hyperf/hyperf.git
synced 2024-12-05 21:28:15 +08:00
Add setTimeout & Cancel API
This commit is contained in:
parent
f03e236d96
commit
27b20e2a5b
@ -12,10 +12,13 @@ declare(strict_types=1);
|
|||||||
|
|
||||||
namespace Hyperf\Utils;
|
namespace Hyperf\Utils;
|
||||||
|
|
||||||
|
use Carbon\Carbon;
|
||||||
use Swoole\Coroutine as SwCoroutine;
|
use Swoole\Coroutine as SwCoroutine;
|
||||||
|
|
||||||
class Context
|
class Context
|
||||||
{
|
{
|
||||||
|
public const DONE = 'hyperf.context.done';
|
||||||
|
|
||||||
protected static $nonCoContext = [];
|
protected static $nonCoContext = [];
|
||||||
|
|
||||||
public static function set(string $id, $value)
|
public static function set(string $id, $value)
|
||||||
@ -108,4 +111,50 @@ class Context
|
|||||||
|
|
||||||
return static::$nonCoContext;
|
return static::$nonCoContext;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public static function done(): bool
|
||||||
|
{
|
||||||
|
$holder = self::getOrSet(static::DONE, new \stdClass());
|
||||||
|
return $holder->done ?? false;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param float|int $millisecond
|
||||||
|
*/
|
||||||
|
public static function setTimeout($millisecond)
|
||||||
|
{
|
||||||
|
$holder = self::getOrSet(static::DONE, new \stdClass());
|
||||||
|
Coroutine::create(function () use ($holder, $millisecond) {
|
||||||
|
usleep((int) $millisecond * 1000);
|
||||||
|
$holder->done = true;
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
public static function setDeadline(\DateTime $deadline)
|
||||||
|
{
|
||||||
|
if (! ($deadline instanceof Carbon)) {
|
||||||
|
$deadline = Carbon::instance($deadline);
|
||||||
|
}
|
||||||
|
|
||||||
|
$timeout = $deadline->getPreciseTimestamp(3) - microtime(true) * 1000;
|
||||||
|
$timeout = $timeout > 0 ? $timeout : 0;
|
||||||
|
static::setTimeout($timeout);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static function cancel(): void
|
||||||
|
{
|
||||||
|
$holder = self::getOrSet(static::DONE, new \stdClass());
|
||||||
|
$holder->done = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static function go(callable $callable): int
|
||||||
|
{
|
||||||
|
if (! self::has(static::DONE)) {
|
||||||
|
self::set(static::DONE, new \stdClass());
|
||||||
|
}
|
||||||
|
return Coroutine::create(function () use ($callable) {
|
||||||
|
static::copy(coroutine::parentId());
|
||||||
|
$callable();
|
||||||
|
});
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
@ -12,8 +12,12 @@ declare(strict_types=1);
|
|||||||
|
|
||||||
namespace HyperfTest\Utils;
|
namespace HyperfTest\Utils;
|
||||||
|
|
||||||
|
use Carbon\Carbon;
|
||||||
use Hyperf\Utils\Context;
|
use Hyperf\Utils\Context;
|
||||||
use PHPUnit\Framework\TestCase;
|
use PHPUnit\Framework\TestCase;
|
||||||
|
use Swoole\Coroutine\Channel;
|
||||||
|
use Swoole\Coroutine\System;
|
||||||
|
use Swoole\Runtime;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @internal
|
* @internal
|
||||||
@ -45,4 +49,101 @@ class ContextTest extends TestCase
|
|||||||
Context::set('test.store.id', null);
|
Context::set('test.store.id', null);
|
||||||
$this->assertSame(1, Context::getOrSet('test.store.id', 1));
|
$this->assertSame(1, Context::getOrSet('test.store.id', 1));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public function testCancel()
|
||||||
|
{
|
||||||
|
Context::set(Context::DONE, null);
|
||||||
|
$chan = new Channel(1);
|
||||||
|
Context::go(function () use ($chan) {
|
||||||
|
if (Context::done()) {
|
||||||
|
$chan->push(1);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
$chan->push(2);
|
||||||
|
});
|
||||||
|
$this->assertEquals(2, $chan->pop());
|
||||||
|
Context::cancel();
|
||||||
|
Context::go(function () use ($chan) {
|
||||||
|
if (Context::done()) {
|
||||||
|
$chan->push(1);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
$chan->push(2);
|
||||||
|
});
|
||||||
|
$this->assertEquals(1, $chan->pop());
|
||||||
|
}
|
||||||
|
|
||||||
|
public function testNestedCancel()
|
||||||
|
{
|
||||||
|
Context::set(Context::DONE, null);
|
||||||
|
$chan = new Channel(1);
|
||||||
|
Context::go(function () use ($chan) {
|
||||||
|
if (Context::done()) {
|
||||||
|
$chan->push(1);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
usleep(20000);
|
||||||
|
System::sleep(1);
|
||||||
|
Context::go(function () use ($chan) {
|
||||||
|
if (Context::done()) {
|
||||||
|
$chan->push(2);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
$chan->push(3);
|
||||||
|
});
|
||||||
|
});
|
||||||
|
usleep(10000);
|
||||||
|
Context::cancel();
|
||||||
|
$this->assertEquals(2, $chan->pop());
|
||||||
|
}
|
||||||
|
|
||||||
|
public function testTimeout()
|
||||||
|
{
|
||||||
|
Context::set(Context::DONE, null);
|
||||||
|
Runtime::enableCoroutine();
|
||||||
|
Context::setTimeout(5);
|
||||||
|
$chan = new Channel(1);
|
||||||
|
Context::go(function () use ($chan) {
|
||||||
|
if (Context::done()) {
|
||||||
|
$chan->push(1);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
$chan->push(2);
|
||||||
|
});
|
||||||
|
$this->assertEquals(2, $chan->pop());
|
||||||
|
Context::go(function () use ($chan) {
|
||||||
|
usleep(10000);
|
||||||
|
if (Context::done()) {
|
||||||
|
$chan->push(1);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
$chan->push(2);
|
||||||
|
});
|
||||||
|
$this->assertEquals(1, $chan->pop());
|
||||||
|
}
|
||||||
|
|
||||||
|
public function testDeadline()
|
||||||
|
{
|
||||||
|
Context::set(Context::DONE, null);
|
||||||
|
$deadline = Carbon::now()->addMillisecond(5);
|
||||||
|
Context::setDeadline($deadline);
|
||||||
|
$chan = new Channel(1);
|
||||||
|
Context::go(function () use ($chan) {
|
||||||
|
if (Context::done()) {
|
||||||
|
$chan->push(1);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
$chan->push(2);
|
||||||
|
});
|
||||||
|
$this->assertEquals(2, $chan->pop());
|
||||||
|
usleep(10000);
|
||||||
|
Context::go(function () use ($chan) {
|
||||||
|
if (Context::done()) {
|
||||||
|
$chan->push(1);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
$chan->push(2);
|
||||||
|
});
|
||||||
|
$this->assertEquals(1, $chan->pop());
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
Loading…
Reference in New Issue
Block a user