Skip to content

Commit f8e7adc

Browse files
committed
Reproduce requests leaks in the tests
1 parent e62ec64 commit f8e7adc

File tree

2 files changed

+77
-0
lines changed

2 files changed

+77
-0
lines changed
Lines changed: 32 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,32 @@
1+
<?php
2+
3+
/**
4+
* This file is part of Temporal package.
5+
*
6+
* For the full copyright and license information, please view the LICENSE
7+
* file that was distributed with this source code.
8+
*/
9+
10+
declare(strict_types=1);
11+
12+
namespace Temporal\Tests\Workflow;
13+
14+
use Temporal\Workflow;
15+
use Temporal\Workflow\WorkflowMethod;
16+
17+
#[Workflow\WorkflowInterface]
18+
class DetachedScopeWorkflow
19+
{
20+
#[WorkflowMethod]
21+
public function handler()
22+
{
23+
yield Workflow::asyncDetached(
24+
static function (): void {
25+
// Don't add `yield` here. It's important for the tests.
26+
Workflow::await(Workflow::timer(5000));
27+
},
28+
);
29+
30+
return 'ok';
31+
}
32+
}

tests/Functional/WorkflowTestCase.php

Lines changed: 45 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -363,6 +363,41 @@ public function testAwaitWithOneTimer_Leaks(): void
363363
$this->assertSame(0, $after - $before);
364364
}
365365

366+
public function testDetachedScope_Leaks(): void
367+
{
368+
$worker = WorkerMock::createMock();
369+
370+
// Run the workflow $i times
371+
for ($id = 9000, $i = 0; $i < 100; ++$i) {
372+
$uuid1 = Uuid::v4();
373+
$uuid2 = Uuid::v4();
374+
$id1 = ++$id;
375+
$id2 = ++$id;
376+
$log = <<<LOG
377+
[0m [{"command":"StartWorkflow","options":{"info":{"WorkflowExecution":{"ID":"$uuid1","RunID":"$uuid2"},"WorkflowType":{"Name":"DetachedScopeWorkflow"},"TaskQueueName":"default","WorkflowExecutionTimeout":315360000000000000,"WorkflowRunTimeout":315360000000000000,"WorkflowTaskTimeout":0,"Namespace":"default","Attempt":1,"CronSchedule":"","ContinuedExecutionRunID":"","ParentWorkflowNamespace":"","ParentWorkflowExecution":null,"Memo":null,"SearchAttributes":null,"BinaryChecksum":"4301710877bf4b107429ee12de0922be"}},"payloads":"CicKFgoIZW5jb2RpbmcSCmpzb24vcGxhaW4SDSJIZWxsbyBXb3JsZCI="}] {"taskQueue":"default","tickTime":"2021-01-12T15:21:52.2672785Z"}
378+
# Run a timer
379+
[0m [{"id":$id1,"command":"NewTimer","options":{"ms":5000000},"payloads":"","header":""},{"payloads":"ChkKFwoIZW5jb2RpbmcSC2JpbmFyeS9udWxs"},{"id":$id2,"command":"CompleteWorkflow","options":{},"payloads":"Ch4KFgoIZW5jb2RpbmcSCmpzb24vcGxhaW4SBCJvayI=","header":""}] {"receive": true}
380+
# Destroy workflow
381+
[0m [{"command":"DestroyWorkflow","options":{"runId":"$uuid2"}}] {"taskQueue":"default","tickTime":"2021-01-12T15:21:53.3838443Z","replay":true}
382+
[0m [{"payloads":"ChkKFwoIZW5jb2RpbmcSC2JpbmFyeS9udWxs"}] {"receive": true}
383+
LOG;
384+
385+
$worker->run($this, Splitter::createFromString($log)->getQueue());
386+
if ($i === 3) {
387+
\gc_collect_cycles();
388+
$before = \memory_get_usage();
389+
}
390+
}
391+
$after = \memory_get_usage();
392+
393+
$factory = self::getPrivate($worker, 'factory');
394+
$client = self::getPrivate($factory, 'client');
395+
$requests = self::getPrivate($client, 'requests');
396+
self::assertCount(0, $requests);
397+
398+
$this->assertSame(0, $after - $before);
399+
}
400+
366401
/**
367402
* Test case when an external Temporal SDK returns empty payload that doesn't contain even NULL value.
368403
*
@@ -399,4 +434,14 @@ public function setUp(): void
399434
// emulate connection to parent server
400435
$_SERVER['RR_RPC'] = 'tcp://127.0.0.1:6001';
401436
}
437+
438+
/**
439+
* Fetch a private property from an object.
440+
*
441+
* @param non-empty-string $key Property name
442+
*/
443+
private static function getPrivate(object $object, string $key): mixed
444+
{
445+
return (fn (object $value) => $value->{$key} ?? null)->call($object, $object);
446+
}
402447
}

0 commit comments

Comments
 (0)