Skip to content

Commit

Permalink
close #27
Browse files Browse the repository at this point in the history
  • Loading branch information
chaz6chez committed Nov 9, 2024
1 parent 314b094 commit dab0ff1
Show file tree
Hide file tree
Showing 5 changed files with 97 additions and 14 deletions.
21 changes: 11 additions & 10 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -82,16 +82,17 @@ composer require workbunny/webman-coroutine

## 文档

| 目录 | 地址 |
|:---:|:----------------------------------------------------------------------------------------------:|
| API | [Fucntion-APIs](https://workbunny.github.io/webman-coroutine/) |
| 教程 | [PHP 协程入门](https://github.com/workbunny/webman-coroutine/tree/main/docs/doc/coroutine.md) |
| - | [安装及配置](https://github.com/workbunny/webman-coroutine/tree/main/docs/doc/install.md) |
| - | [助手函数](https://github.com/workbunny/webman-coroutine/tree/main/docs/doc/helpers.md) |
| - | [`workerman`环境](https://github.com/workbunny/webman-coroutine/tree/main/docs/doc/workerman.md) |
| - | [`webman`框架](https://github.com/workbunny/webman-coroutine/tree/main/docs/doc/webman.md) |
| - | [`Utils`说明](https://github.com/workbunny/webman-coroutine/tree/main/docs/doc/utils.md) |
| - | [自定义拓展](https://github.com/workbunny/webman-coroutine/tree/main/docs/doc/custom.md) |
| 目录 | 地址 |
|:---:|:------------------------------------------------------------------------------------------------------:|
| API | [Fucntion-APIs](https://workbunny.github.io/webman-coroutine/) |
| 教程 | [PHP 协程入门](https://github.com/workbunny/webman-coroutine/tree/main/docs/doc/coroutine.md) |
| - | [安装及配置](https://github.com/workbunny/webman-coroutine/tree/main/docs/doc/install.md) |
| - | [助手函数](https://github.com/workbunny/webman-coroutine/tree/main/docs/doc/helpers.md) |
| - | [`workerman`环境](https://github.com/workbunny/webman-coroutine/tree/main/docs/doc/workerman.md) |
| - | [`webman`框架](https://github.com/workbunny/webman-coroutine/tree/main/docs/doc/webman.md) |
| - | [`Utils`说明](https://github.com/workbunny/webman-coroutine/tree/main/docs/doc/utils.md) |
| - | [自定义拓展](https://github.com/workbunny/webman-coroutine/tree/main/docs/doc/custom.md) |
| - | [协程的观测和管理](https://github.com/workbunny/webman-coroutine/tree/main/docs/doc/suspension-manage.md) |

## 参与开发

Expand Down
80 changes: 80 additions & 0 deletions docs/doc/suspension-manage.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,80 @@
# 协程的观测和管理

`webman-coroutine`中提供的关于协程的部分来自`Utils/Coroutine``Factory::sleep()`

## `Utils/Coroutine` 协程工具

> `Utils/Coroutine`会在每次构造的时候将注入一个WeakMap,并储存`id``startTime`
- 获取当前进程所有协程

```php
$weakMap = \Workbunny\WebmanCoroutine\Utils\Coroutine\Coroutine::getCoroutinesWeakMap();
```
> Tips: 方法返回一个储存所有通过`Utils/Coroutine`创建的协程的`WeakMap`
- 退出当前进程所有协程

```php
$weakMap = \Workbunny\WebmanCoroutine\Utils\Coroutine\Coroutine::getCoroutinesWeakMap();
/**
* @var \Workbunny\WebmanCoroutine\Utils\Coroutine\Handlers\CoroutineInterface $coroutine
* @var array<string, mixed> $info ['id' => 协程id, 'startTime' => 开始时间]
*/
foreach ($weakMap as $coroutine => $info) {
$coroutine->kill(new \Workbunny\WebmanCoroutine\Exceptions\KilledException());
}
```
> Tips:
> - `kill`方法并不会立即退出协程,而是在该协程下一次唤起的时候触发,抛出一个异常
> - 各协程驱动各略有不同,如:swoole驱动在协程遇到文件IO事件时并不会立即退出,也不会在下次唤起时抛出异常
## `Handler::$suspension`挂起事件

> 所有基于`Factory::sleep()`创建的挂起事件既是`Handler::$suspension`,包括`sleep()``wait_for()``Factory::waitFor()`
- 获取当前进程所有挂起事件

```php
$weakMap = \Workbunny\WebmanCoroutine\Factory::getSuspensionsWeakMap();
```
> Tips: 方法返回一个储存所有通过`Factory`创建的协程的`WeakMap`
- 添加/设置一个挂起事件至`WeakMap`
```php
$weakMap = \Workbunny\WebmanCoroutine\Factory::setSuspensionsWeakMap();
```

- 退出当前进程所有挂起事件

```php
$weakMap = \Workbunny\WebmanCoroutine\Factory::getSuspensionsWeakMap();
/**
* @var mixed $suspension
* @var array<string, mixed> $info ['id' => 协程id, 'startTime' => 开始时间, 'event' => 挂起事件|NULL]
*/
foreach ($weakMap as $suspension => $info) {
\Workbunny\WebmanCoroutine\Factory::kill($suspension);
}
```

> Tips:
> - `kill`方法并不会立即退出协程,而是在该挂起下一次被唤起的时候触发,抛出一个`KilledException`
> - 各协程驱动各略有不同,如:`swoole`驱动在协程遇到文件IO事件时并不会立即退出,挂起事件会抛出`KilledException`
## 观测/管理实践

### 采样监听方案

1. 在服务进程启动时创建定时器
2. 定时器实现`Coroutine::getCoroutinesWeakMap()``Factory::getSuspensionsWeakMap()`的采样,并以进程pid为区分输出至日志

> Tips: 可以自定义实现对协程或挂起事件的startTime比对,合理杀死过长挂起的协程/事件
### 遥控管理方案

1. 在进程中实现命令对应的控制逻辑,例如:`kill``dump``check`
2. 在服务进程启动时通过`redis`/`apcu`对通道进行监听,注册命令对应的控制监听
3. 遥控cli程序通过对通道的`pub`发送指定命令进行控制

> Tips: `webman`/`workerman` 环境基于`apcu`的共享缓存插件推荐:https://www.workerman.net/plugin/133
3 changes: 2 additions & 1 deletion src/Factory.php
Original file line number Diff line number Diff line change
Expand Up @@ -28,7 +28,8 @@
* @method static void wakeup(string $event)
* @method static void sleep(int|float $timeout = 0, ?string $event = null)
* @method static void kill(object|int|string $suspensionOrSuspensionId, string $message = 'kill', int $exitCode = 0)
* @method static null|WeakMap listSuspensionsWeakMap()
* @method static null|WeakMap getSuspensionsWeakMap()
* @method static void setSuspensionsWeakMap(object $object, string|int $id, ?string $event, float|int $startTime)
*/
class Factory
{
Expand Down
4 changes: 4 additions & 0 deletions src/Handlers/SwooleHandler.php
Original file line number Diff line number Diff line change
Expand Up @@ -89,7 +89,9 @@ public static function sleep(float|int $timeout = 0, ?string $event = null): voi
if ($timeout < 0) {
Coroutine::suspend();
if ($object->throw instanceof Throwable) {
// @codeCoverageIgnoreStart
throw $object->throw;
// @codeCoverageIgnoreEnd
}

return;
Expand Down Expand Up @@ -119,7 +121,9 @@ public static function sleep(float|int $timeout = 0, ?string $event = null): voi
}
Coroutine::suspend();
if ($object->throw instanceof Throwable) {
// @codeCoverageIgnoreStart
throw $object->throw;
// @codeCoverageIgnoreEnd
}
} finally {
if ($event) {
Expand Down
3 changes: 0 additions & 3 deletions tests/HandlersCase/SwooleHandlerTest.php
Original file line number Diff line number Diff line change
Expand Up @@ -91,9 +91,6 @@ public function testWaitFor()
}, 0.1);
}

/**
* @return void
*/
public function testSleep()
{
$timerMock = Mockery::mock('alias:Swoole\Timer');
Expand Down

0 comments on commit dab0ff1

Please sign in to comment.