Skip to content
This repository was archived by the owner on Mar 24, 2025. It is now read-only.

Commit e96b46f

Browse files
authored
Merge pull request #488 from memfork/ref-same-coroutine-id-in-same-request
Fix: ref different coroutine id on same request
2 parents ebc5859 + d089754 commit e96b46f

File tree

2 files changed

+68
-10
lines changed

2 files changed

+68
-10
lines changed

src/Coroutine/Context.php

Lines changed: 27 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,8 @@
77

88
class Context
99
{
10+
protected const MAX_RECURSE_COROUTINE_ID = 50;
11+
1012
/**
1113
* The app containers in different coroutine environment.
1214
*
@@ -26,7 +28,7 @@ class Context
2628
*/
2729
public static function getApp()
2830
{
29-
return static::$apps[static::getCoroutineId()] ?? null;
31+
return static::$apps[static::getRequestedCoroutineId()] ?? null;
3032
}
3133

3234
/**
@@ -36,7 +38,7 @@ public static function getApp()
3638
*/
3739
public static function setApp(Container $app)
3840
{
39-
static::$apps[static::getCoroutineId()] = $app;
41+
static::$apps[static::getRequestedCoroutineId()] = $app;
4042
}
4143

4244
/**
@@ -48,7 +50,7 @@ public static function setApp(Container $app)
4850
*/
4951
public static function getData(string $key)
5052
{
51-
return static::$data[static::getCoroutineId()][$key] ?? null;
53+
return static::$data[static::getRequestedCoroutineId()][$key] ?? null;
5254
}
5355

5456
/**
@@ -59,7 +61,7 @@ public static function getData(string $key)
5961
*/
6062
public static function setData(string $key, $value)
6163
{
62-
static::$data[static::getCoroutineId()][$key] = $value;
64+
static::$data[static::getRequestedCoroutineId()][$key] = $value;
6365
}
6466

6567
/**
@@ -69,31 +71,46 @@ public static function setData(string $key, $value)
6971
*/
7072
public static function removeData(string $key)
7173
{
72-
unset(static::$data[static::getCoroutineId()][$key]);
74+
unset(static::$data[static::getRequestedCoroutineId()][$key]);
7375
}
7476

7577
/**
7678
* Get data keys by current coroutine id.
7779
*/
7880
public static function getDataKeys()
7981
{
80-
return array_keys(static::$data[static::getCoroutineId()] ?? []);
82+
return array_keys(static::$data[static::getRequestedCoroutineId()] ?? []);
8183
}
8284

8385
/**
8486
* Clear data by current coroutine id.
8587
*/
8688
public static function clear()
8789
{
88-
unset(static::$apps[static::getCoroutineId()]);
89-
unset(static::$data[static::getCoroutineId()]);
90+
unset(static::$apps[static::getRequestedCoroutineId()]);
91+
unset(static::$data[static::getRequestedCoroutineId()]);
92+
}
93+
94+
public static function getCoroutineId(): int
95+
{
96+
return Coroutine::getuid();
9097
}
9198

9299
/**
93100
* Get current coroutine id.
94101
*/
95-
public static function getCoroutineId()
102+
public static function getRequestedCoroutineId(): int
96103
{
97-
return Coroutine::getuid();
104+
$currentId = static::getCoroutineId();
105+
if ($currentId === -1) {
106+
return -1;
107+
}
108+
109+
$counter = 0;
110+
while (($topCoroutineId = Coroutine::getPcid($currentId)) !== -1 && $counter <= static::MAX_RECURSE_COROUTINE_ID) {
111+
$currentId = $topCoroutineId;
112+
$counter++;
113+
}
114+
return $currentId;
98115
}
99116
}

tests/Coroutine/ContextTest.php

Lines changed: 41 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -52,6 +52,47 @@ public function testGetDataKeys()
5252
$this->assertSame(['foo', 'sea'], Context::getDataKeys());
5353
}
5454

55+
public function testGetDataKeyInCoroutine()
56+
{
57+
$data1 = null;
58+
$data2 = null;
59+
$data3 = null;
60+
61+
$coroutineId1 = null;
62+
$coroutineId2 = null;
63+
$coroutineId3 = null;
64+
65+
\Swoole\Coroutine\run(function () use (&$data1, &$data2, &$data3, &$coroutineId1, &$coroutineId2, &$coroutineId3) {
66+
Context::setData('foo', 'bar');
67+
68+
$data1 = Context::getData('foo');
69+
$data2 = 'baz';
70+
$data2 = 'swoole';
71+
72+
$coroutineId1 = Context::getRequestedCoroutineId();
73+
$coroutineId2 = -1;
74+
$coroutineId3 = -1;
75+
76+
go(function () use (&$data2, &$data3, &$coroutineId2, &$coroutineId3) {
77+
$data2 = Context::getData('foo');
78+
$coroutineId2 = Context::getRequestedCoroutineId();
79+
80+
// test nested coroutine
81+
go(function () use (&$data3, &$coroutineId3) {
82+
$data3 = Context::getData('foo');
83+
$coroutineId3 = Context::getRequestedCoroutineId();
84+
});
85+
});
86+
});
87+
88+
$this->assertSame('bar', $data1);
89+
$this->assertSame($data1, $data2);
90+
$this->assertSame($data2, $data3);
91+
$this->assertSame($coroutineId1, $coroutineId2);
92+
$this->assertSame($coroutineId2, $coroutineId3);
93+
94+
}
95+
5596
public function testClear()
5697
{
5798
Context::setApp(m::mock(Container::class));

0 commit comments

Comments
 (0)