From bf045c3ed7d5bf668930a809ae749cf265e4a481 Mon Sep 17 00:00:00 2001 From: Deeka Wong <8337659+huangdijia@users.noreply.github.com> Date: Fri, 14 Nov 2025 21:14:55 +0800 Subject: [PATCH 01/11] refactor: remove unused PendingClosureDispatch class - Remove `PendingClosureDispatch` class in favor of `PendingAsyncQueueDispatch` - Add `onConnection()` alias method to `PendingAsyncQueueDispatch` for backward compatibility - Update all documentation to reference `PendingAsyncQueueDispatch` - Update test files to use `PendingAsyncQueueDispatch` and correct property references - Remove dedicated `PendingClosureDispatch` test files This change simplifies the codebase by using the shared `PendingAsyncQueueDispatch` class from the Support package, eliminating code duplication while maintaining the same functionality and API compatibility. --- docs/en/components/async-queue-closure-job.md | 6 +- .../components/async-queue-closure-job.md | 6 +- .../components/async-queue-closure-job.md | 6 +- .../components/async-queue-closure-job.md | 6 +- src/async-queue-closure-job/README.md | 4 +- src/async-queue-closure-job/README.zh-CN.md | 4 +- src/async-queue-closure-job/src/Functions.php | 5 +- .../src/PendingClosureDispatch.php | 66 ------ .../src/Bus/PendingAsyncQueueDispatch.php | 5 + .../BasicFunctionalityTest.php | 2 +- .../CoreFunctionalityTest.php | 22 +- .../DispatchFunctionSimpleTest.php | 18 +- .../DispatchFunctionTest.php | 16 +- .../FluentDispatchIntegrationTest.php | 4 +- .../PendingClosureDispatchSimpleTest.php | 197 ---------------- .../PendingClosureDispatchTest.php | 223 ------------------ 16 files changed, 55 insertions(+), 535 deletions(-) delete mode 100644 src/async-queue-closure-job/src/PendingClosureDispatch.php delete mode 100644 tests/AsyncQueueClosureJob/PendingClosureDispatchSimpleTest.php delete mode 100644 tests/AsyncQueueClosureJob/PendingClosureDispatchTest.php diff --git a/docs/en/components/async-queue-closure-job.md b/docs/en/components/async-queue-closure-job.md index 9fb790f18..66795ff6c 100644 --- a/docs/en/components/async-queue-closure-job.md +++ b/docs/en/components/async-queue-closure-job.md @@ -219,7 +219,7 @@ foreach ($userIds as $userId) { ## API Reference -### `dispatch(Closure $closure): PendingClosureDispatch` +### `dispatch(Closure $closure): PendingAsyncQueueDispatch` The main dispatch function that creates a closure job. @@ -227,9 +227,9 @@ The main dispatch function that creates a closure job. - `$closure` - The closure to execute **Returns:** -- `PendingClosureDispatch` - Pending closure dispatch object +- `PendingAsyncQueueDispatch` - Pending closure dispatch object -### `PendingClosureDispatch` Methods +### `PendingAsyncQueueDispatch` Methods #### `onConnection(string $connection): static` diff --git a/docs/zh-cn/components/async-queue-closure-job.md b/docs/zh-cn/components/async-queue-closure-job.md index d3b192f44..f2c269206 100644 --- a/docs/zh-cn/components/async-queue-closure-job.md +++ b/docs/zh-cn/components/async-queue-closure-job.md @@ -219,7 +219,7 @@ foreach ($userIds as $userId) { ## API 参考 -### `dispatch(Closure $closure): PendingClosureDispatch` +### `dispatch(Closure $closure): PendingAsyncQueueDispatch` 主要的分发函数,用于创建闭包任务。 @@ -227,9 +227,9 @@ foreach ($userIds as $userId) { - `$closure` - 要执行的闭包 **返回:** -- `PendingClosureDispatch` - 待处理的闭包分发对象 +- `PendingAsyncQueueDispatch` - 待处理的闭包分发对象 -### `PendingClosureDispatch` 方法 +### `PendingAsyncQueueDispatch` 方法 #### `onConnection(string $connection): static` diff --git a/docs/zh-hk/components/async-queue-closure-job.md b/docs/zh-hk/components/async-queue-closure-job.md index 5837099f7..1e9a633d7 100644 --- a/docs/zh-hk/components/async-queue-closure-job.md +++ b/docs/zh-hk/components/async-queue-closure-job.md @@ -219,7 +219,7 @@ foreach ($userIds as $userId) { ## API 參考 -### `dispatch(Closure $closure): PendingClosureDispatch` +### `dispatch(Closure $closure): PendingAsyncQueueDispatch` 主要的分發函數,用於建立閉包任務。 @@ -227,9 +227,9 @@ foreach ($userIds as $userId) { - `$closure` - 要執行的閉包 **返回:** -- `PendingClosureDispatch` - 待處理的閉包分發物件 +- `PendingAsyncQueueDispatch` - 待處理的閉包分發物件 -### `PendingClosureDispatch` 方法 +### `PendingAsyncQueueDispatch` 方法 #### `onConnection(string $connection): static` diff --git a/docs/zh-tw/components/async-queue-closure-job.md b/docs/zh-tw/components/async-queue-closure-job.md index 90e73823d..2016e5331 100644 --- a/docs/zh-tw/components/async-queue-closure-job.md +++ b/docs/zh-tw/components/async-queue-closure-job.md @@ -219,7 +219,7 @@ foreach ($userIds as $userId) { ## API 參考 -### `dispatch(Closure $closure): PendingClosureDispatch` +### `dispatch(Closure $closure): PendingAsyncQueueDispatch` 主要的分發函式,用於建立閉包任務。 @@ -227,9 +227,9 @@ foreach ($userIds as $userId) { - `$closure` - 要執行的閉包 **回傳:** -- `PendingClosureDispatch` - 待處理的閉包分發物件 +- `PendingAsyncQueueDispatch` - 待處理的閉包分發物件 -### `PendingClosureDispatch` 方法 +### `PendingAsyncQueueDispatch` 方法 #### `onConnection(string $connection): static` diff --git a/src/async-queue-closure-job/README.md b/src/async-queue-closure-job/README.md index 947950df6..74a06a4fb 100644 --- a/src/async-queue-closure-job/README.md +++ b/src/async-queue-closure-job/README.md @@ -90,11 +90,11 @@ dispatch(function (UserService $userService, int $userId) { ## API Reference -### `dispatch(Closure $closure): PendingClosureDispatch` +### `dispatch(Closure $closure): PendingAsyncQueueDispatch` The main dispatch function that creates a closure job. -### `PendingClosureDispatch` Methods +### `PendingAsyncQueueDispatch` Methods - `onConnection(string $connection): static` - Set the connection name - `delay(int $delay): static` - Set execution delay in seconds diff --git a/src/async-queue-closure-job/README.zh-CN.md b/src/async-queue-closure-job/README.zh-CN.md index ad2b20642..ad7595c17 100644 --- a/src/async-queue-closure-job/README.zh-CN.md +++ b/src/async-queue-closure-job/README.zh-CN.md @@ -90,11 +90,11 @@ dispatch(function (UserService $userService, int $userId) { ## API 参考 -### `dispatch(Closure $closure): PendingClosureDispatch` +### `dispatch(Closure $closure): PendingAsyncQueueDispatch` 主要的分发函数,用于创建闭包任务。 -### `PendingClosureDispatch` 方法 +### `PendingAsyncQueueDispatch` 方法 - `onConnection(string $connection): static` - 设置连接名称 - `delay(int $delay): static` - 设置延迟执行时间(秒) diff --git a/src/async-queue-closure-job/src/Functions.php b/src/async-queue-closure-job/src/Functions.php index 449bf9540..2c8084fc9 100644 --- a/src/async-queue-closure-job/src/Functions.php +++ b/src/async-queue-closure-job/src/Functions.php @@ -12,6 +12,7 @@ namespace FriendsOfHyperf\AsyncQueueClosureJob; use Closure; +use FriendsOfHyperf\Support\Bus\PendingAsyncQueueDispatch; /** * Dispatch a closure as an async queue job. @@ -19,9 +20,9 @@ * @param Closure $closure The closure to execute * @param-closure-this CallQueuedClosure $closure */ -function dispatch(Closure $closure): PendingClosureDispatch +function dispatch(Closure $closure): PendingAsyncQueueDispatch { - return new PendingClosureDispatch( + return new PendingAsyncQueueDispatch( CallQueuedClosure::create($closure) ); } diff --git a/src/async-queue-closure-job/src/PendingClosureDispatch.php b/src/async-queue-closure-job/src/PendingClosureDispatch.php deleted file mode 100644 index 5959b46cc..000000000 --- a/src/async-queue-closure-job/src/PendingClosureDispatch.php +++ /dev/null @@ -1,66 +0,0 @@ -get(DriverFactory::class) - ->get($this->connection) - ->push($this->job, $this->delay); - } - - public function setMaxAttempts(int $maxAttempts): static - { - $this->job->setMaxAttempts($maxAttempts); - return $this; - } - - /** - * Alias to onConnection. - */ - public function onPool(string $pool): static - { - return $this->onConnection($pool); - } - - public function onConnection(string $connection): static - { - $this->connection = $connection; - - return $this; - } - - public function delay(int $delay): static - { - $this->delay = $delay; - - return $this; - } -} diff --git a/src/support/src/Bus/PendingAsyncQueueDispatch.php b/src/support/src/Bus/PendingAsyncQueueDispatch.php index 50aa8cf8e..eb90a96f2 100644 --- a/src/support/src/Bus/PendingAsyncQueueDispatch.php +++ b/src/support/src/Bus/PendingAsyncQueueDispatch.php @@ -48,6 +48,11 @@ public function onPool(string $pool): static return $this; } + public function onConnection(string $connection): static + { + return $this->onPool($connection); + } + public function delay(int $delay): static { $this->delay = $delay; diff --git a/tests/AsyncQueueClosureJob/BasicFunctionalityTest.php b/tests/AsyncQueueClosureJob/BasicFunctionalityTest.php index 272e60c7c..43d61ac47 100644 --- a/tests/AsyncQueueClosureJob/BasicFunctionalityTest.php +++ b/tests/AsyncQueueClosureJob/BasicFunctionalityTest.php @@ -224,7 +224,7 @@ public function testMultipleCreateCallsWithDifferentMaxAttempts() } // Note: Dispatch function tests are omitted due to container configuration requirements - // The functionality is tested through PendingClosureDispatch direct instantiation + // The functionality is tested through PendingAsyncQueueDispatch direct instantiation /** * Helper method to get protected/private property value. diff --git a/tests/AsyncQueueClosureJob/CoreFunctionalityTest.php b/tests/AsyncQueueClosureJob/CoreFunctionalityTest.php index f13408874..4c29f2a16 100644 --- a/tests/AsyncQueueClosureJob/CoreFunctionalityTest.php +++ b/tests/AsyncQueueClosureJob/CoreFunctionalityTest.php @@ -12,7 +12,7 @@ namespace FriendsOfHyperf\Tests\AsyncQueueClosureJob; use FriendsOfHyperf\AsyncQueueClosureJob\CallQueuedClosure; -use FriendsOfHyperf\AsyncQueueClosureJob\PendingClosureDispatch; +use FriendsOfHyperf\Support\Bus\PendingAsyncQueueDispatch; use FriendsOfHyperf\Tests\TestCase; use Hyperf\AsyncQueue\Driver\Driver; use Hyperf\AsyncQueue\Driver\DriverFactory; @@ -94,13 +94,13 @@ public function testCallQueuedClosureConstructorWithMaxAttempts() $this->assertEquals(3, $job->getMaxAttempts()); } - public function testPendingClosureDispatchConfiguration() + public function testPendingAsyncQueueDispatchConfiguration() { $job = CallQueuedClosure::create(function () { return 'test'; }); - $dispatch = new PendingClosureDispatch($job); + $dispatch = new PendingAsyncQueueDispatch($job); // Test configuration methods $result = $dispatch->onConnection('test-connection') @@ -108,7 +108,7 @@ public function testPendingClosureDispatchConfiguration() ->setMaxAttempts(7); $this->assertSame($dispatch, $result); - $this->assertEquals('test-connection', $this->getProperty($dispatch, 'connection')); + $this->assertEquals('test-connection', $this->getProperty($dispatch, 'pool')); $this->assertEquals(30, $this->getProperty($dispatch, 'delay')); $this->assertEquals(7, $job->getMaxAttempts()); } @@ -122,7 +122,7 @@ public function testDispatchFunctionCreatesCorrectObjects() $dispatch = \FriendsOfHyperf\AsyncQueueClosureJob\dispatch($closure); $dispatch->setMaxAttempts(4); - $this->assertInstanceOf(PendingClosureDispatch::class, $dispatch); + $this->assertInstanceOf(PendingAsyncQueueDispatch::class, $dispatch); $job = $this->getProperty($dispatch, 'job'); $this->assertInstanceOf(CallQueuedClosure::class, $job); @@ -137,7 +137,7 @@ public function testDispatchFunctionWithDefaultMaxAttempts() $dispatch = \FriendsOfHyperf\AsyncQueueClosureJob\dispatch($closure); - $this->assertInstanceOf(PendingClosureDispatch::class, $dispatch); + $this->assertInstanceOf(PendingAsyncQueueDispatch::class, $dispatch); $job = $this->getProperty($dispatch, 'job'); $this->assertInstanceOf(CallQueuedClosure::class, $job); @@ -155,7 +155,7 @@ public function testFluentMethodChaining() ->delay(60) ->setMaxAttempts(8); // Override initial value - $this->assertEquals('chained-connection', $this->getProperty($dispatch, 'connection')); + $this->assertEquals('chained-connection', $this->getProperty($dispatch, 'pool')); $this->assertEquals(60, $this->getProperty($dispatch, 'delay')); $job = $this->getProperty($dispatch, 'job'); @@ -174,7 +174,7 @@ public function testConditionableTraitFunctionality() $dispatch->onConnection('when-true-connection'); }); - $this->assertEquals('when-true-connection', $this->getProperty($dispatch1, 'connection')); + $this->assertEquals('when-true-connection', $this->getProperty($dispatch1, 'pool')); // Test when() with false condition $dispatch2 = \FriendsOfHyperf\AsyncQueueClosureJob\dispatch($closure) @@ -182,7 +182,7 @@ public function testConditionableTraitFunctionality() $dispatch->onConnection('when-false-connection'); }); - $this->assertEquals('default', $this->getProperty($dispatch2, 'connection')); + $this->assertEquals('default', $this->getProperty($dispatch2, 'pool')); // Test unless() with true condition $dispatch3 = \FriendsOfHyperf\AsyncQueueClosureJob\dispatch($closure) @@ -190,7 +190,7 @@ public function testConditionableTraitFunctionality() $dispatch->onConnection('unless-true-connection'); }); - $this->assertEquals('default', $this->getProperty($dispatch3, 'connection')); + $this->assertEquals('default', $this->getProperty($dispatch3, 'pool')); // Test unless() with false condition $dispatch4 = \FriendsOfHyperf\AsyncQueueClosureJob\dispatch($closure) @@ -198,7 +198,7 @@ public function testConditionableTraitFunctionality() $dispatch->onConnection('unless-false-connection'); }); - $this->assertEquals('unless-false-connection', $this->getProperty($dispatch4, 'connection')); + $this->assertEquals('unless-false-connection', $this->getProperty($dispatch4, 'pool')); } public function testJobExecutionWithMaxAttempts() diff --git a/tests/AsyncQueueClosureJob/DispatchFunctionSimpleTest.php b/tests/AsyncQueueClosureJob/DispatchFunctionSimpleTest.php index 1177a18d4..1ddd9f013 100644 --- a/tests/AsyncQueueClosureJob/DispatchFunctionSimpleTest.php +++ b/tests/AsyncQueueClosureJob/DispatchFunctionSimpleTest.php @@ -12,7 +12,7 @@ namespace FriendsOfHyperf\Tests\AsyncQueueClosureJob; use FriendsOfHyperf\AsyncQueueClosureJob\CallQueuedClosure; -use FriendsOfHyperf\AsyncQueueClosureJob\PendingClosureDispatch; +use FriendsOfHyperf\Support\Bus\PendingAsyncQueueDispatch; use FriendsOfHyperf\Tests\TestCase; use Hyperf\AsyncQueue\Driver\Driver; use Hyperf\AsyncQueue\Driver\DriverFactory; @@ -64,7 +64,7 @@ public function testDispatchFunctionWithDefaultMaxAttempts() $dispatch = \FriendsOfHyperf\AsyncQueueClosureJob\dispatch($closure); - $this->assertInstanceOf(PendingClosureDispatch::class, $dispatch); + $this->assertInstanceOf(PendingAsyncQueueDispatch::class, $dispatch); // Verify the job has default maxAttempts (0) $job = $this->getProperty($dispatch, 'job'); @@ -81,7 +81,7 @@ public function testDispatchFunctionWithCustomMaxAttempts() $dispatch = \FriendsOfHyperf\AsyncQueueClosureJob\dispatch($closure); $dispatch->setMaxAttempts(5); - $this->assertInstanceOf(PendingClosureDispatch::class, $dispatch); + $this->assertInstanceOf(PendingAsyncQueueDispatch::class, $dispatch); // Verify the job has the specified maxAttempts $job = $this->getProperty($dispatch, 'job'); @@ -98,7 +98,7 @@ public function testDispatchFunctionWithZeroMaxAttempts() $dispatch = \FriendsOfHyperf\AsyncQueueClosureJob\dispatch($closure); $dispatch->setMaxAttempts(0); - $this->assertInstanceOf(PendingClosureDispatch::class, $dispatch); + $this->assertInstanceOf(PendingAsyncQueueDispatch::class, $dispatch); // Verify the job has zero maxAttempts $job = $this->getProperty($dispatch, 'job'); @@ -117,7 +117,7 @@ public function testDispatchFunctionChainingWithMaxAttempts() ->delay(120) ->setMaxAttempts(5); // Override the initial maxAttempts - $this->assertInstanceOf(PendingClosureDispatch::class, $dispatch); + $this->assertInstanceOf(PendingAsyncQueueDispatch::class, $dispatch); // Verify the job has the overridden maxAttempts $job = $this->getProperty($dispatch, 'job'); @@ -125,7 +125,7 @@ public function testDispatchFunctionChainingWithMaxAttempts() $this->assertEquals(5, $job->getMaxAttempts()); // Should be overridden to 5 // Verify fluent configuration - $this->assertEquals('delayed-connection', $this->getProperty($dispatch, 'connection')); + $this->assertEquals('delayed-connection', $this->getProperty($dispatch, 'pool')); $this->assertEquals(120, $this->getProperty($dispatch, 'delay')); } @@ -144,10 +144,10 @@ public function testDispatchFunctionConditionableMethods() }) ->setMaxAttempts(1); - $this->assertInstanceOf(PendingClosureDispatch::class, $dispatch); + $this->assertInstanceOf(PendingAsyncQueueDispatch::class, $dispatch); // Verify configuration - $this->assertEquals('conditional-connection', $this->getProperty($dispatch, 'connection')); + $this->assertEquals('conditional-connection', $this->getProperty($dispatch, 'pool')); $this->assertEquals(45, $this->getProperty($dispatch, 'delay')); // Verify the job has the specified maxAttempts @@ -171,7 +171,7 @@ public function testDispatchFunctionWithMultipleConfigurations() ->delay(300) // Override delay ->setMaxAttempts(10); // Final maxAttempts - $this->assertEquals('multi-config-connection', $this->getProperty($dispatch, 'connection')); + $this->assertEquals('multi-config-connection', $this->getProperty($dispatch, 'pool')); $this->assertEquals(300, $this->getProperty($dispatch, 'delay')); $job = $this->getProperty($dispatch, 'job'); diff --git a/tests/AsyncQueueClosureJob/DispatchFunctionTest.php b/tests/AsyncQueueClosureJob/DispatchFunctionTest.php index 8166e1951..5f90fc6fe 100644 --- a/tests/AsyncQueueClosureJob/DispatchFunctionTest.php +++ b/tests/AsyncQueueClosureJob/DispatchFunctionTest.php @@ -12,7 +12,7 @@ namespace FriendsOfHyperf\Tests\AsyncQueueClosureJob; use FriendsOfHyperf\AsyncQueueClosureJob\CallQueuedClosure; -use FriendsOfHyperf\AsyncQueueClosureJob\PendingClosureDispatch; +use FriendsOfHyperf\Support\Bus\PendingAsyncQueueDispatch; use FriendsOfHyperf\Tests\TestCase; use Hyperf\AsyncQueue\Driver\Driver; use Hyperf\AsyncQueue\Driver\DriverFactory; @@ -59,7 +59,7 @@ public function testDispatchFunctionWithDefaultMaxAttempts() $dispatch = \FriendsOfHyperf\AsyncQueueClosureJob\dispatch($closure); - $this->assertInstanceOf(PendingClosureDispatch::class, $dispatch); + $this->assertInstanceOf(PendingAsyncQueueDispatch::class, $dispatch); // Verify the job has default maxAttempts (0) $job = $this->getProperty($dispatch, 'job'); @@ -94,7 +94,7 @@ public function testDispatchFunctionWithCustomMaxAttempts() $dispatch = \FriendsOfHyperf\AsyncQueueClosureJob\dispatch($closure); $dispatch->setMaxAttempts(5); - $this->assertInstanceOf(PendingClosureDispatch::class, $dispatch); + $this->assertInstanceOf(PendingAsyncQueueDispatch::class, $dispatch); // Verify the job has the specified maxAttempts $job = $this->getProperty($dispatch, 'job'); @@ -137,7 +137,7 @@ public function testDispatchFunctionWithFluentConfiguration() ->delay(30) ->setMaxAttempts(3); - $this->assertInstanceOf(PendingClosureDispatch::class, $dispatch); + $this->assertInstanceOf(PendingAsyncQueueDispatch::class, $dispatch); // Verify the job has the specified maxAttempts $job = $this->getProperty($dispatch, 'job'); @@ -181,7 +181,7 @@ public function testDispatchFunctionChainingWithMaxAttempts() ->delay(120) ->setMaxAttempts(5); // Override the initial maxAttempts - $this->assertInstanceOf(PendingClosureDispatch::class, $dispatch); + $this->assertInstanceOf(PendingAsyncQueueDispatch::class, $dispatch); // Verify the job has the overridden maxAttempts $job = $this->getProperty($dispatch, 'job'); @@ -218,7 +218,7 @@ public function testDispatchFunctionWithZeroMaxAttempts() $dispatch = \FriendsOfHyperf\AsyncQueueClosureJob\dispatch($closure); $dispatch->setMaxAttempts(0); - $this->assertInstanceOf(PendingClosureDispatch::class, $dispatch); + $this->assertInstanceOf(PendingAsyncQueueDispatch::class, $dispatch); // Verify the job has zero maxAttempts $job = $this->getProperty($dispatch, 'job'); @@ -261,10 +261,10 @@ public function testDispatchFunctionConditionableMethods() }) ->setMaxAttempts(1); - $this->assertInstanceOf(PendingClosureDispatch::class, $dispatch); + $this->assertInstanceOf(PendingAsyncQueueDispatch::class, $dispatch); // Verify configuration - $this->assertEquals('conditional-connection', $this->getProperty($dispatch, 'connection')); + $this->assertEquals('conditional-connection', $this->getProperty($dispatch, 'pool')); $this->assertEquals(45, $this->getProperty($dispatch, 'delay')); // Verify the job has the specified maxAttempts diff --git a/tests/AsyncQueueClosureJob/FluentDispatchIntegrationTest.php b/tests/AsyncQueueClosureJob/FluentDispatchIntegrationTest.php index 16aa6789b..ae66847c8 100644 --- a/tests/AsyncQueueClosureJob/FluentDispatchIntegrationTest.php +++ b/tests/AsyncQueueClosureJob/FluentDispatchIntegrationTest.php @@ -234,7 +234,7 @@ public function testFluentDispatchWithConditionalLogic() }) ->setMaxAttempts(2); - $this->assertEquals('high-priority', $this->getProperty($dispatch, 'connection')); + $this->assertEquals('high-priority', $this->getProperty($dispatch, 'pool')); $this->assertEquals(30, $this->getProperty($dispatch, 'delay')); unset($dispatch); @@ -280,7 +280,7 @@ public function testFluentDispatchWithMultipleConfigurations() ->delay(300) // Override delay ->setMaxAttempts(10); // Final maxAttempts - $this->assertEquals('multi-config-connection', $this->getProperty($dispatch, 'connection')); + $this->assertEquals('multi-config-connection', $this->getProperty($dispatch, 'pool')); $this->assertEquals(300, $this->getProperty($dispatch, 'delay')); $job = $this->getProperty($dispatch, 'job'); diff --git a/tests/AsyncQueueClosureJob/PendingClosureDispatchSimpleTest.php b/tests/AsyncQueueClosureJob/PendingClosureDispatchSimpleTest.php deleted file mode 100644 index 80db6f8a0..000000000 --- a/tests/AsyncQueueClosureJob/PendingClosureDispatchSimpleTest.php +++ /dev/null @@ -1,197 +0,0 @@ -shouldReceive('get') - ->with(DriverFactory::class) - ->zeroOrMoreTimes() - ->byDefault() - ->andReturn($driverFactory); - - $driverFactory->shouldReceive('get') - ->withAnyArgs() - ->zeroOrMoreTimes() - ->byDefault() - ->andReturn($driver); - - $driver->shouldReceive('push') - ->zeroOrMoreTimes() - ->byDefault() - ->andReturnTrue(); - - ApplicationContext::setContainer($container); - } - - protected function tearDown(): void - { - parent::tearDown(); - m::close(); - } - - public function testPendingClosureDispatchCanBeCreated() - { - $job = CallQueuedClosure::create(function () { - return 'test'; - }); - - $dispatch = new PendingClosureDispatch($job); - - $this->assertInstanceOf(PendingClosureDispatch::class, $dispatch); - $this->assertSame($job, $this->getProperty($dispatch, 'job')); - } - - public function testSetMaxAttemptsMethod() - { - $job = m::mock(CallQueuedClosure::class); - $job->shouldReceive('setMaxAttempts') - ->once() - ->with(5); - - $dispatch = new PendingClosureDispatch($job); - $result = $dispatch->setMaxAttempts(5); - - $this->assertSame($dispatch, $result); - } - - public function testonConnectionMethod() - { - $job = m::mock(CallQueuedClosure::class); - - $dispatch = new PendingClosureDispatch($job); - $result = $dispatch->onConnection('high-priority'); - - $this->assertSame($dispatch, $result); - $this->assertEquals('high-priority', $this->getProperty($dispatch, 'connection')); - } - - public function testDelayMethod() - { - $job = m::mock(CallQueuedClosure::class); - - $dispatch = new PendingClosureDispatch($job); - $result = $dispatch->delay(60); - - $this->assertSame($dispatch, $result); - $this->assertEquals(60, $this->getProperty($dispatch, 'delay')); - } - - public function testMethodChaining() - { - $job = m::mock(CallQueuedClosure::class); - $job->shouldReceive('setMaxAttempts') - ->once() - ->with(3); - - $dispatch = new PendingClosureDispatch($job); - $result = $dispatch->onConnection('default') - ->delay(30) - ->setMaxAttempts(3); - - $this->assertSame($dispatch, $result); - $this->assertEquals('default', $this->getProperty($dispatch, 'connection')); - $this->assertEquals(30, $this->getProperty($dispatch, 'delay')); - } - - public function testDefaultValues() - { - $job = m::mock(CallQueuedClosure::class); - $dispatch = new PendingClosureDispatch($job); - - $this->assertEquals('default', $this->getProperty($dispatch, 'connection')); - $this->assertEquals(0, $this->getProperty($dispatch, 'delay')); - } - - public function testConditionableTrait() - { - $job = m::mock(CallQueuedClosure::class); - - $dispatch = new PendingClosureDispatch($job); - - // Test when() method from Conditionable trait - $result = $dispatch->when(true, function ($dispatch) { - $dispatch->onConnection('conditional-connection'); - }); - - $this->assertSame($dispatch, $result); - $this->assertEquals('conditional-connection', $this->getProperty($dispatch, 'connection')); - - // Test when() with false condition - $dispatch2 = new PendingClosureDispatch($job); - $result2 = $dispatch2->when(false, function ($dispatch) { - $dispatch->onConnection('should-not-change'); - }); - - $this->assertSame($dispatch2, $result2); - $this->assertEquals('default', $this->getProperty($dispatch2, 'connection')); - } - - public function testUnlessMethodFromConditionableTrait() - { - $job = m::mock(CallQueuedClosure::class); - - $dispatch = new PendingClosureDispatch($job); - - // Test unless() method from Conditionable trait - $result = $dispatch->unless(false, function ($dispatch) { - $dispatch->onConnection('unless-connection'); - }); - - $this->assertSame($dispatch, $result); - $this->assertEquals('unless-connection', $this->getProperty($dispatch, 'connection')); - - // Test unless() with true condition - $dispatch2 = new PendingClosureDispatch($job); - $result2 = $dispatch2->unless(true, function ($dispatch) { - $dispatch->onConnection('should-not-connection'); - }); - - $this->assertSame($dispatch2, $result2); - $this->assertEquals('default', $this->getProperty($dispatch2, 'connection')); - } - - /** - * Helper method to get protected/private property value. - */ - protected function getProperty(object $object, string $property): mixed - { - $reflection = new ReflectionClass($object); - $property = $reflection->getProperty($property); - $property->setAccessible(true); - - return $property->getValue($object); - } -} diff --git a/tests/AsyncQueueClosureJob/PendingClosureDispatchTest.php b/tests/AsyncQueueClosureJob/PendingClosureDispatchTest.php deleted file mode 100644 index 01070a9f3..000000000 --- a/tests/AsyncQueueClosureJob/PendingClosureDispatchTest.php +++ /dev/null @@ -1,223 +0,0 @@ -shouldReceive('get') - ->with(DriverFactory::class) - ->andReturn($driverFactory); - - $driverFactory->shouldReceive('get') - ->withAnyArgs() - ->andReturn($driver); - - $driver->shouldReceive('push') - ->andReturnTrue(); - - ApplicationContext::setContainer($container); - } - - protected function tearDown(): void - { - parent::tearDown(); - m::close(); - } - - public function testPendingClosureDispatchCanBeCreated() - { - $job = CallQueuedClosure::create(function () { - return 'test'; - }); - - $dispatch = new PendingClosureDispatch($job); - - $this->assertInstanceOf(PendingClosureDispatch::class, $dispatch); - $this->assertSame($job, $this->getProperty($dispatch, 'job')); - } - - public function testSetMaxAttemptsMethod() - { - $job = m::mock(CallQueuedClosure::class); - $job->shouldReceive('setMaxAttempts') - ->once() - ->with(5); - - $dispatch = new PendingClosureDispatch($job); - $result = $dispatch->setMaxAttempts(5); - - $this->assertSame($dispatch, $result); - } - - public function testOnQueueMethod() - { - $job = m::mock(CallQueuedClosure::class); - - $dispatch = new PendingClosureDispatch($job); - $result = $dispatch->onConnection('high-priority'); - - $this->assertSame($dispatch, $result); - $this->assertEquals('high-priority', $this->getProperty($dispatch, 'connection')); - } - - public function testDelayMethod() - { - $job = m::mock(CallQueuedClosure::class); - - $dispatch = new PendingClosureDispatch($job); - $result = $dispatch->delay(60); - - $this->assertSame($dispatch, $result); - $this->assertEquals(60, $this->getProperty($dispatch, 'delay')); - } - - public function testMethodChaining() - { - $job = m::mock(CallQueuedClosure::class); - $job->shouldReceive('setMaxAttempts') - ->once() - ->with(3); - - $dispatch = new PendingClosureDispatch($job); - $result = $dispatch->onConnection('default') - ->delay(30) - ->setMaxAttempts(3); - - $this->assertSame($dispatch, $result); - $this->assertEquals('default', $this->getProperty($dispatch, 'connection')); - $this->assertEquals(30, $this->getProperty($dispatch, 'delay')); - } - - public function testAutoDispatchOnDestruction() - { - $job = m::mock(CallQueuedClosure::class); - - // Mock the container and driver factory - $container = m::mock(ContainerInterface::class); - $driverFactory = m::mock(DriverFactory::class); - $driver = m::mock(Driver::class); - - $container->shouldReceive('get') - ->with(DriverFactory::class) - ->once() - ->andReturn($driverFactory); - - $driverFactory->shouldReceive('get') - ->with('custom-connection') - ->once() - ->andReturn($driver); - - $driver->shouldReceive('push') - ->once() - ->with($job, 120) - ->andReturnTrue(); - - ApplicationContext::setContainer($container); - - $dispatch = new PendingClosureDispatch($job); - $dispatch->onConnection('custom-connection')->delay(120); - - // Trigger destruct by unsetting - unset($dispatch); - } - - public function testDefaultValues() - { - $job = m::mock(CallQueuedClosure::class); - $dispatch = new PendingClosureDispatch($job); - - $this->assertEquals('default', $this->getProperty($dispatch, 'connection')); - $this->assertEquals(0, $this->getProperty($dispatch, 'delay')); - } - - public function testConditionableTrait() - { - $job = m::mock(CallQueuedClosure::class); - - $dispatch = new PendingClosureDispatch($job); - - // Test when() method from Conditionable trait - $result = $dispatch->when(true, function ($dispatch) { - $dispatch->onConnection('conditional-connection'); - }); - - $this->assertSame($dispatch, $result); - $this->assertEquals('conditional-connection', $this->getProperty($dispatch, 'connection')); - - // Test when() with false condition - $dispatch2 = new PendingClosureDispatch($job); - $result2 = $dispatch2->when(false, function ($dispatch) { - $dispatch->onConnection('should-not-change'); - }); - - $this->assertSame($dispatch2, $result2); - $this->assertEquals('default', $this->getProperty($dispatch2, 'connection')); - } - - public function testUnlessMethodFromConditionableTrait() - { - $job = m::mock(CallQueuedClosure::class); - $dispatch = new PendingClosureDispatch($job); - - // Test unless() method from Conditionable trait - $result = $dispatch->unless(false, function ($dispatch) { - $dispatch->onConnection('unless-connection'); - }); - - $this->assertSame($dispatch, $result); - $this->assertEquals('unless-connection', $this->getProperty($dispatch, 'connection')); - - // Test unless() with true condition - $dispatch2 = new PendingClosureDispatch($job); - $result2 = $dispatch2->unless(true, function ($dispatch) { - $dispatch->onConnection('should-not-change'); - }); - - $this->assertSame($dispatch2, $result2); - $this->assertEquals('default', $this->getProperty($dispatch2, 'connection')); - } - - /** - * Helper method to get protected/private property value. - */ - protected function getProperty(object $object, string $property): mixed - { - $reflection = new ReflectionClass($object); - $property = $reflection->getProperty($property); - $property->setAccessible(true); - - return $property->getValue($object); - } -} From 6802dfd106d1cf4ea2135111153183253e7fc052 Mon Sep 17 00:00:00 2001 From: huangdijia <8337659+huangdijia@users.noreply.github.com> Date: Fri, 14 Nov 2025 13:17:42 +0000 Subject: [PATCH 02/11] Update docs and translate --- docs/en/components/async-queue-closure-job.md | 134 +++++++++--------- .../components/async-queue-closure-job.md | 122 ++++++++-------- docs/zh-hk/guide/start/components.md | 1 + .../components/async-queue-closure-job.md | 114 +++++++-------- docs/zh-tw/guide/start/components.md | 1 + 5 files changed, 187 insertions(+), 185 deletions(-) diff --git a/docs/en/components/async-queue-closure-job.md b/docs/en/components/async-queue-closure-job.md index 66795ff6c..52bf9bb33 100644 --- a/docs/en/components/async-queue-closure-job.md +++ b/docs/en/components/async-queue-closure-job.md @@ -2,9 +2,9 @@ ## Introduction -`friendsofhyperf/async-queue-closure-job` is an async queue closure job component for Hyperf. It allows you to execute closures as background jobs with full support for dependency injection and fluent configuration, making async tasks simpler and more elegant. +`friendsofhyperf/async-queue-closure-job` is an asynchronous queue closure job component for Hyperf. It allows you to execute closures as background tasks, with full support for dependency injection and fluent configuration, making the use of asynchronous tasks simpler and more elegant. -Unlike traditional job classes, this component lets you define job logic directly with closures, eliminating the need for extra class files and making your code more concise. +Unlike traditional methods that require creating task classes, this component enables you to define task logic directly using closures, eliminating the need for additional class files and resulting in cleaner code. ## Installation @@ -14,26 +14,26 @@ composer require friendsofhyperf/async-queue-closure-job ## Basic Usage -### Simple Closure Job +### Simple Closure Task ```php use function FriendsOfHyperf\AsyncQueueClosureJob\dispatch; -// Dispatch a simple closure job +// Dispatch a simple closure task dispatch(function () { - // Your job logic here + // Your task logic var_dump('Hello from closure job!'); }); ``` -### Set Maximum Attempts +### Setting Maximum Attempts ```php use function FriendsOfHyperf\AsyncQueueClosureJob\dispatch; // Set maximum attempts (retry limit) dispatch(function () { - // Your job logic here + // Your task logic // If it fails, it will retry up to 3 times })->setMaxAttempts(3); ``` @@ -42,59 +42,59 @@ dispatch(function () { ### Fluent API Configuration -You can flexibly configure various options using method chaining: +You can flexibly configure various task options through method chaining: ```php use function FriendsOfHyperf\AsyncQueueClosureJob\dispatch; // Chain multiple configuration options dispatch(function () { - // Your job logic here + // Your task logic }) ->onConnection('high-priority') // Specify queue connection ->delay(60) // Delay execution by 60 seconds - ->setMaxAttempts(5); // Retry up to 5 times + ->setMaxAttempts(5); // Maximum of 5 retries ``` -### Specifying Queue Connections +### Specifying Queue Connection -When you have multiple queue connections, you can specify which connection to use: +When you have multiple queue connections, you can specify which connection the task should use: ```php use function FriendsOfHyperf\AsyncQueueClosureJob\dispatch; -// Use a specific queue connection +// Use specified queue connection dispatch(function () { - // High priority task logic + // High-priority task logic })->onConnection('high-priority'); // Or use the onPool method (alias) dispatch(function () { - // Low priority task logic + // Low-priority task logic })->onPool('low-priority'); ``` ### Delayed Execution -You can set a delay before the task starts executing: +You can set tasks to execute after a certain period: ```php use function FriendsOfHyperf\AsyncQueueClosureJob\dispatch; -// Delay execution by 60 seconds +// Execute after 60 seconds delay dispatch(function () { - // Your job logic here + // Your task logic })->delay(60); -// Delay execution by 5 minutes +// Execute after 5 minutes delay dispatch(function () { - // Your job logic here + // Your task logic })->delay(300); ``` ### Conditional Execution -Use `when` and `unless` methods to dynamically configure tasks based on conditions: +Use the `when` and `unless` methods to dynamically configure tasks based on conditions: ```php use function FriendsOfHyperf\AsyncQueueClosureJob\dispatch; @@ -103,7 +103,7 @@ $isUrgent = true; // Execute callback only when condition is true dispatch(function () { - // Your job logic here + // Your task logic }) ->when($isUrgent, function ($dispatch) { $dispatch->onConnection('urgent'); @@ -111,15 +111,15 @@ dispatch(function () { // Execute callback only when condition is false dispatch(function () { - // Your job logic here + // Your task logic }) ->unless($isUrgent, function ($dispatch) { - $dispatch->delay(30); + $dispatch->delay(300); }); -// Combine usage +// Combined usage dispatch(function () { - // Your job logic here + // Your task logic }) ->when($isUrgent, function ($dispatch) { $dispatch->onConnection('urgent'); @@ -131,7 +131,7 @@ dispatch(function () { ### Dependency Injection -Closure jobs fully support Hyperf's dependency injection. You can declare required dependencies as closure parameters: +Closure tasks fully support Hyperf's dependency injection functionality. You can declare required dependencies in the closure parameters: ```php use function FriendsOfHyperf\AsyncQueueClosureJob\dispatch; @@ -142,9 +142,9 @@ use Psr\Log\LoggerInterface; dispatch(function (UserService $userService, LoggerInterface $logger) { $users = $userService->getActiveUsers(); $logger->info('Processing ' . count($users) . ' users'); - + foreach ($users as $user) { - // Process users... + // Process user... } }); ``` @@ -159,17 +159,17 @@ use function FriendsOfHyperf\AsyncQueueClosureJob\dispatch; $userId = 123; $action = 'update'; -// Use captured variables +// Using captured variables dispatch(function (UserService $userService) use ($userId, $action) { $user = $userService->find($userId); - + if ($action === 'update') { $userService->update($user); } })->setMaxAttempts(3); ``` -## Real-World Use Cases +## Practical Application Scenarios ### Sending Notifications @@ -181,7 +181,7 @@ dispatch(function (NotificationService $notification) use ($userId, $message) { })->setMaxAttempts(3); ``` -### File Upload Processing +### Processing File Uploads ```php use function FriendsOfHyperf\AsyncQueueClosureJob\dispatch; @@ -221,10 +221,10 @@ foreach ($userIds as $userId) { ### `dispatch(Closure $closure): PendingAsyncQueueDispatch` -The main dispatch function that creates a closure job. +The main dispatch function used to create closure tasks. **Parameters:** -- `$closure` - The closure to execute +- `$closure` - The closure to be executed **Returns:** - `PendingAsyncQueueDispatch` - Pending closure dispatch object @@ -239,85 +239,85 @@ Set the queue connection name. - `$connection` - Queue connection name **Returns:** -- `static` - Current object for method chaining +- `static` - Current object, supports method chaining #### `onPool(string $pool): static` -Set the queue connection name (alias for `onConnection`). +Set the queue connection name (alias of `onConnection`). **Parameters:** - `$pool` - Queue connection name **Returns:** -- `static` - Current object for method chaining +- `static` - Current object, supports method chaining #### `delay(int $delay): static` -Set the delay time before execution. +Set the delay execution time. **Parameters:** - `$delay` - Delay time in seconds **Returns:** -- `static` - Current object for method chaining +- `static` - Current object, supports method chaining #### `setMaxAttempts(int $maxAttempts): static` -Set the maximum retry attempts. +Set the maximum number of retry attempts. **Parameters:** -- `$maxAttempts` - Maximum attempts +- `$maxAttempts` - Maximum number of attempts **Returns:** -- `static` - Current object for method chaining +- `static` - Current object, supports method chaining #### `when($condition, $callback): static` Execute callback when condition is true. **Parameters:** -- `$condition` - Condition expression +- `$condition` - Conditional expression - `$callback` - Callback function that receives the current object as parameter **Returns:** -- `static` - Current object for method chaining +- `static` - Current object, supports method chaining #### `unless($condition, $callback): static` Execute callback when condition is false. **Parameters:** -- `$condition` - Condition expression +- `$condition` - Conditional expression - `$callback` - Callback function that receives the current object as parameter **Returns:** -- `static` - Current object for method chaining +- `static` - Current object, supports method chaining ## Supported Closure Types -This component supports the following closure types: +This component supports the following types of closures: - ✅ Simple closures without parameters - ✅ Closures with dependency injection -- ✅ Closures with captured variables (`use`) +- ✅ Closures using captured variables (`use`) - ✅ Closures with nullable parameters -- ✅ Mixing dependency injection and captured variables +- ✅ Closures mixing dependency injection and captured variables ## Notes -1. **Serialization Limitations**: Closures are serialized before storage, therefore: - - Cannot capture non-serializable resources (e.g., database connections, file handles) +1. **Serialization Limitations**: Closures are serialized for storage, therefore: + - Cannot capture unserializable resources (such as database connections, file handles, etc.) - Captured objects should be serializable -2. **Dependency Injection**: Dependencies in closures will be resolved from the container when the job executes, not serialized +2. **Dependency Injection**: Dependencies in closures are resolved from the container when the task executes and are not serialized -3. **Async Execution**: Tasks execute asynchronously. The dispatch function returns immediately without waiting for task completion +3. **Asynchronous Execution**: Tasks are executed asynchronously; the dispatch function returns immediately without waiting for task completion -4. **Error Handling**: Failed tasks will retry according to the `setMaxAttempts` configuration +4. **Error Handling**: Failed task executions will be retried according to the number of attempts set by `setMaxAttempts` ## Configuration -This component uses Hyperf's async queue configuration. You can configure queue parameters in `config/autoload/async_queue.php`: +This component uses Hyperf's asynchronous queue configuration. You can configure queue parameters in `config/autoload/async_queue.php`: ```php push(new SendNotificationJob($userId, $message)); ``` -### Using Closure Jobs +### Using Closure Tasks ```php use function FriendsOfHyperf\AsyncQueueClosureJob\dispatch; -// Directly use closure, no need to create a class +// Use closure directly, no need to create class dispatch(function (NotificationService $notification) use ($userId, $message) { $notification->send($userId, $message); }); ``` -Advantages of closure jobs: -- Cleaner code, no need to create extra class files -- Better readability, job logic is right where it's dispatched -- Full dependency injection support +Advantages of closure tasks: +- Cleaner code, no need for additional class files +- Better readability with task logic located at dispatch point +- Full support for dependency injection - Flexible fluent API configuration ## Related Components -- [hyperf/async-queue](https://hyperf.wiki/3.1/#/zh-cn/async-queue) - Hyperf Async Queue -- [friendsofhyperf/closure-job](https://github.com/friendsofhyperf/components/tree/main/src/closure-job) - Generic Closure Job Component +- [hyperf/async-queue](https://hyperf.wiki/3.1/#/en/async-queue) - Hyperf Async Queue +- [friendsofhyperf/closure-job](https://github.com/friendsofhyperf/components/tree/main/src/closure-job) - General Closure Job Component \ No newline at end of file diff --git a/docs/zh-hk/components/async-queue-closure-job.md b/docs/zh-hk/components/async-queue-closure-job.md index 1e9a633d7..7303bc539 100644 --- a/docs/zh-hk/components/async-queue-closure-job.md +++ b/docs/zh-hk/components/async-queue-closure-job.md @@ -1,10 +1,10 @@ -# Async Queue Closure Job(異步隊列閉包任務) +# Async Queue Closure Job ## 簡介 -`friendsofhyperf/async-queue-closure-job` 是一個用於 Hyperf 的異步隊列閉包任務元件。它容許你將閉包作為背景任務執行,完整支援依賴注入和流式配置,讓異步任務的使用變得更加簡單和優雅。 +`friendsofhyperf/async-queue-closure-job` 是一個用於 Hyperf 的異步隊列閉包任務組件。它允許你將閉包作為後台任務執行,完整支持依賴注入和流式配置,讓異步任務的使用變得更加簡單和優雅。 -與傳統的建立任務類別方式不同,該元件容許你直接使用閉包來定義任務邏輯,無需建立額外的類別檔案,使代碼更加簡潔。 +與傳統的創建任務類的方式不同,該組件允許你直接使用閉包來定義任務邏輯,無需創建額外的類文件,使代碼更加簡潔。 ## 安裝 @@ -26,23 +26,23 @@ dispatch(function () { }); ``` -### 設定最大嘗試次數 +### 設置最大嘗試次數 ```php use function FriendsOfHyperf\AsyncQueueClosureJob\dispatch; -// 設定最大嘗試次數(重試限制) +// 設置最大嘗試次數(重試限制) dispatch(function () { // 你的任務邏輯 // 如果失敗,將重試最多 3 次 })->setMaxAttempts(3); ``` -## 進階用法 +## 高級用法 ### 流式 API 配置 -透過鏈式調用的方式,你可以靈活地配置任務的各種選項: +通過鏈式調用的方式,你可以靈活地配置任務的各種選項: ```php use function FriendsOfHyperf\AsyncQueueClosureJob\dispatch; @@ -51,19 +51,19 @@ use function FriendsOfHyperf\AsyncQueueClosureJob\dispatch; dispatch(function () { // 你的任務邏輯 }) - ->onConnection('high-priority') // 指定隊列連線 + ->onConnection('high-priority') // 指定隊列連接 ->delay(60) // 延遲 60 秒執行 ->setMaxAttempts(5); // 最多重試 5 次 ``` -### 指定隊列連線 +### 指定隊列連接 -當你有多個隊列連線時,可以指定任務使用的連線: +當你有多個隊列連接時,可以指定任務使用的連接: ```php use function FriendsOfHyperf\AsyncQueueClosureJob\dispatch; -// 使用指定的隊列連線 +// 使用指定的隊列連接 dispatch(function () { // 高優先級任務邏輯 })->onConnection('high-priority'); @@ -76,7 +76,7 @@ dispatch(function () { ### 延遲執行 -你可以設定任務在一段時間後才開始執行: +你可以設置任務在一段時間後才開始執行: ```php use function FriendsOfHyperf\AsyncQueueClosureJob\dispatch; @@ -101,7 +101,7 @@ use function FriendsOfHyperf\AsyncQueueClosureJob\dispatch; $isUrgent = true; -// 僅當條件為 true 時執行回撥 +// 僅當條件為 true 時執行回調 dispatch(function () { // 你的任務邏輯 }) @@ -109,7 +109,7 @@ dispatch(function () { $dispatch->onConnection('urgent'); }); -// 僅當條件為 false 時執行回撥 +// 僅當條件為 false 時執行回調 dispatch(function () { // 你的任務邏輯 }) @@ -131,7 +131,7 @@ dispatch(function () { ### 依賴注入 -閉包任務完整支援 Hyperf 的依賴注入功能,你可以在閉包參數中宣告需要的依賴: +閉包任務完整支持 Hyperf 的依賴注入功能,你可以在閉包參數中聲明需要的依賴: ```php use function FriendsOfHyperf\AsyncQueueClosureJob\dispatch; @@ -141,17 +141,17 @@ use Psr\Log\LoggerInterface; // 自動依賴注入 dispatch(function (UserService $userService, LoggerInterface $logger) { $users = $userService->getActiveUsers(); - $logger->info('正在處理 ' . count($users) . ' 個用戶'); - + $logger->info('正在處理 ' . count($users) . ' 個用户'); + foreach ($users as $user) { - // 處理用戶... + // 處理用户... } }); ``` -### 使用捕獲變數 +### 使用捕獲變量 -你可以透過 `use` 關鍵字在閉包中使用外部變數: +你可以通過 `use` 關鍵字在閉包中使用外部變量: ```php use function FriendsOfHyperf\AsyncQueueClosureJob\dispatch; @@ -159,10 +159,10 @@ use function FriendsOfHyperf\AsyncQueueClosureJob\dispatch; $userId = 123; $action = 'update'; -// 使用捕獲變數 +// 使用捕獲變量 dispatch(function (UserService $userService) use ($userId, $action) { $user = $userService->find($userId); - + if ($action === 'update') { $userService->update($user); } @@ -171,7 +171,7 @@ dispatch(function (UserService $userService) use ($userId, $action) { ## 實際應用場景 -### 傳送通知 +### 發送通知 ```php use function FriendsOfHyperf\AsyncQueueClosureJob\dispatch; @@ -181,7 +181,7 @@ dispatch(function (NotificationService $notification) use ($userId, $message) { })->setMaxAttempts(3); ``` -### 處理檔案上載 +### 處理文件上傳 ```php use function FriendsOfHyperf\AsyncQueueClosureJob\dispatch; @@ -203,7 +203,7 @@ dispatch(function (StatisticsService $stats) use ($date) { })->onConnection('statistics'); ``` -### 批次操作 +### 批量操作 ```php use function FriendsOfHyperf\AsyncQueueClosureJob\dispatch; @@ -213,7 +213,7 @@ $userIds = [1, 2, 3, 4, 5]; foreach ($userIds as $userId) { dispatch(function (UserService $userService) use ($userId) { $userService->syncUserData($userId); - })->delay(10 * $userId); // 為每個任務設定不同的延遲 + })->delay(10 * $userId); // 為每個任務設置不同的延遲 } ``` @@ -221,103 +221,103 @@ foreach ($userIds as $userId) { ### `dispatch(Closure $closure): PendingAsyncQueueDispatch` -主要的分發函數,用於建立閉包任務。 +主要的分發函數,用於創建閉包任務。 **參數:** - `$closure` - 要執行的閉包 **返回:** -- `PendingAsyncQueueDispatch` - 待處理的閉包分發物件 +- `PendingAsyncQueueDispatch` - 待處理的閉包分發對象 ### `PendingAsyncQueueDispatch` 方法 #### `onConnection(string $connection): static` -設定隊列連線名稱。 +設置隊列連接名稱。 **參數:** -- `$connection` - 隊列連線名稱 +- `$connection` - 隊列連接名稱 **返回:** -- `static` - 目前物件,支援鏈式調用 +- `static` - 當前對象,支持鏈式調用 #### `onPool(string $pool): static` -設定隊列連線名稱(`onConnection` 的別名)。 +設置隊列連接名稱(`onConnection` 的別名)。 **參數:** -- `$pool` - 隊列連線名稱 +- `$pool` - 隊列連接名稱 **返回:** -- `static` - 目前物件,支援鏈式調用 +- `static` - 當前對象,支持鏈式調用 #### `delay(int $delay): static` -設定延遲執行時間。 +設置延遲執行時間。 **參數:** - `$delay` - 延遲時間(秒) **返回:** -- `static` - 目前物件,支援鏈式調用 +- `static` - 當前對象,支持鏈式調用 #### `setMaxAttempts(int $maxAttempts): static` -設定最大重試次數。 +設置最大重試次數。 **參數:** - `$maxAttempts` - 最大嘗試次數 **返回:** -- `static` - 目前物件,支援鏈式調用 +- `static` - 當前對象,支持鏈式調用 #### `when($condition, $callback): static` -當條件為真時執行回撥。 +當條件為真時執行回調。 **參數:** - `$condition` - 條件表達式 -- `$callback` - 回撥函數,接收目前物件作為參數 +- `$callback` - 回調函數,接收當前對象作為參數 **返回:** -- `static` - 目前物件,支援鏈式調用 +- `static` - 當前對象,支持鏈式調用 #### `unless($condition, $callback): static` -當條件為假時執行回撥。 +當條件為假時執行回調。 **參數:** - `$condition` - 條件表達式 -- `$callback` - 回撥函數,接收目前物件作為參數 +- `$callback` - 回調函數,接收當前對象作為參數 **返回:** -- `static` - 目前物件,支援鏈式調用 +- `static` - 當前對象,支持鏈式調用 -## 支援的閉包類型 +## 支持的閉包類型 -該元件支援以下類型的閉包: +該組件支持以下類型的閉包: - ✅ 無參數的簡單閉包 - ✅ 帶依賴注入的閉包 -- ✅ 使用捕獲變數(`use`)的閉包 +- ✅ 使用捕獲變量(`use`)的閉包 - ✅ 帶可空參數的閉包 -- ✅ 混合依賴注入和捕獲變數的閉包 +- ✅ 混合依賴注入和捕獲變量的閉包 ## 注意事項 -1. **序列化限制**:閉包會被序列化後儲存,因此: - - 不能捕獲無法序列化的資源(如資料庫連線、檔案句柄等) - - 捕獲的物件應該是可序列化的 +1. **序列化限制**:閉包會被序列化後存儲,因此: + - 不能捕獲無法序列化的資源(如數據庫連接、文件句柄等) + - 捕獲的對象應該是可序列化的 2. **依賴注入**:閉包中的依賴會在任務執行時從容器中解析,不會被序列化 3. **異步執行**:任務是異步執行的,dispatch 函數會立即返回,不會等待任務完成 -4. **錯誤處理**:任務執行失敗時會根據 `setMaxAttempts` 設定的次數進行重試 +4. **錯誤處理**:任務執行失敗時會根據 `setMaxAttempts` 設置的次數進行重試 ## 配置 -該元件使用 Hyperf 的異步隊列配置,你可以在 `config/autoload/async_queue.php` 中配置隊列參數: +該組件使用 Hyperf 的異步隊列配置,你可以在 `config/autoload/async_queue.php` 中配置隊列參數: ```php push(new SendNotificationJob($userId, $message)); ```php use function FriendsOfHyperf\AsyncQueueClosureJob\dispatch; -// 直接使用閉包,無需建立類別 +// 直接使用閉包,無需創建類 dispatch(function (NotificationService $notification) use ($userId, $message) { $notification->send($userId, $message); }); ``` 閉包任務的優勢: -- 代碼更簡潔,無需建立額外的類別檔案 +- 代碼更簡潔,無需創建額外的類文件 - 更好的可讀性,任務邏輯就在分發的地方 -- 完整支援依賴注入 +- 完整支持依賴注入 - 靈活的流式 API 配置 -## 相關元件 +## 相關組件 -- [hyperf/async-queue](https://hyperf.wiki/3.1/#/zh-cn/async-queue) - Hyperf 異步隊列 -- [friendsofhyperf/closure-job](https://github.com/friendsofhyperf/components/tree/main/src/closure-job) - 通用閉包任務元件 +- [hyperf/async-queue](https://hyperf.wiki/3.1/#/zh-hk/async-queue) - Hyperf 異步隊列 +- [friendsofhyperf/closure-job](https://github.com/friendsofhyperf/components/tree/main/src/closure-job) - 通用閉包任務組件 diff --git a/docs/zh-hk/guide/start/components.md b/docs/zh-hk/guide/start/components.md index 64772bc7b..5c1191615 100644 --- a/docs/zh-hk/guide/start/components.md +++ b/docs/zh-hk/guide/start/components.md @@ -5,6 +5,7 @@ |Repository|Stable Version|Total Downloads|Monthly Downloads| |--|--|--|--| |[amqp-job](https://github.com/friendsofhyperf/amqp-job)|[![Latest Stable Version](https://poser.pugx.org/friendsofhyperf/amqp-job/v)](https://packagist.org/packages/friendsofhyperf/amqp-job)|[![Total Downloads](https://poser.pugx.org/friendsofhyperf/amqp-job/downloads)](https://packagist.org/packages/friendsofhyperf/amqp-job)|[![Monthly Downloads](https://poser.pugx.org/friendsofhyperf/amqp-job/d/monthly)](https://packagist.org/packages/friendsofhyperf/amqp-job)| +|[async-queue-closure-job](https://github.com/friendsofhyperf/async-queue-closure-job)|[![Latest Stable Version](https://poser.pugx.org/friendsofhyperf/async-queue-closure-job/v)](https://packagist.org/packages/friendsofhyperf/async-queue-closure-job)|[![Total Downloads](https://poser.pugx.org/friendsofhyperf/async-queue-closure-job/downloads)](https://packagist.org/packages/friendsofhyperf/async-queue-closure-job)|[![Monthly Downloads](https://poser.pugx.org/friendsofhyperf/async-queue-closure-job/d/monthly)](https://packagist.org/packages/friendsofhyperf/async-queue-closure-job)| |[cache](https://github.com/friendsofhyperf/cache)|[![Latest Stable Version](https://poser.pugx.org/friendsofhyperf/cache/v)](https://packagist.org/packages/friendsofhyperf/cache)|[![Total Downloads](https://poser.pugx.org/friendsofhyperf/cache/downloads)](https://packagist.org/packages/friendsofhyperf/cache)|[![Monthly Downloads](https://poser.pugx.org/friendsofhyperf/cache/d/monthly)](https://packagist.org/packages/friendsofhyperf/cache)| |[co-phpunit](https://github.com/friendsofhyperf/co-phpunit)|[![Latest Stable Version](https://poser.pugx.org/friendsofhyperf/co-phpunit/v)](https://packagist.org/packages/friendsofhyperf/co-phpunit)|[![Total Downloads](https://poser.pugx.org/friendsofhyperf/co-phpunit/downloads)](https://packagist.org/packages/friendsofhyperf/co-phpunit)|[![Monthly Downloads](https://poser.pugx.org/friendsofhyperf/co-phpunit/d/monthly)](https://packagist.org/packages/friendsofhyperf/co-phpunit)| |[command-benchmark](https://github.com/friendsofhyperf/command-benchmark)|[![Latest Stable Version](https://poser.pugx.org/friendsofhyperf/command-benchmark/v)](https://packagist.org/packages/friendsofhyperf/command-benchmark)|[![Total Downloads](https://poser.pugx.org/friendsofhyperf/command-benchmark/downloads)](https://packagist.org/packages/friendsofhyperf/command-benchmark)|[![Monthly Downloads](https://poser.pugx.org/friendsofhyperf/command-benchmark/d/monthly)](https://packagist.org/packages/friendsofhyperf/command-benchmark)| diff --git a/docs/zh-tw/components/async-queue-closure-job.md b/docs/zh-tw/components/async-queue-closure-job.md index 2016e5331..e4827ebdc 100644 --- a/docs/zh-tw/components/async-queue-closure-job.md +++ b/docs/zh-tw/components/async-queue-closure-job.md @@ -1,10 +1,10 @@ -# Async Queue Closure Job(非同步佇列閉包任務) +# Async Queue Closure Job ## 簡介 -`friendsofhyperf/async-queue-closure-job` 是一個用於 Hyperf 的非同步佇列閉包任務元件。它允許你將閉包作為背景工作執行,完整支援依賴注入和流式配置,讓非同步任務的使用變得更加簡單和優雅。 +`friendsofhyperf/async-queue-closure-job` 是一個用於 Hyperf 的非同步佇列閉包任務元件。它允許你將閉包作為後臺任務執行,完整支援依賴注入和流式配置,讓非同步任務的使用變得更加簡單和優雅。 -與傳統的建立任務類別方式不同,該元件允許你直接使用閉包來定義任務邏輯,無需建立額外的類別檔案,使程式碼更加簡潔。 +與傳統的建立任務類的方式不同,該元件允許你直接使用閉包來定義任務邏輯,無需建立額外的類檔案,使程式碼更加簡潔。 ## 安裝 @@ -19,7 +19,7 @@ composer require friendsofhyperf/async-queue-closure-job ```php use function FriendsOfHyperf\AsyncQueueClosureJob\dispatch; -// 分派一個簡單的閉包任務 +// 分發一個簡單的閉包任務 dispatch(function () { // 你的任務邏輯 var_dump('Hello from closure job!'); @@ -38,7 +38,7 @@ dispatch(function () { })->setMaxAttempts(3); ``` -## 進階用法 +## 高階用法 ### 流式 API 配置 @@ -65,12 +65,12 @@ use function FriendsOfHyperf\AsyncQueueClosureJob\dispatch; // 使用指定的佇列連線 dispatch(function () { - // 高優先級任務邏輯 + // 高優先順序任務邏輯 })->onConnection('high-priority'); // 或者使用 onPool 方法(別名) dispatch(function () { - // 低優先級任務邏輯 + // 低優先順序任務邏輯 })->onPool('low-priority'); ``` @@ -101,7 +101,7 @@ use function FriendsOfHyperf\AsyncQueueClosureJob\dispatch; $isUrgent = true; -// 僅當條件為 true 時執行回呼 +// 僅當條件為 true 時執行回撥 dispatch(function () { // 你的任務邏輯 }) @@ -109,7 +109,7 @@ dispatch(function () { $dispatch->onConnection('urgent'); }); -// 僅當條件為 false 時執行回呼 +// 僅當條件為 false 時執行回撥 dispatch(function () { // 你的任務邏輯 }) @@ -131,7 +131,7 @@ dispatch(function () { ### 依賴注入 -閉包任務完整支援 Hyperf 的依賴注入功能,你可以在閉包參數中宣告需要的依賴: +閉包任務完整支援 Hyperf 的依賴注入功能,你可以在閉包引數中宣告需要的依賴: ```php use function FriendsOfHyperf\AsyncQueueClosureJob\dispatch; @@ -142,7 +142,7 @@ use Psr\Log\LoggerInterface; dispatch(function (UserService $userService, LoggerInterface $logger) { $users = $userService->getActiveUsers(); $logger->info('正在處理 ' . count($users) . ' 個使用者'); - + foreach ($users as $user) { // 處理使用者... } @@ -162,7 +162,7 @@ $action = 'update'; // 使用捕獲變數 dispatch(function (UserService $userService) use ($userId, $action) { $user = $userService->find($userId); - + if ($action === 'update') { $userService->update($user); } @@ -223,10 +223,10 @@ foreach ($userIds as $userId) { 主要的分發函式,用於建立閉包任務。 -**參數:** +**引數:** - `$closure` - 要執行的閉包 -**回傳:** +**返回:** - `PendingAsyncQueueDispatch` - 待處理的閉包分發物件 ### `PendingAsyncQueueDispatch` 方法 @@ -235,89 +235,89 @@ foreach ($userIds as $userId) { 設定佇列連線名稱。 -**參數:** +**引數:** - `$connection` - 佇列連線名稱 -**回傳:** -- `static` - 目前物件,支援鏈式呼叫 +**返回:** +- `static` - 當前物件,支援鏈式呼叫 #### `onPool(string $pool): static` 設定佇列連線名稱(`onConnection` 的別名)。 -**參數:** +**引數:** - `$pool` - 佇列連線名稱 -**回傳:** -- `static` - 目前物件,支援鏈式呼叫 +**返回:** +- `static` - 當前物件,支援鏈式呼叫 #### `delay(int $delay): static` 設定延遲執行時間。 -**參數:** +**引數:** - `$delay` - 延遲時間(秒) -**回傳:** -- `static` - 目前物件,支援鏈式呼叫 +**返回:** +- `static` - 當前物件,支援鏈式呼叫 #### `setMaxAttempts(int $maxAttempts): static` 設定最大重試次數。 -**參數:** +**引數:** - `$maxAttempts` - 最大嘗試次數 -**回傳:** -- `static` - 目前物件,支援鏈式呼叫 +**返回:** +- `static` - 當前物件,支援鏈式呼叫 #### `when($condition, $callback): static` -當條件為真時執行回呼。 +當條件為真時執行回撥。 -**參數:** -- `$condition` - 條件表達式 -- `$callback` - 回呼函式,接收目前物件作為參數 +**引數:** +- `$condition` - 條件表示式 +- `$callback` - 回撥函式,接收當前物件作為引數 -**回傳:** -- `static` - 目前物件,支援鏈式呼叫 +**返回:** +- `static` - 當前物件,支援鏈式呼叫 #### `unless($condition, $callback): static` -當條件為假時執行回呼。 +當條件為假時執行回撥。 -**參數:** -- `$condition` - 條件表達式 -- `$callback` - 回呼函式,接收目前物件作為參數 +**引數:** +- `$condition` - 條件表示式 +- `$callback` - 回撥函式,接收當前物件作為引數 -**回傳:** -- `static` - 目前物件,支援鏈式呼叫 +**返回:** +- `static` - 當前物件,支援鏈式呼叫 -## 支援的閉包類型 +## 支援的閉包型別 -該元件支援以下類型的閉包: +該元件支援以下型別的閉包: -- ✅ 無參數的簡單閉包 +- ✅ 無引數的簡單閉包 - ✅ 帶依賴注入的閉包 - ✅ 使用捕獲變數(`use`)的閉包 -- ✅ 帶可空參數的閉包 +- ✅ 帶可空引數的閉包 - ✅ 混合依賴注入和捕獲變數的閉包 ## 注意事項 1. **序列化限制**:閉包會被序列化後儲存,因此: - - 不能捕獲無法序列化的資源(如資料庫連線、檔案句柄等) + - 不能捕獲無法序列化的資源(如資料庫連線、檔案控制代碼等) - 捕獲的物件應該是可序列化的 -2. **依賴注入**:閉包中的依賴會在工作執行時從容器中解析,不會被序列化 +2. **依賴注入**:閉包中的依賴會在任務執行時從容器中解析,不會被序列化 -3. **非同步執行**:工作是非同步執行的,dispatch 函式會立即返回,不會等待工作完成 +3. **非同步執行**:任務是非同步執行的,dispatch 函式會立即返回,不會等待任務完成 -4. **錯誤處理**:工作執行失敗時會根據 `setMaxAttempts` 設定的次數進行重試 +4. **錯誤處理**:任務執行失敗時會根據 `setMaxAttempts` 設定的次數進行重試 ## 配置 -該元件使用 Hyperf 的非同步佇列配置,你可以在 `config/autoload/async_queue.php` 中配置佇列參數: +該元件使用 Hyperf 的非同步佇列配置,你可以在 `config/autoload/async_queue.php` 中配置佇列引數: ```php push(new SendNotificationJob($userId, $message)); ``` -### 使用閉包工作 +### 使用閉包任務 ```php use function FriendsOfHyperf\AsyncQueueClosureJob\dispatch; -// 直接使用閉包,無需建立類別 +// 直接使用閉包,無需建立類 dispatch(function (NotificationService $notification) use ($userId, $message) { $notification->send($userId, $message); }); ``` -閉包工作的優勢: -- 程式碼更簡潔,無需建立額外的類別檔案 -- 更好的可讀性,工作邏輯就在分派的地方 +閉包任務的優勢: +- 程式碼更簡潔,無需建立額外的類檔案 +- 更好的可讀性,任務邏輯就在分發的地方 - 完整支援依賴注入 - 靈活的流式 API 配置 ## 相關元件 -- [hyperf/async-queue](https://hyperf.wiki/3.1/#/zh-cn/async-queue) - Hyperf 非同步佇列 -- [friendsofhyperf/closure-job](https://github.com/friendsofhyperf/components/tree/main/src/closure-job) - 通用閉包工作元件 +- [hyperf/async-queue](https://hyperf.wiki/3.1/#/zh-tw/async-queue) - Hyperf 非同步佇列 +- [friendsofhyperf/closure-job](https://github.com/friendsofhyperf/components/tree/main/src/closure-job) - 通用閉包任務元件 diff --git a/docs/zh-tw/guide/start/components.md b/docs/zh-tw/guide/start/components.md index 3ebe7709d..51cf60210 100644 --- a/docs/zh-tw/guide/start/components.md +++ b/docs/zh-tw/guide/start/components.md @@ -5,6 +5,7 @@ |Repository|Stable Version|Total Downloads|Monthly Downloads| |--|--|--|--| |[amqp-job](https://github.com/friendsofhyperf/amqp-job)|[![Latest Stable Version](https://poser.pugx.org/friendsofhyperf/amqp-job/v)](https://packagist.org/packages/friendsofhyperf/amqp-job)|[![Total Downloads](https://poser.pugx.org/friendsofhyperf/amqp-job/downloads)](https://packagist.org/packages/friendsofhyperf/amqp-job)|[![Monthly Downloads](https://poser.pugx.org/friendsofhyperf/amqp-job/d/monthly)](https://packagist.org/packages/friendsofhyperf/amqp-job)| +|[async-queue-closure-job](https://github.com/friendsofhyperf/async-queue-closure-job)|[![Latest Stable Version](https://poser.pugx.org/friendsofhyperf/async-queue-closure-job/v)](https://packagist.org/packages/friendsofhyperf/async-queue-closure-job)|[![Total Downloads](https://poser.pugx.org/friendsofhyperf/async-queue-closure-job/downloads)](https://packagist.org/packages/friendsofhyperf/async-queue-closure-job)|[![Monthly Downloads](https://poser.pugx.org/friendsofhyperf/async-queue-closure-job/d/monthly)](https://packagist.org/packages/friendsofhyperf/async-queue-closure-job)| |[cache](https://github.com/friendsofhyperf/cache)|[![Latest Stable Version](https://poser.pugx.org/friendsofhyperf/cache/v)](https://packagist.org/packages/friendsofhyperf/cache)|[![Total Downloads](https://poser.pugx.org/friendsofhyperf/cache/downloads)](https://packagist.org/packages/friendsofhyperf/cache)|[![Monthly Downloads](https://poser.pugx.org/friendsofhyperf/cache/d/monthly)](https://packagist.org/packages/friendsofhyperf/cache)| |[co-phpunit](https://github.com/friendsofhyperf/co-phpunit)|[![Latest Stable Version](https://poser.pugx.org/friendsofhyperf/co-phpunit/v)](https://packagist.org/packages/friendsofhyperf/co-phpunit)|[![Total Downloads](https://poser.pugx.org/friendsofhyperf/co-phpunit/downloads)](https://packagist.org/packages/friendsofhyperf/co-phpunit)|[![Monthly Downloads](https://poser.pugx.org/friendsofhyperf/co-phpunit/d/monthly)](https://packagist.org/packages/friendsofhyperf/co-phpunit)| |[command-benchmark](https://github.com/friendsofhyperf/command-benchmark)|[![Latest Stable Version](https://poser.pugx.org/friendsofhyperf/command-benchmark/v)](https://packagist.org/packages/friendsofhyperf/command-benchmark)|[![Total Downloads](https://poser.pugx.org/friendsofhyperf/command-benchmark/downloads)](https://packagist.org/packages/friendsofhyperf/command-benchmark)|[![Monthly Downloads](https://poser.pugx.org/friendsofhyperf/command-benchmark/d/monthly)](https://packagist.org/packages/friendsofhyperf/command-benchmark)| From 4fbe042ee9ee4e1664890c73bd7a0c612cb95496 Mon Sep 17 00:00:00 2001 From: Deeka Wong <8337659+huangdijia@users.noreply.github.com> Date: Fri, 14 Nov 2025 21:18:46 +0800 Subject: [PATCH 03/11] Remove onConnection method in PendingAsyncQueueDispatch The onConnection method was removed from PendingAsyncQueueDispatch in favor of using onPool directly. All test cases have been updated to replace onConnection calls with onPool to maintain consistency and avoid method duplication. --- src/support/src/Bus/PendingAsyncQueueDispatch.php | 5 ----- tests/AsyncQueueClosureJob/CoreFunctionalityTest.php | 12 ++++++------ .../DispatchFunctionSimpleTest.php | 8 ++++---- tests/AsyncQueueClosureJob/DispatchFunctionTest.php | 6 +++--- .../FluentDispatchIntegrationTest.php | 12 ++++++------ 5 files changed, 19 insertions(+), 24 deletions(-) diff --git a/src/support/src/Bus/PendingAsyncQueueDispatch.php b/src/support/src/Bus/PendingAsyncQueueDispatch.php index eb90a96f2..50aa8cf8e 100644 --- a/src/support/src/Bus/PendingAsyncQueueDispatch.php +++ b/src/support/src/Bus/PendingAsyncQueueDispatch.php @@ -48,11 +48,6 @@ public function onPool(string $pool): static return $this; } - public function onConnection(string $connection): static - { - return $this->onPool($connection); - } - public function delay(int $delay): static { $this->delay = $delay; diff --git a/tests/AsyncQueueClosureJob/CoreFunctionalityTest.php b/tests/AsyncQueueClosureJob/CoreFunctionalityTest.php index 4c29f2a16..1d6cc9ba9 100644 --- a/tests/AsyncQueueClosureJob/CoreFunctionalityTest.php +++ b/tests/AsyncQueueClosureJob/CoreFunctionalityTest.php @@ -103,7 +103,7 @@ public function testPendingAsyncQueueDispatchConfiguration() $dispatch = new PendingAsyncQueueDispatch($job); // Test configuration methods - $result = $dispatch->onConnection('test-connection') + $result = $dispatch->onPool('test-connection') ->delay(30) ->setMaxAttempts(7); @@ -151,7 +151,7 @@ public function testFluentMethodChaining() }; $dispatch = \FriendsOfHyperf\AsyncQueueClosureJob\dispatch($closure) - ->onConnection('chained-connection') + ->onPool('chained-connection') ->delay(60) ->setMaxAttempts(8); // Override initial value @@ -171,7 +171,7 @@ public function testConditionableTraitFunctionality() // Test when() with true condition $dispatch1 = \FriendsOfHyperf\AsyncQueueClosureJob\dispatch($closure) ->when(true, function ($dispatch) { - $dispatch->onConnection('when-true-connection'); + $dispatch->onPool('when-true-connection'); }); $this->assertEquals('when-true-connection', $this->getProperty($dispatch1, 'pool')); @@ -179,7 +179,7 @@ public function testConditionableTraitFunctionality() // Test when() with false condition $dispatch2 = \FriendsOfHyperf\AsyncQueueClosureJob\dispatch($closure) ->when(false, function ($dispatch) { - $dispatch->onConnection('when-false-connection'); + $dispatch->onPool('when-false-connection'); }); $this->assertEquals('default', $this->getProperty($dispatch2, 'pool')); @@ -187,7 +187,7 @@ public function testConditionableTraitFunctionality() // Test unless() with true condition $dispatch3 = \FriendsOfHyperf\AsyncQueueClosureJob\dispatch($closure) ->unless(true, function ($dispatch) { - $dispatch->onConnection('unless-true-connection'); + $dispatch->onPool('unless-true-connection'); }); $this->assertEquals('default', $this->getProperty($dispatch3, 'pool')); @@ -195,7 +195,7 @@ public function testConditionableTraitFunctionality() // Test unless() with false condition $dispatch4 = \FriendsOfHyperf\AsyncQueueClosureJob\dispatch($closure) ->unless(false, function ($dispatch) { - $dispatch->onConnection('unless-false-connection'); + $dispatch->onPool('unless-false-connection'); }); $this->assertEquals('unless-false-connection', $this->getProperty($dispatch4, 'pool')); diff --git a/tests/AsyncQueueClosureJob/DispatchFunctionSimpleTest.php b/tests/AsyncQueueClosureJob/DispatchFunctionSimpleTest.php index 1ddd9f013..0deb2adc8 100644 --- a/tests/AsyncQueueClosureJob/DispatchFunctionSimpleTest.php +++ b/tests/AsyncQueueClosureJob/DispatchFunctionSimpleTest.php @@ -113,7 +113,7 @@ public function testDispatchFunctionChainingWithMaxAttempts() }; $dispatch = \FriendsOfHyperf\AsyncQueueClosureJob\dispatch($closure) - ->onConnection('delayed-connection') + ->onPool('delayed-connection') ->delay(120) ->setMaxAttempts(5); // Override the initial maxAttempts @@ -137,7 +137,7 @@ public function testDispatchFunctionConditionableMethods() $dispatch = \FriendsOfHyperf\AsyncQueueClosureJob\dispatch($closure) ->when(true, function ($dispatch) { - $dispatch->onConnection('conditional-connection'); + $dispatch->onPool('conditional-connection'); }) ->unless(false, function ($dispatch) { $dispatch->delay(45); @@ -164,10 +164,10 @@ public function testDispatchFunctionWithMultipleConfigurations() // Test multiple method calls and overrides $dispatch = \FriendsOfHyperf\AsyncQueueClosureJob\dispatch($closure) - ->onConnection('initial-connection') + ->onPool('initial-connection') ->delay(60) ->setMaxAttempts(8) // Override maxAttempts - ->onConnection('multi-config-connection') // Override connection + ->onPool('multi-config-connection') // Override connection ->delay(300) // Override delay ->setMaxAttempts(10); // Final maxAttempts diff --git a/tests/AsyncQueueClosureJob/DispatchFunctionTest.php b/tests/AsyncQueueClosureJob/DispatchFunctionTest.php index 5f90fc6fe..176cd7eaf 100644 --- a/tests/AsyncQueueClosureJob/DispatchFunctionTest.php +++ b/tests/AsyncQueueClosureJob/DispatchFunctionTest.php @@ -133,7 +133,7 @@ public function testDispatchFunctionWithFluentConfiguration() }; $dispatch = \FriendsOfHyperf\AsyncQueueClosureJob\dispatch($closure) - ->onConnection('high-priority') + ->onPool('high-priority') ->delay(30) ->setMaxAttempts(3); @@ -177,7 +177,7 @@ public function testDispatchFunctionChainingWithMaxAttempts() }; $dispatch = \FriendsOfHyperf\AsyncQueueClosureJob\dispatch($closure) - ->onConnection('delayed-connection') + ->onPool('delayed-connection') ->delay(120) ->setMaxAttempts(5); // Override the initial maxAttempts @@ -254,7 +254,7 @@ public function testDispatchFunctionConditionableMethods() $dispatch = \FriendsOfHyperf\AsyncQueueClosureJob\dispatch($closure) ->when(true, function ($dispatch) { - $dispatch->onConnection('conditional-connection'); + $dispatch->onPool('conditional-connection'); }) ->unless(false, function ($dispatch) { $dispatch->delay(45); diff --git a/tests/AsyncQueueClosureJob/FluentDispatchIntegrationTest.php b/tests/AsyncQueueClosureJob/FluentDispatchIntegrationTest.php index ae66847c8..38d12f25a 100644 --- a/tests/AsyncQueueClosureJob/FluentDispatchIntegrationTest.php +++ b/tests/AsyncQueueClosureJob/FluentDispatchIntegrationTest.php @@ -90,7 +90,7 @@ public function testCompleteFluentDispatchWorkflow() // Use the fluent dispatch API $dispatch = \FriendsOfHyperf\AsyncQueueClosureJob\dispatch($closure) - ->onConnection('integration-connection') + ->onPool('integration-connection') ->delay(90) ->setMaxAttempts(3); @@ -187,7 +187,7 @@ public function testFluentDispatchWithDependencyInjection() // Dispatch with dependency injection $dispatch = \FriendsOfHyperf\AsyncQueueClosureJob\dispatch($closure) - ->onConnection('di-connection') + ->onPool('di-connection') ->delay(60) ->setMaxAttempts(1); @@ -227,7 +227,7 @@ public function testFluentDispatchWithConditionalLogic() $executed = true; }) ->when($condition, function ($dispatch) { - $dispatch->onConnection('high-priority'); + $dispatch->onPool('high-priority'); }) ->unless(! $condition, function ($dispatch) { $dispatch->delay(30); @@ -273,10 +273,10 @@ public function testFluentDispatchWithMultipleConfigurations() // Test multiple method calls and overrides $dispatch = \FriendsOfHyperf\AsyncQueueClosureJob\dispatch($closure) - ->onConnection('initial-connection') + ->onPool('initial-connection') ->delay(60) ->setMaxAttempts(8) // Override maxAttempts - ->onConnection('multi-config-connection') // Override queue + ->onPool('multi-config-connection') // Override queue ->delay(300) // Override delay ->setMaxAttempts(10); // Final maxAttempts @@ -315,7 +315,7 @@ public function testFluentDispatchErrorHandling() }; $dispatch = \FriendsOfHyperf\AsyncQueueClosureJob\dispatch($closure) - ->onConnection('error-connection') + ->onPool('error-connection') ->setMaxAttempts(1); unset($dispatch); // This should trigger the exception From 64283e5b88009467fee78af2cd2d46acaafe824b Mon Sep 17 00:00:00 2001 From: Deeka Wong <8337659+huangdijia@users.noreply.github.com> Date: Fri, 14 Nov 2025 21:19:22 +0800 Subject: [PATCH 04/11] Update docs to use onPool instead of onConnection Replaces all instances of the onConnection method with onPool in async queue closure job documentation for consistency with the latest API usage. --- docs/en/components/async-queue-closure-job.md | 146 +++++++++--------- 1 file changed, 73 insertions(+), 73 deletions(-) diff --git a/docs/en/components/async-queue-closure-job.md b/docs/en/components/async-queue-closure-job.md index 52bf9bb33..e1e7bdaee 100644 --- a/docs/en/components/async-queue-closure-job.md +++ b/docs/en/components/async-queue-closure-job.md @@ -2,9 +2,9 @@ ## Introduction -`friendsofhyperf/async-queue-closure-job` is an asynchronous queue closure job component for Hyperf. It allows you to execute closures as background tasks, with full support for dependency injection and fluent configuration, making the use of asynchronous tasks simpler and more elegant. +`friendsofhyperf/async-queue-closure-job` is an async queue closure job component for Hyperf. It allows you to execute closures as background jobs with full support for dependency injection and fluent configuration, making async tasks simpler and more elegant. -Unlike traditional methods that require creating task classes, this component enables you to define task logic directly using closures, eliminating the need for additional class files and resulting in cleaner code. +Unlike traditional job classes, this component lets you define job logic directly with closures, eliminating the need for extra class files and making your code more concise. ## Installation @@ -14,26 +14,26 @@ composer require friendsofhyperf/async-queue-closure-job ## Basic Usage -### Simple Closure Task +### Simple Closure Job ```php use function FriendsOfHyperf\AsyncQueueClosureJob\dispatch; -// Dispatch a simple closure task +// Dispatch a simple closure job dispatch(function () { - // Your task logic + // Your job logic here var_dump('Hello from closure job!'); }); ``` -### Setting Maximum Attempts +### Set Maximum Attempts ```php use function FriendsOfHyperf\AsyncQueueClosureJob\dispatch; // Set maximum attempts (retry limit) dispatch(function () { - // Your task logic + // Your job logic here // If it fails, it will retry up to 3 times })->setMaxAttempts(3); ``` @@ -42,59 +42,59 @@ dispatch(function () { ### Fluent API Configuration -You can flexibly configure various task options through method chaining: +You can flexibly configure various options using method chaining: ```php use function FriendsOfHyperf\AsyncQueueClosureJob\dispatch; // Chain multiple configuration options dispatch(function () { - // Your task logic + // Your job logic here }) - ->onConnection('high-priority') // Specify queue connection + ->onPool('high-priority') // Specify queue connection ->delay(60) // Delay execution by 60 seconds - ->setMaxAttempts(5); // Maximum of 5 retries + ->setMaxAttempts(5); // Retry up to 5 times ``` -### Specifying Queue Connection +### Specifying Queue Connections -When you have multiple queue connections, you can specify which connection the task should use: +When you have multiple queue connections, you can specify which connection to use: ```php use function FriendsOfHyperf\AsyncQueueClosureJob\dispatch; -// Use specified queue connection +// Use a specific queue connection dispatch(function () { - // High-priority task logic -})->onConnection('high-priority'); + // High priority task logic +})->onPool('high-priority'); -// Or use the onPool method (alias) +// Alternative pool name dispatch(function () { - // Low-priority task logic + // Low priority task logic })->onPool('low-priority'); ``` ### Delayed Execution -You can set tasks to execute after a certain period: +You can set a delay before the task starts executing: ```php use function FriendsOfHyperf\AsyncQueueClosureJob\dispatch; -// Execute after 60 seconds delay +// Delay execution by 60 seconds dispatch(function () { - // Your task logic + // Your job logic here })->delay(60); -// Execute after 5 minutes delay +// Delay execution by 5 minutes dispatch(function () { - // Your task logic + // Your job logic here })->delay(300); ``` ### Conditional Execution -Use the `when` and `unless` methods to dynamically configure tasks based on conditions: +Use `when` and `unless` methods to dynamically configure tasks based on conditions: ```php use function FriendsOfHyperf\AsyncQueueClosureJob\dispatch; @@ -103,26 +103,26 @@ $isUrgent = true; // Execute callback only when condition is true dispatch(function () { - // Your task logic + // Your job logic here }) ->when($isUrgent, function ($dispatch) { - $dispatch->onConnection('urgent'); + $dispatch->onPool('urgent'); }); // Execute callback only when condition is false dispatch(function () { - // Your task logic + // Your job logic here }) ->unless($isUrgent, function ($dispatch) { - $dispatch->delay(300); + $dispatch->delay(30); }); -// Combined usage +// Combine usage dispatch(function () { - // Your task logic + // Your job logic here }) ->when($isUrgent, function ($dispatch) { - $dispatch->onConnection('urgent'); + $dispatch->onPool('urgent'); }) ->unless($isUrgent, function ($dispatch) { $dispatch->delay(60); @@ -131,7 +131,7 @@ dispatch(function () { ### Dependency Injection -Closure tasks fully support Hyperf's dependency injection functionality. You can declare required dependencies in the closure parameters: +Closure jobs fully support Hyperf's dependency injection. You can declare required dependencies as closure parameters: ```php use function FriendsOfHyperf\AsyncQueueClosureJob\dispatch; @@ -142,9 +142,9 @@ use Psr\Log\LoggerInterface; dispatch(function (UserService $userService, LoggerInterface $logger) { $users = $userService->getActiveUsers(); $logger->info('Processing ' . count($users) . ' users'); - + foreach ($users as $user) { - // Process user... + // Process users... } }); ``` @@ -159,17 +159,17 @@ use function FriendsOfHyperf\AsyncQueueClosureJob\dispatch; $userId = 123; $action = 'update'; -// Using captured variables +// Use captured variables dispatch(function (UserService $userService) use ($userId, $action) { $user = $userService->find($userId); - + if ($action === 'update') { $userService->update($user); } })->setMaxAttempts(3); ``` -## Practical Application Scenarios +## Real-World Use Cases ### Sending Notifications @@ -181,7 +181,7 @@ dispatch(function (NotificationService $notification) use ($userId, $message) { })->setMaxAttempts(3); ``` -### Processing File Uploads +### File Upload Processing ```php use function FriendsOfHyperf\AsyncQueueClosureJob\dispatch; @@ -200,7 +200,7 @@ use function FriendsOfHyperf\AsyncQueueClosureJob\dispatch; dispatch(function (StatisticsService $stats) use ($date) { $stats->calculateDailyReport($date); $stats->sendReport($date); -})->onConnection('statistics'); +})->onPool('statistics'); ``` ### Batch Operations @@ -221,10 +221,10 @@ foreach ($userIds as $userId) { ### `dispatch(Closure $closure): PendingAsyncQueueDispatch` -The main dispatch function used to create closure tasks. +The main dispatch function that creates a closure job. **Parameters:** -- `$closure` - The closure to be executed +- `$closure` - The closure to execute **Returns:** - `PendingAsyncQueueDispatch` - Pending closure dispatch object @@ -239,85 +239,85 @@ Set the queue connection name. - `$connection` - Queue connection name **Returns:** -- `static` - Current object, supports method chaining +- `static` - Current object for method chaining #### `onPool(string $pool): static` -Set the queue connection name (alias of `onConnection`). +Set the queue connection name (alias for `onConnection`). **Parameters:** - `$pool` - Queue connection name **Returns:** -- `static` - Current object, supports method chaining +- `static` - Current object for method chaining #### `delay(int $delay): static` -Set the delay execution time. +Set the delay time before execution. **Parameters:** - `$delay` - Delay time in seconds **Returns:** -- `static` - Current object, supports method chaining +- `static` - Current object for method chaining #### `setMaxAttempts(int $maxAttempts): static` -Set the maximum number of retry attempts. +Set the maximum retry attempts. **Parameters:** -- `$maxAttempts` - Maximum number of attempts +- `$maxAttempts` - Maximum attempts **Returns:** -- `static` - Current object, supports method chaining +- `static` - Current object for method chaining #### `when($condition, $callback): static` Execute callback when condition is true. **Parameters:** -- `$condition` - Conditional expression +- `$condition` - Condition expression - `$callback` - Callback function that receives the current object as parameter **Returns:** -- `static` - Current object, supports method chaining +- `static` - Current object for method chaining #### `unless($condition, $callback): static` Execute callback when condition is false. **Parameters:** -- `$condition` - Conditional expression +- `$condition` - Condition expression - `$callback` - Callback function that receives the current object as parameter **Returns:** -- `static` - Current object, supports method chaining +- `static` - Current object for method chaining ## Supported Closure Types -This component supports the following types of closures: +This component supports the following closure types: - ✅ Simple closures without parameters - ✅ Closures with dependency injection -- ✅ Closures using captured variables (`use`) +- ✅ Closures with captured variables (`use`) - ✅ Closures with nullable parameters -- ✅ Closures mixing dependency injection and captured variables +- ✅ Mixing dependency injection and captured variables ## Notes -1. **Serialization Limitations**: Closures are serialized for storage, therefore: - - Cannot capture unserializable resources (such as database connections, file handles, etc.) +1. **Serialization Limitations**: Closures are serialized before storage, therefore: + - Cannot capture non-serializable resources (e.g., database connections, file handles) - Captured objects should be serializable -2. **Dependency Injection**: Dependencies in closures are resolved from the container when the task executes and are not serialized +2. **Dependency Injection**: Dependencies in closures will be resolved from the container when the job executes, not serialized -3. **Asynchronous Execution**: Tasks are executed asynchronously; the dispatch function returns immediately without waiting for task completion +3. **Async Execution**: Tasks execute asynchronously. The dispatch function returns immediately without waiting for task completion -4. **Error Handling**: Failed task executions will be retried according to the number of attempts set by `setMaxAttempts` +4. **Error Handling**: Failed tasks will retry according to the `setMaxAttempts` configuration ## Configuration -This component uses Hyperf's asynchronous queue configuration. You can configure queue parameters in `config/autoload/async_queue.php`: +This component uses Hyperf's async queue configuration. You can configure queue parameters in `config/autoload/async_queue.php`: ```php push(new SendNotificationJob($userId, $message)); ``` -### Using Closure Tasks +### Using Closure Jobs ```php use function FriendsOfHyperf\AsyncQueueClosureJob\dispatch; -// Use closure directly, no need to create class +// Directly use closure, no need to create a class dispatch(function (NotificationService $notification) use ($userId, $message) { $notification->send($userId, $message); }); ``` -Advantages of closure tasks: -- Cleaner code, no need for additional class files -- Better readability with task logic located at dispatch point -- Full support for dependency injection +Advantages of closure jobs: +- Cleaner code, no need to create extra class files +- Better readability, job logic is right where it's dispatched +- Full dependency injection support - Flexible fluent API configuration ## Related Components -- [hyperf/async-queue](https://hyperf.wiki/3.1/#/en/async-queue) - Hyperf Async Queue -- [friendsofhyperf/closure-job](https://github.com/friendsofhyperf/components/tree/main/src/closure-job) - General Closure Job Component \ No newline at end of file +- [hyperf/async-queue](https://hyperf.wiki/3.1/#/zh-cn/async-queue) - Hyperf Async Queue +- [friendsofhyperf/closure-job](https://github.com/friendsofhyperf/components/tree/main/src/closure-job) - Generic Closure Job Component From 718a2f7cc000f3708e97bb0ace133af8dbf68887 Mon Sep 17 00:00:00 2001 From: Deeka Wong <8337659+huangdijia@users.noreply.github.com> Date: Fri, 14 Nov 2025 21:20:26 +0800 Subject: [PATCH 05/11] Update async queue closure job docs for method naming Replaces references to `onConnection` with `onPool` in the Chinese documentation for consistency with the API. Adds formatting improvements to the English documentation for better readability. --- docs/en/components/async-queue-closure-job.md | 15 +++++++++++++++ docs/zh-cn/components/async-queue-closure-job.md | 14 +++++++------- 2 files changed, 22 insertions(+), 7 deletions(-) diff --git a/docs/en/components/async-queue-closure-job.md b/docs/en/components/async-queue-closure-job.md index e1e7bdaee..f261b2ecb 100644 --- a/docs/en/components/async-queue-closure-job.md +++ b/docs/en/components/async-queue-closure-job.md @@ -224,9 +224,11 @@ foreach ($userIds as $userId) { The main dispatch function that creates a closure job. **Parameters:** + - `$closure` - The closure to execute **Returns:** + - `PendingAsyncQueueDispatch` - Pending closure dispatch object ### `PendingAsyncQueueDispatch` Methods @@ -236,9 +238,11 @@ The main dispatch function that creates a closure job. Set the queue connection name. **Parameters:** + - `$connection` - Queue connection name **Returns:** + - `static` - Current object for method chaining #### `onPool(string $pool): static` @@ -246,9 +250,11 @@ Set the queue connection name. Set the queue connection name (alias for `onConnection`). **Parameters:** + - `$pool` - Queue connection name **Returns:** + - `static` - Current object for method chaining #### `delay(int $delay): static` @@ -256,9 +262,11 @@ Set the queue connection name (alias for `onConnection`). Set the delay time before execution. **Parameters:** + - `$delay` - Delay time in seconds **Returns:** + - `static` - Current object for method chaining #### `setMaxAttempts(int $maxAttempts): static` @@ -266,9 +274,11 @@ Set the delay time before execution. Set the maximum retry attempts. **Parameters:** + - `$maxAttempts` - Maximum attempts **Returns:** + - `static` - Current object for method chaining #### `when($condition, $callback): static` @@ -276,10 +286,12 @@ Set the maximum retry attempts. Execute callback when condition is true. **Parameters:** + - `$condition` - Condition expression - `$callback` - Callback function that receives the current object as parameter **Returns:** + - `static` - Current object for method chaining #### `unless($condition, $callback): static` @@ -287,10 +299,12 @@ Execute callback when condition is true. Execute callback when condition is false. **Parameters:** + - `$condition` - Condition expression - `$callback` - Callback function that receives the current object as parameter **Returns:** + - `static` - Current object for method chaining ## Supported Closure Types @@ -375,6 +389,7 @@ dispatch(function (NotificationService $notification) use ($userId, $message) { ``` Advantages of closure jobs: + - Cleaner code, no need to create extra class files - Better readability, job logic is right where it's dispatched - Full dependency injection support diff --git a/docs/zh-cn/components/async-queue-closure-job.md b/docs/zh-cn/components/async-queue-closure-job.md index f2c269206..a5471f970 100644 --- a/docs/zh-cn/components/async-queue-closure-job.md +++ b/docs/zh-cn/components/async-queue-closure-job.md @@ -51,7 +51,7 @@ use function FriendsOfHyperf\AsyncQueueClosureJob\dispatch; dispatch(function () { // 你的任务逻辑 }) - ->onConnection('high-priority') // 指定队列连接 + ->onPool('high-priority') // 指定队列连接 ->delay(60) // 延迟 60 秒执行 ->setMaxAttempts(5); // 最多重试 5 次 ``` @@ -66,7 +66,7 @@ use function FriendsOfHyperf\AsyncQueueClosureJob\dispatch; // 使用指定的队列连接 dispatch(function () { // 高优先级任务逻辑 -})->onConnection('high-priority'); +})->onPool('high-priority'); // 或者使用 onPool 方法(别名) dispatch(function () { @@ -106,7 +106,7 @@ dispatch(function () { // 你的任务逻辑 }) ->when($isUrgent, function ($dispatch) { - $dispatch->onConnection('urgent'); + $dispatch->onPool('urgent'); }); // 仅当条件为 false 时执行回调 @@ -122,7 +122,7 @@ dispatch(function () { // 你的任务逻辑 }) ->when($isUrgent, function ($dispatch) { - $dispatch->onConnection('urgent'); + $dispatch->onPool('urgent'); }) ->unless($isUrgent, function ($dispatch) { $dispatch->delay(60); @@ -200,7 +200,7 @@ use function FriendsOfHyperf\AsyncQueueClosureJob\dispatch; dispatch(function (StatisticsService $stats) use ($date) { $stats->calculateDailyReport($date); $stats->sendReport($date); -})->onConnection('statistics'); +})->onPool('statistics'); ``` ### 批量操作 @@ -231,7 +231,7 @@ foreach ($userIds as $userId) { ### `PendingAsyncQueueDispatch` 方法 -#### `onConnection(string $connection): static` +#### `onPool(string $connection): static` 设置队列连接名称。 @@ -243,7 +243,7 @@ foreach ($userIds as $userId) { #### `onPool(string $pool): static` -设置队列连接名称(`onConnection` 的别名)。 +设置队列连接名称(`onPool` 的别名)。 **参数:** - `$pool` - 队列连接名称 From 3400290d0721edeedf6225a69e76f95aff1d6079 Mon Sep 17 00:00:00 2001 From: Deeka Wong <8337659+huangdijia@users.noreply.github.com> Date: Fri, 14 Nov 2025 21:20:53 +0800 Subject: [PATCH 06/11] Replace onConnection with onPool in async queue docs Updated documentation to use the onPool method instead of onConnection for specifying queue connections, reflecting API changes and improving consistency in examples and method descriptions. --- docs/zh-hk/components/async-queue-closure-job.md | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/docs/zh-hk/components/async-queue-closure-job.md b/docs/zh-hk/components/async-queue-closure-job.md index 7303bc539..4da567735 100644 --- a/docs/zh-hk/components/async-queue-closure-job.md +++ b/docs/zh-hk/components/async-queue-closure-job.md @@ -51,7 +51,7 @@ use function FriendsOfHyperf\AsyncQueueClosureJob\dispatch; dispatch(function () { // 你的任務邏輯 }) - ->onConnection('high-priority') // 指定隊列連接 + ->onPool('high-priority') // 指定隊列連接 ->delay(60) // 延遲 60 秒執行 ->setMaxAttempts(5); // 最多重試 5 次 ``` @@ -66,7 +66,7 @@ use function FriendsOfHyperf\AsyncQueueClosureJob\dispatch; // 使用指定的隊列連接 dispatch(function () { // 高優先級任務邏輯 -})->onConnection('high-priority'); +})->onPool('high-priority'); // 或者使用 onPool 方法(別名) dispatch(function () { @@ -106,7 +106,7 @@ dispatch(function () { // 你的任務邏輯 }) ->when($isUrgent, function ($dispatch) { - $dispatch->onConnection('urgent'); + $dispatch->onPool('urgent'); }); // 僅當條件為 false 時執行回調 @@ -122,7 +122,7 @@ dispatch(function () { // 你的任務邏輯 }) ->when($isUrgent, function ($dispatch) { - $dispatch->onConnection('urgent'); + $dispatch->onPool('urgent'); }) ->unless($isUrgent, function ($dispatch) { $dispatch->delay(60); @@ -200,7 +200,7 @@ use function FriendsOfHyperf\AsyncQueueClosureJob\dispatch; dispatch(function (StatisticsService $stats) use ($date) { $stats->calculateDailyReport($date); $stats->sendReport($date); -})->onConnection('statistics'); +})->onPool('statistics'); ``` ### 批量操作 @@ -231,7 +231,7 @@ foreach ($userIds as $userId) { ### `PendingAsyncQueueDispatch` 方法 -#### `onConnection(string $connection): static` +#### `onPool(string $connection): static` 設置隊列連接名稱。 @@ -243,7 +243,7 @@ foreach ($userIds as $userId) { #### `onPool(string $pool): static` -設置隊列連接名稱(`onConnection` 的別名)。 +設置隊列連接名稱(`onPool` 的別名)。 **參數:** - `$pool` - 隊列連接名稱 From 63b41762f8d9592af610128da9c9341bf1baa469 Mon Sep 17 00:00:00 2001 From: huangdijia <8337659+huangdijia@users.noreply.github.com> Date: Fri, 14 Nov 2025 13:23:13 +0000 Subject: [PATCH 07/11] Update docs and translate --- docs/en/components/async-queue-closure-job.md | 145 ++++++++---------- .../components/async-queue-closure-job.md | 14 +- 2 files changed, 72 insertions(+), 87 deletions(-) diff --git a/docs/en/components/async-queue-closure-job.md b/docs/en/components/async-queue-closure-job.md index f261b2ecb..0996c93ee 100644 --- a/docs/en/components/async-queue-closure-job.md +++ b/docs/en/components/async-queue-closure-job.md @@ -2,9 +2,9 @@ ## Introduction -`friendsofhyperf/async-queue-closure-job` is an async queue closure job component for Hyperf. It allows you to execute closures as background jobs with full support for dependency injection and fluent configuration, making async tasks simpler and more elegant. +`friendsofhyperf/async-queue-closure-job` is an asynchronous queue closure job component for Hyperf. It allows you to execute closures as background tasks, with full support for dependency injection and fluent configuration, making the use of asynchronous tasks simpler and more elegant. -Unlike traditional job classes, this component lets you define job logic directly with closures, eliminating the need for extra class files and making your code more concise. +Unlike the traditional approach of creating task classes, this component enables you to define task logic directly using closures, eliminating the need for additional class files and making the code more concise. ## Installation @@ -14,26 +14,26 @@ composer require friendsofhyperf/async-queue-closure-job ## Basic Usage -### Simple Closure Job +### Simple Closure Task ```php use function FriendsOfHyperf\AsyncQueueClosureJob\dispatch; -// Dispatch a simple closure job +// Dispatch a simple closure task dispatch(function () { - // Your job logic here + // Your task logic var_dump('Hello from closure job!'); }); ``` -### Set Maximum Attempts +### Setting Maximum Attempts ```php use function FriendsOfHyperf\AsyncQueueClosureJob\dispatch; // Set maximum attempts (retry limit) dispatch(function () { - // Your job logic here + // Your task logic // If it fails, it will retry up to 3 times })->setMaxAttempts(3); ``` @@ -42,59 +42,59 @@ dispatch(function () { ### Fluent API Configuration -You can flexibly configure various options using method chaining: +You can flexibly configure various task options through method chaining: ```php use function FriendsOfHyperf\AsyncQueueClosureJob\dispatch; // Chain multiple configuration options dispatch(function () { - // Your job logic here + // Your task logic }) ->onPool('high-priority') // Specify queue connection ->delay(60) // Delay execution by 60 seconds - ->setMaxAttempts(5); // Retry up to 5 times + ->setMaxAttempts(5); // Maximum of 5 retries ``` -### Specifying Queue Connections +### Specifying Queue Connection -When you have multiple queue connections, you can specify which connection to use: +When you have multiple queue connections, you can specify which connection the task uses: ```php use function FriendsOfHyperf\AsyncQueueClosureJob\dispatch; -// Use a specific queue connection +// Use specified queue connection dispatch(function () { - // High priority task logic + // High-priority task logic })->onPool('high-priority'); -// Alternative pool name +// Or use the onPool method (alias) dispatch(function () { - // Low priority task logic + // Low-priority task logic })->onPool('low-priority'); ``` ### Delayed Execution -You can set a delay before the task starts executing: +You can set tasks to execute after a certain period: ```php use function FriendsOfHyperf\AsyncQueueClosureJob\dispatch; -// Delay execution by 60 seconds +// Execute after 60 seconds delay dispatch(function () { - // Your job logic here + // Your task logic })->delay(60); -// Delay execution by 5 minutes +// Execute after 5 minutes delay dispatch(function () { - // Your job logic here + // Your task logic })->delay(300); ``` ### Conditional Execution -Use `when` and `unless` methods to dynamically configure tasks based on conditions: +Use the `when` and `unless` methods to dynamically configure tasks based on conditions: ```php use function FriendsOfHyperf\AsyncQueueClosureJob\dispatch; @@ -103,7 +103,7 @@ $isUrgent = true; // Execute callback only when condition is true dispatch(function () { - // Your job logic here + // Your task logic }) ->when($isUrgent, function ($dispatch) { $dispatch->onPool('urgent'); @@ -111,15 +111,15 @@ dispatch(function () { // Execute callback only when condition is false dispatch(function () { - // Your job logic here + // Your task logic }) ->unless($isUrgent, function ($dispatch) { - $dispatch->delay(30); + $dispatch->delay(300); }); -// Combine usage +// Combined usage dispatch(function () { - // Your job logic here + // Your task logic }) ->when($isUrgent, function ($dispatch) { $dispatch->onPool('urgent'); @@ -131,7 +131,7 @@ dispatch(function () { ### Dependency Injection -Closure jobs fully support Hyperf's dependency injection. You can declare required dependencies as closure parameters: +Closure tasks fully support Hyperf's dependency injection functionality. You can declare required dependencies in the closure parameters: ```php use function FriendsOfHyperf\AsyncQueueClosureJob\dispatch; @@ -142,9 +142,9 @@ use Psr\Log\LoggerInterface; dispatch(function (UserService $userService, LoggerInterface $logger) { $users = $userService->getActiveUsers(); $logger->info('Processing ' . count($users) . ' users'); - + foreach ($users as $user) { - // Process users... + // Process user... } }); ``` @@ -162,14 +162,14 @@ $action = 'update'; // Use captured variables dispatch(function (UserService $userService) use ($userId, $action) { $user = $userService->find($userId); - + if ($action === 'update') { $userService->update($user); } })->setMaxAttempts(3); ``` -## Real-World Use Cases +## Practical Application Scenarios ### Sending Notifications @@ -181,7 +181,7 @@ dispatch(function (NotificationService $notification) use ($userId, $message) { })->setMaxAttempts(3); ``` -### File Upload Processing +### Processing File Uploads ```php use function FriendsOfHyperf\AsyncQueueClosureJob\dispatch; @@ -221,117 +221,103 @@ foreach ($userIds as $userId) { ### `dispatch(Closure $closure): PendingAsyncQueueDispatch` -The main dispatch function that creates a closure job. +The main dispatch function used to create closure tasks. **Parameters:** - - `$closure` - The closure to execute **Returns:** - - `PendingAsyncQueueDispatch` - Pending closure dispatch object ### `PendingAsyncQueueDispatch` Methods -#### `onConnection(string $connection): static` +#### `onPool(string $connection): static` Set the queue connection name. **Parameters:** - - `$connection` - Queue connection name **Returns:** - -- `static` - Current object for method chaining +- `static` - Current object, supports method chaining #### `onPool(string $pool): static` -Set the queue connection name (alias for `onConnection`). +Set the queue connection name (alias of `onPool`). **Parameters:** - - `$pool` - Queue connection name **Returns:** - -- `static` - Current object for method chaining +- `static` - Current object, supports method chaining #### `delay(int $delay): static` -Set the delay time before execution. +Set the delay execution time. **Parameters:** - - `$delay` - Delay time in seconds **Returns:** - -- `static` - Current object for method chaining +- `static` - Current object, supports method chaining #### `setMaxAttempts(int $maxAttempts): static` -Set the maximum retry attempts. +Set the maximum number of retry attempts. **Parameters:** - -- `$maxAttempts` - Maximum attempts +- `$maxAttempts` - Maximum number of attempts **Returns:** - -- `static` - Current object for method chaining +- `static` - Current object, supports method chaining #### `when($condition, $callback): static` Execute callback when condition is true. **Parameters:** - - `$condition` - Condition expression - `$callback` - Callback function that receives the current object as parameter **Returns:** - -- `static` - Current object for method chaining +- `static` - Current object, supports method chaining #### `unless($condition, $callback): static` Execute callback when condition is false. **Parameters:** - - `$condition` - Condition expression - `$callback` - Callback function that receives the current object as parameter **Returns:** - -- `static` - Current object for method chaining +- `static` - Current object, supports method chaining ## Supported Closure Types -This component supports the following closure types: +This component supports the following types of closures: - ✅ Simple closures without parameters - ✅ Closures with dependency injection -- ✅ Closures with captured variables (`use`) +- ✅ Closures using captured variables (`use`) - ✅ Closures with nullable parameters -- ✅ Mixing dependency injection and captured variables +- ✅ Closures mixing dependency injection and captured variables ## Notes -1. **Serialization Limitations**: Closures are serialized before storage, therefore: - - Cannot capture non-serializable resources (e.g., database connections, file handles) +1. **Serialization Limitations**: Closures are serialized for storage, therefore: + - Cannot capture unserializable resources (such as database connections, file handles, etc.) - Captured objects should be serializable -2. **Dependency Injection**: Dependencies in closures will be resolved from the container when the job executes, not serialized +2. **Dependency Injection**: Dependencies in closures are resolved from the container when the task executes and are not serialized -3. **Async Execution**: Tasks execute asynchronously. The dispatch function returns immediately without waiting for task completion +3. **Asynchronous Execution**: Tasks are executed asynchronously; the dispatch function returns immediately without waiting for task completion -4. **Error Handling**: Failed tasks will retry according to the `setMaxAttempts` configuration +4. **Error Handling**: Failed task executions will retry according to the number of attempts set by `setMaxAttempts` ## Configuration -This component uses Hyperf's async queue configuration. You can configure queue parameters in `config/autoload/async_queue.php`: +This component uses Hyperf's asynchronous queue configuration. You can configure queue parameters in `config/autoload/async_queue.php`: ```php push(new SendNotificationJob($userId, $message)); ``` -### Using Closure Jobs +### Using Closure Tasks ```php use function FriendsOfHyperf\AsyncQueueClosureJob\dispatch; -// Directly use closure, no need to create a class +// Use closure directly, no need to create class dispatch(function (NotificationService $notification) use ($userId, $message) { $notification->send($userId, $message); }); ``` -Advantages of closure jobs: - -- Cleaner code, no need to create extra class files -- Better readability, job logic is right where it's dispatched -- Full dependency injection support +Advantages of closure tasks: +- More concise code, no need for additional class files +- Better readability, task logic is located where it's dispatched +- Full support for dependency injection - Flexible fluent API configuration ## Related Components -- [hyperf/async-queue](https://hyperf.wiki/3.1/#/zh-cn/async-queue) - Hyperf Async Queue -- [friendsofhyperf/closure-job](https://github.com/friendsofhyperf/components/tree/main/src/closure-job) - Generic Closure Job Component +- [hyperf/async-queue](https://hyperf.wiki/3.1/#/en/async-queue) - Hyperf Async Queue +- [friendsofhyperf/closure-job](https://github.com/friendsofhyperf/components/tree/main/src/closure-job) - General Closure Job Component \ No newline at end of file diff --git a/docs/zh-tw/components/async-queue-closure-job.md b/docs/zh-tw/components/async-queue-closure-job.md index e4827ebdc..e3471ec4f 100644 --- a/docs/zh-tw/components/async-queue-closure-job.md +++ b/docs/zh-tw/components/async-queue-closure-job.md @@ -51,7 +51,7 @@ use function FriendsOfHyperf\AsyncQueueClosureJob\dispatch; dispatch(function () { // 你的任務邏輯 }) - ->onConnection('high-priority') // 指定佇列連線 + ->onPool('high-priority') // 指定佇列連線 ->delay(60) // 延遲 60 秒執行 ->setMaxAttempts(5); // 最多重試 5 次 ``` @@ -66,7 +66,7 @@ use function FriendsOfHyperf\AsyncQueueClosureJob\dispatch; // 使用指定的佇列連線 dispatch(function () { // 高優先順序任務邏輯 -})->onConnection('high-priority'); +})->onPool('high-priority'); // 或者使用 onPool 方法(別名) dispatch(function () { @@ -106,7 +106,7 @@ dispatch(function () { // 你的任務邏輯 }) ->when($isUrgent, function ($dispatch) { - $dispatch->onConnection('urgent'); + $dispatch->onPool('urgent'); }); // 僅當條件為 false 時執行回撥 @@ -122,7 +122,7 @@ dispatch(function () { // 你的任務邏輯 }) ->when($isUrgent, function ($dispatch) { - $dispatch->onConnection('urgent'); + $dispatch->onPool('urgent'); }) ->unless($isUrgent, function ($dispatch) { $dispatch->delay(60); @@ -200,7 +200,7 @@ use function FriendsOfHyperf\AsyncQueueClosureJob\dispatch; dispatch(function (StatisticsService $stats) use ($date) { $stats->calculateDailyReport($date); $stats->sendReport($date); -})->onConnection('statistics'); +})->onPool('statistics'); ``` ### 批次操作 @@ -231,7 +231,7 @@ foreach ($userIds as $userId) { ### `PendingAsyncQueueDispatch` 方法 -#### `onConnection(string $connection): static` +#### `onPool(string $connection): static` 設定佇列連線名稱。 @@ -243,7 +243,7 @@ foreach ($userIds as $userId) { #### `onPool(string $pool): static` -設定佇列連線名稱(`onConnection` 的別名)。 +設定佇列連線名稱(`onPool` 的別名)。 **引數:** - `$pool` - 佇列連線名稱 From b256c29c27b205f2a142fe699c7e3c1e160fa54f Mon Sep 17 00:00:00 2001 From: Deeka Wong <8337659+huangdijia@users.noreply.github.com> Date: Fri, 14 Nov 2025 21:25:56 +0800 Subject: [PATCH 08/11] Update async queue job docs to use onPool method Replaces references and documentation for the onConnection method with onPool in all language versions. Clarifies that onPool sets the queue connection name and removes duplicate/alias documentation for consistency. --- docs/en/components/async-queue-closure-job.md | 147 +++++++++--------- .../components/async-queue-closure-job.md | 12 +- .../components/async-queue-closure-job.md | 12 +- .../components/async-queue-closure-job.md | 12 +- 4 files changed, 78 insertions(+), 105 deletions(-) diff --git a/docs/en/components/async-queue-closure-job.md b/docs/en/components/async-queue-closure-job.md index 0996c93ee..e83d74372 100644 --- a/docs/en/components/async-queue-closure-job.md +++ b/docs/en/components/async-queue-closure-job.md @@ -2,9 +2,9 @@ ## Introduction -`friendsofhyperf/async-queue-closure-job` is an asynchronous queue closure job component for Hyperf. It allows you to execute closures as background tasks, with full support for dependency injection and fluent configuration, making the use of asynchronous tasks simpler and more elegant. +`friendsofhyperf/async-queue-closure-job` is an async queue closure job component for Hyperf. It allows you to execute closures as background jobs with full support for dependency injection and fluent configuration, making async tasks simpler and more elegant. -Unlike the traditional approach of creating task classes, this component enables you to define task logic directly using closures, eliminating the need for additional class files and making the code more concise. +Unlike traditional job classes, this component lets you define job logic directly with closures, eliminating the need for extra class files and making your code more concise. ## Installation @@ -14,26 +14,26 @@ composer require friendsofhyperf/async-queue-closure-job ## Basic Usage -### Simple Closure Task +### Simple Closure Job ```php use function FriendsOfHyperf\AsyncQueueClosureJob\dispatch; -// Dispatch a simple closure task +// Dispatch a simple closure job dispatch(function () { - // Your task logic + // Your job logic here var_dump('Hello from closure job!'); }); ``` -### Setting Maximum Attempts +### Set Maximum Attempts ```php use function FriendsOfHyperf\AsyncQueueClosureJob\dispatch; // Set maximum attempts (retry limit) dispatch(function () { - // Your task logic + // Your job logic here // If it fails, it will retry up to 3 times })->setMaxAttempts(3); ``` @@ -42,59 +42,59 @@ dispatch(function () { ### Fluent API Configuration -You can flexibly configure various task options through method chaining: +You can flexibly configure various options using method chaining: ```php use function FriendsOfHyperf\AsyncQueueClosureJob\dispatch; // Chain multiple configuration options dispatch(function () { - // Your task logic + // Your job logic here }) ->onPool('high-priority') // Specify queue connection ->delay(60) // Delay execution by 60 seconds - ->setMaxAttempts(5); // Maximum of 5 retries + ->setMaxAttempts(5); // Retry up to 5 times ``` -### Specifying Queue Connection +### Specifying Queue Connections -When you have multiple queue connections, you can specify which connection the task uses: +When you have multiple queue connections, you can specify which connection to use: ```php use function FriendsOfHyperf\AsyncQueueClosureJob\dispatch; -// Use specified queue connection +// Use a specific queue connection dispatch(function () { - // High-priority task logic + // High priority task logic })->onPool('high-priority'); -// Or use the onPool method (alias) +// Alternative pool name dispatch(function () { - // Low-priority task logic + // Low priority task logic })->onPool('low-priority'); ``` ### Delayed Execution -You can set tasks to execute after a certain period: +You can set a delay before the task starts executing: ```php use function FriendsOfHyperf\AsyncQueueClosureJob\dispatch; -// Execute after 60 seconds delay +// Delay execution by 60 seconds dispatch(function () { - // Your task logic + // Your job logic here })->delay(60); -// Execute after 5 minutes delay +// Delay execution by 5 minutes dispatch(function () { - // Your task logic + // Your job logic here })->delay(300); ``` ### Conditional Execution -Use the `when` and `unless` methods to dynamically configure tasks based on conditions: +Use `when` and `unless` methods to dynamically configure tasks based on conditions: ```php use function FriendsOfHyperf\AsyncQueueClosureJob\dispatch; @@ -103,7 +103,7 @@ $isUrgent = true; // Execute callback only when condition is true dispatch(function () { - // Your task logic + // Your job logic here }) ->when($isUrgent, function ($dispatch) { $dispatch->onPool('urgent'); @@ -111,15 +111,15 @@ dispatch(function () { // Execute callback only when condition is false dispatch(function () { - // Your task logic + // Your job logic here }) ->unless($isUrgent, function ($dispatch) { - $dispatch->delay(300); + $dispatch->delay(30); }); -// Combined usage +// Combine usage dispatch(function () { - // Your task logic + // Your job logic here }) ->when($isUrgent, function ($dispatch) { $dispatch->onPool('urgent'); @@ -131,7 +131,7 @@ dispatch(function () { ### Dependency Injection -Closure tasks fully support Hyperf's dependency injection functionality. You can declare required dependencies in the closure parameters: +Closure jobs fully support Hyperf's dependency injection. You can declare required dependencies as closure parameters: ```php use function FriendsOfHyperf\AsyncQueueClosureJob\dispatch; @@ -142,9 +142,9 @@ use Psr\Log\LoggerInterface; dispatch(function (UserService $userService, LoggerInterface $logger) { $users = $userService->getActiveUsers(); $logger->info('Processing ' . count($users) . ' users'); - + foreach ($users as $user) { - // Process user... + // Process users... } }); ``` @@ -162,14 +162,14 @@ $action = 'update'; // Use captured variables dispatch(function (UserService $userService) use ($userId, $action) { $user = $userService->find($userId); - + if ($action === 'update') { $userService->update($user); } })->setMaxAttempts(3); ``` -## Practical Application Scenarios +## Real-World Use Cases ### Sending Notifications @@ -181,7 +181,7 @@ dispatch(function (NotificationService $notification) use ($userId, $message) { })->setMaxAttempts(3); ``` -### Processing File Uploads +### File Upload Processing ```php use function FriendsOfHyperf\AsyncQueueClosureJob\dispatch; @@ -221,103 +221,105 @@ foreach ($userIds as $userId) { ### `dispatch(Closure $closure): PendingAsyncQueueDispatch` -The main dispatch function used to create closure tasks. +The main dispatch function that creates a closure job. **Parameters:** + - `$closure` - The closure to execute **Returns:** + - `PendingAsyncQueueDispatch` - Pending closure dispatch object ### `PendingAsyncQueueDispatch` Methods -#### `onPool(string $connection): static` +#### `onPool(string $pool): static` Set the queue connection name. **Parameters:** -- `$connection` - Queue connection name -**Returns:** -- `static` - Current object, supports method chaining - -#### `onPool(string $pool): static` - -Set the queue connection name (alias of `onPool`). - -**Parameters:** - `$pool` - Queue connection name **Returns:** -- `static` - Current object, supports method chaining + +- `static` - Current object for method chaining #### `delay(int $delay): static` -Set the delay execution time. +Set the delay time before execution. **Parameters:** + - `$delay` - Delay time in seconds **Returns:** -- `static` - Current object, supports method chaining + +- `static` - Current object for method chaining #### `setMaxAttempts(int $maxAttempts): static` -Set the maximum number of retry attempts. +Set the maximum retry attempts. **Parameters:** -- `$maxAttempts` - Maximum number of attempts + +- `$maxAttempts` - Maximum attempts **Returns:** -- `static` - Current object, supports method chaining + +- `static` - Current object for method chaining #### `when($condition, $callback): static` Execute callback when condition is true. **Parameters:** + - `$condition` - Condition expression - `$callback` - Callback function that receives the current object as parameter **Returns:** -- `static` - Current object, supports method chaining + +- `static` - Current object for method chaining #### `unless($condition, $callback): static` Execute callback when condition is false. **Parameters:** + - `$condition` - Condition expression - `$callback` - Callback function that receives the current object as parameter **Returns:** -- `static` - Current object, supports method chaining + +- `static` - Current object for method chaining ## Supported Closure Types -This component supports the following types of closures: +This component supports the following closure types: - ✅ Simple closures without parameters - ✅ Closures with dependency injection -- ✅ Closures using captured variables (`use`) +- ✅ Closures with captured variables (`use`) - ✅ Closures with nullable parameters -- ✅ Closures mixing dependency injection and captured variables +- ✅ Mixing dependency injection and captured variables ## Notes -1. **Serialization Limitations**: Closures are serialized for storage, therefore: - - Cannot capture unserializable resources (such as database connections, file handles, etc.) +1. **Serialization Limitations**: Closures are serialized before storage, therefore: + - Cannot capture non-serializable resources (e.g., database connections, file handles) - Captured objects should be serializable -2. **Dependency Injection**: Dependencies in closures are resolved from the container when the task executes and are not serialized +2. **Dependency Injection**: Dependencies in closures will be resolved from the container when the job executes, not serialized -3. **Asynchronous Execution**: Tasks are executed asynchronously; the dispatch function returns immediately without waiting for task completion +3. **Async Execution**: Tasks execute asynchronously. The dispatch function returns immediately without waiting for task completion -4. **Error Handling**: Failed task executions will retry according to the number of attempts set by `setMaxAttempts` +4. **Error Handling**: Failed tasks will retry according to the `setMaxAttempts` configuration ## Configuration -This component uses Hyperf's asynchronous queue configuration. You can configure queue parameters in `config/autoload/async_queue.php`: +This component uses Hyperf's async queue configuration. You can configure queue parameters in `config/autoload/async_queue.php`: ```php push(new SendNotificationJob($userId, $message)); ``` -### Using Closure Tasks +### Using Closure Jobs ```php use function FriendsOfHyperf\AsyncQueueClosureJob\dispatch; -// Use closure directly, no need to create class +// Directly use closure, no need to create a class dispatch(function (NotificationService $notification) use ($userId, $message) { $notification->send($userId, $message); }); ``` -Advantages of closure tasks: -- More concise code, no need for additional class files -- Better readability, task logic is located where it's dispatched -- Full support for dependency injection +Advantages of closure jobs: + +- Cleaner code, no need to create extra class files +- Better readability, job logic is right where it's dispatched +- Full dependency injection support - Flexible fluent API configuration ## Related Components -- [hyperf/async-queue](https://hyperf.wiki/3.1/#/en/async-queue) - Hyperf Async Queue -- [friendsofhyperf/closure-job](https://github.com/friendsofhyperf/components/tree/main/src/closure-job) - General Closure Job Component \ No newline at end of file +- [hyperf/async-queue](https://hyperf.wiki/3.1/#/zh-cn/async-queue) - Hyperf Async Queue +- [friendsofhyperf/closure-job](https://github.com/friendsofhyperf/components/tree/main/src/closure-job) - Generic Closure Job Component diff --git a/docs/zh-cn/components/async-queue-closure-job.md b/docs/zh-cn/components/async-queue-closure-job.md index a5471f970..42365e1a0 100644 --- a/docs/zh-cn/components/async-queue-closure-job.md +++ b/docs/zh-cn/components/async-queue-closure-job.md @@ -231,19 +231,9 @@ foreach ($userIds as $userId) { ### `PendingAsyncQueueDispatch` 方法 -#### `onPool(string $connection): static` - -设置队列连接名称。 - -**参数:** -- `$connection` - 队列连接名称 - -**返回:** -- `static` - 当前对象,支持链式调用 - #### `onPool(string $pool): static` -设置队列连接名称(`onPool` 的别名)。 +设置队列连接名称。 **参数:** - `$pool` - 队列连接名称 diff --git a/docs/zh-hk/components/async-queue-closure-job.md b/docs/zh-hk/components/async-queue-closure-job.md index 4da567735..435f5d820 100644 --- a/docs/zh-hk/components/async-queue-closure-job.md +++ b/docs/zh-hk/components/async-queue-closure-job.md @@ -231,19 +231,9 @@ foreach ($userIds as $userId) { ### `PendingAsyncQueueDispatch` 方法 -#### `onPool(string $connection): static` - -設置隊列連接名稱。 - -**參數:** -- `$connection` - 隊列連接名稱 - -**返回:** -- `static` - 當前對象,支持鏈式調用 - #### `onPool(string $pool): static` -設置隊列連接名稱(`onPool` 的別名)。 +設置隊列連接名稱。 **參數:** - `$pool` - 隊列連接名稱 diff --git a/docs/zh-tw/components/async-queue-closure-job.md b/docs/zh-tw/components/async-queue-closure-job.md index e3471ec4f..e6e405a79 100644 --- a/docs/zh-tw/components/async-queue-closure-job.md +++ b/docs/zh-tw/components/async-queue-closure-job.md @@ -231,19 +231,9 @@ foreach ($userIds as $userId) { ### `PendingAsyncQueueDispatch` 方法 -#### `onPool(string $connection): static` - -設定佇列連線名稱。 - -**引數:** -- `$connection` - 佇列連線名稱 - -**返回:** -- `static` - 當前物件,支援鏈式呼叫 - #### `onPool(string $pool): static` -設定佇列連線名稱(`onPool` 的別名)。 +設定佇列連線名稱。 **引數:** - `$pool` - 佇列連線名稱 From 28f589705cb39e55c7935627005b55061ba9e2f3 Mon Sep 17 00:00:00 2001 From: huangdijia <8337659+huangdijia@users.noreply.github.com> Date: Fri, 14 Nov 2025 13:28:24 +0000 Subject: [PATCH 09/11] Update docs and translate --- docs/en/components/async-queue-closure-job.md | 153 ++++++++---------- 1 file changed, 70 insertions(+), 83 deletions(-) diff --git a/docs/en/components/async-queue-closure-job.md b/docs/en/components/async-queue-closure-job.md index e83d74372..2949ce5f9 100644 --- a/docs/en/components/async-queue-closure-job.md +++ b/docs/en/components/async-queue-closure-job.md @@ -2,9 +2,9 @@ ## Introduction -`friendsofhyperf/async-queue-closure-job` is an async queue closure job component for Hyperf. It allows you to execute closures as background jobs with full support for dependency injection and fluent configuration, making async tasks simpler and more elegant. +`friendsofhyperf/async-queue-closure-job` is an asynchronous queue closure job component for Hyperf. It allows you to execute closures as background tasks, with full support for dependency injection and fluent configuration, making the use of asynchronous tasks simpler and more elegant. -Unlike traditional job classes, this component lets you define job logic directly with closures, eliminating the need for extra class files and making your code more concise. +Unlike the traditional approach of creating task classes, this component enables you to define task logic directly using closures, eliminating the need for additional class files and resulting in cleaner code. ## Installation @@ -14,26 +14,26 @@ composer require friendsofhyperf/async-queue-closure-job ## Basic Usage -### Simple Closure Job +### Simple Closure Task ```php use function FriendsOfHyperf\AsyncQueueClosureJob\dispatch; -// Dispatch a simple closure job +// Dispatch a simple closure task dispatch(function () { - // Your job logic here + // Your task logic var_dump('Hello from closure job!'); }); ``` -### Set Maximum Attempts +### Setting Maximum Attempts ```php use function FriendsOfHyperf\AsyncQueueClosureJob\dispatch; // Set maximum attempts (retry limit) dispatch(function () { - // Your job logic here + // Your task logic // If it fails, it will retry up to 3 times })->setMaxAttempts(3); ``` @@ -42,84 +42,84 @@ dispatch(function () { ### Fluent API Configuration -You can flexibly configure various options using method chaining: +Through method chaining, you can flexibly configure various options for the task: ```php use function FriendsOfHyperf\AsyncQueueClosureJob\dispatch; // Chain multiple configuration options dispatch(function () { - // Your job logic here + // Your task logic }) ->onPool('high-priority') // Specify queue connection ->delay(60) // Delay execution by 60 seconds ->setMaxAttempts(5); // Retry up to 5 times ``` -### Specifying Queue Connections +### Specifying Queue Connection -When you have multiple queue connections, you can specify which connection to use: +When you have multiple queue connections, you can specify which connection the task should use: ```php use function FriendsOfHyperf\AsyncQueueClosureJob\dispatch; -// Use a specific queue connection +// Use the specified queue connection dispatch(function () { - // High priority task logic + // High-priority task logic })->onPool('high-priority'); -// Alternative pool name +// Or use the onPool method (alias) dispatch(function () { - // Low priority task logic + // Low-priority task logic })->onPool('low-priority'); ``` ### Delayed Execution -You can set a delay before the task starts executing: +You can set the task to execute after a certain period: ```php use function FriendsOfHyperf\AsyncQueueClosureJob\dispatch; -// Delay execution by 60 seconds +// Execute after a 60-second delay dispatch(function () { - // Your job logic here + // Your task logic })->delay(60); -// Delay execution by 5 minutes +// Execute after a 5-minute delay dispatch(function () { - // Your job logic here + // Your task logic })->delay(300); ``` ### Conditional Execution -Use `when` and `unless` methods to dynamically configure tasks based on conditions: +Use the `when` and `unless` methods to dynamically configure tasks based on conditions: ```php use function FriendsOfHyperf\AsyncQueueClosureJob\dispatch; $isUrgent = true; -// Execute callback only when condition is true +// Execute callback only when the condition is true dispatch(function () { - // Your job logic here + // Your task logic }) ->when($isUrgent, function ($dispatch) { $dispatch->onPool('urgent'); }); -// Execute callback only when condition is false +// Execute callback only when the condition is false dispatch(function () { - // Your job logic here + // Your task logic }) ->unless($isUrgent, function ($dispatch) { - $dispatch->delay(30); + $dispatch->delay(300); }); -// Combine usage +// Combined usage dispatch(function () { - // Your job logic here + // Your task logic }) ->when($isUrgent, function ($dispatch) { $dispatch->onPool('urgent'); @@ -131,7 +131,7 @@ dispatch(function () { ### Dependency Injection -Closure jobs fully support Hyperf's dependency injection. You can declare required dependencies as closure parameters: +Closure tasks fully support Hyperf's dependency injection. You can declare required dependencies in the closure parameters: ```php use function FriendsOfHyperf\AsyncQueueClosureJob\dispatch; @@ -142,16 +142,16 @@ use Psr\Log\LoggerInterface; dispatch(function (UserService $userService, LoggerInterface $logger) { $users = $userService->getActiveUsers(); $logger->info('Processing ' . count($users) . ' users'); - + foreach ($users as $user) { - // Process users... + // Process user... } }); ``` ### Using Captured Variables -You can use external variables in closures via the `use` keyword: +You can use external variables in the closure via the `use` keyword: ```php use function FriendsOfHyperf\AsyncQueueClosureJob\dispatch; @@ -159,17 +159,17 @@ use function FriendsOfHyperf\AsyncQueueClosureJob\dispatch; $userId = 123; $action = 'update'; -// Use captured variables +// Using captured variables dispatch(function (UserService $userService) use ($userId, $action) { $user = $userService->find($userId); - + if ($action === 'update') { $userService->update($user); } })->setMaxAttempts(3); ``` -## Real-World Use Cases +## Practical Application Scenarios ### Sending Notifications @@ -181,7 +181,7 @@ dispatch(function (NotificationService $notification) use ($userId, $message) { })->setMaxAttempts(3); ``` -### File Upload Processing +### Handling File Uploads ```php use function FriendsOfHyperf\AsyncQueueClosureJob\dispatch; @@ -221,15 +221,13 @@ foreach ($userIds as $userId) { ### `dispatch(Closure $closure): PendingAsyncQueueDispatch` -The main dispatch function that creates a closure job. +The main dispatch function used to create closure tasks. **Parameters:** - - `$closure` - The closure to execute **Returns:** - -- `PendingAsyncQueueDispatch` - Pending closure dispatch object +- `PendingAsyncQueueDispatch` - The pending closure dispatch object ### `PendingAsyncQueueDispatch` Methods @@ -238,88 +236,78 @@ The main dispatch function that creates a closure job. Set the queue connection name. **Parameters:** - - `$pool` - Queue connection name **Returns:** - -- `static` - Current object for method chaining +- `static` - Current object, supports method chaining #### `delay(int $delay): static` -Set the delay time before execution. +Set the delay execution time. **Parameters:** - - `$delay` - Delay time in seconds **Returns:** - -- `static` - Current object for method chaining +- `static` - Current object, supports method chaining #### `setMaxAttempts(int $maxAttempts): static` -Set the maximum retry attempts. +Set the maximum number of retry attempts. **Parameters:** - -- `$maxAttempts` - Maximum attempts +- `$maxAttempts` - Maximum number of attempts **Returns:** - -- `static` - Current object for method chaining +- `static` - Current object, supports method chaining #### `when($condition, $callback): static` -Execute callback when condition is true. +Execute callback when the condition is true. **Parameters:** - - `$condition` - Condition expression -- `$callback` - Callback function that receives the current object as parameter +- `$callback` - Callback function that receives the current object as a parameter **Returns:** - -- `static` - Current object for method chaining +- `static` - Current object, supports method chaining #### `unless($condition, $callback): static` -Execute callback when condition is false. +Execute callback when the condition is false. **Parameters:** - - `$condition` - Condition expression -- `$callback` - Callback function that receives the current object as parameter +- `$callback` - Callback function that receives the current object as a parameter **Returns:** - -- `static` - Current object for method chaining +- `static` - Current object, supports method chaining ## Supported Closure Types -This component supports the following closure types: +This component supports the following types of closures: - ✅ Simple closures without parameters - ✅ Closures with dependency injection -- ✅ Closures with captured variables (`use`) +- ✅ Closures using captured variables (`use`) - ✅ Closures with nullable parameters -- ✅ Mixing dependency injection and captured variables +- ✅ Closures mixing dependency injection and captured variables ## Notes -1. **Serialization Limitations**: Closures are serialized before storage, therefore: - - Cannot capture non-serializable resources (e.g., database connections, file handles) +1. **Serialization Limitations**: Closures are serialized and stored, therefore: + - Cannot capture unserializable resources (such as database connections, file handles, etc.) - Captured objects should be serializable -2. **Dependency Injection**: Dependencies in closures will be resolved from the container when the job executes, not serialized +2. **Dependency Injection**: Dependencies in closures are resolved from the container when the task executes and are not serialized -3. **Async Execution**: Tasks execute asynchronously. The dispatch function returns immediately without waiting for task completion +3. **Asynchronous Execution**: Tasks are executed asynchronously; the dispatch function returns immediately without waiting for task completion -4. **Error Handling**: Failed tasks will retry according to the `setMaxAttempts` configuration +4. **Error Handling**: Failed tasks will be retried according to the number set by `setMaxAttempts` ## Configuration -This component uses Hyperf's async queue configuration. You can configure queue parameters in `config/autoload/async_queue.php`: +This component uses Hyperf's asynchronous queue configuration. You can configure queue parameters in `config/autoload/async_queue.php`: ```php push(new SendNotificationJob($userId, $message)); ``` -### Using Closure Jobs +### Using Closure Tasks ```php use function FriendsOfHyperf\AsyncQueueClosureJob\dispatch; -// Directly use closure, no need to create a class +// Use closure directly, no need to create a class dispatch(function (NotificationService $notification) use ($userId, $message) { $notification->send($userId, $message); }); ``` -Advantages of closure jobs: - -- Cleaner code, no need to create extra class files -- Better readability, job logic is right where it's dispatched -- Full dependency injection support +Advantages of closure tasks: +- Cleaner code, no need for additional class files +- Better readability, task logic is right where it's dispatched +- Full support for dependency injection - Flexible fluent API configuration ## Related Components -- [hyperf/async-queue](https://hyperf.wiki/3.1/#/zh-cn/async-queue) - Hyperf Async Queue -- [friendsofhyperf/closure-job](https://github.com/friendsofhyperf/components/tree/main/src/closure-job) - Generic Closure Job Component +- [hyperf/async-queue](https://hyperf.wiki/3.1/#/en/async-queue) - Hyperf Asynchronous Queue +- [friendsofhyperf/closure-job](https://github.com/friendsofhyperf/components/tree/main/src/closure-job) - General Closure Job Component \ No newline at end of file From c324010e292bbcf1af12120a7c25dce72a3b5328 Mon Sep 17 00:00:00 2001 From: Deeka Wong <8337659+huangdijia@users.noreply.github.com> Date: Fri, 14 Nov 2025 21:28:56 +0800 Subject: [PATCH 10/11] =?UTF-8?q?=E5=88=A0=E9=99=A4=20AsyncQueueClosureJob?= =?UTF-8?q?=20=E7=9B=B8=E5=85=B3=E7=9A=84=E6=B5=8B=E8=AF=95=E6=96=87?= =?UTF-8?q?=E4=BB=B6=E4=BB=A5=E7=AE=80=E5=8C=96=E4=BB=A3=E7=A0=81=E5=BA=93?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../CoreFunctionalityTest.php | 263 ----------- .../DispatchFunctionSimpleTest.php | 192 -------- .../DispatchFunctionTest.php | 289 ------------ .../FluentDispatchIntegrationTest.php | 434 ------------------ 4 files changed, 1178 deletions(-) delete mode 100644 tests/AsyncQueueClosureJob/CoreFunctionalityTest.php delete mode 100644 tests/AsyncQueueClosureJob/DispatchFunctionSimpleTest.php delete mode 100644 tests/AsyncQueueClosureJob/DispatchFunctionTest.php delete mode 100644 tests/AsyncQueueClosureJob/FluentDispatchIntegrationTest.php diff --git a/tests/AsyncQueueClosureJob/CoreFunctionalityTest.php b/tests/AsyncQueueClosureJob/CoreFunctionalityTest.php deleted file mode 100644 index 1d6cc9ba9..000000000 --- a/tests/AsyncQueueClosureJob/CoreFunctionalityTest.php +++ /dev/null @@ -1,263 +0,0 @@ -shouldReceive('get') - ->with(DriverFactory::class) - ->andReturn($driverFactory); - - $driverFactory->shouldReceive('get') - ->withAnyArgs() - ->andReturn($driver); - - $driver->shouldReceive('push') - ->andReturnTrue(); - - ApplicationContext::setContainer($container); - } - - protected function tearDown(): void - { - parent::tearDown(); - m::close(); - } - - public function testCallQueuedClosureCreateWithMaxAttempts() - { - $closure = function () { - return 'test'; - }; - - $job = CallQueuedClosure::create($closure); - $job->setMaxAttempts(5); - - $this->assertInstanceOf(CallQueuedClosure::class, $job); - $this->assertEquals(5, $job->getMaxAttempts()); - } - - public function testCallQueuedClosureCreateWithDefaultMaxAttempts() - { - $closure = function () { - return 'test'; - }; - - $job = CallQueuedClosure::create($closure); - - $this->assertInstanceOf(CallQueuedClosure::class, $job); - $this->assertEquals(0, $job->getMaxAttempts()); - } - - public function testCallQueuedClosureConstructorWithMaxAttempts() - { - $closure = function () { - return 'test'; - }; - - $job = CallQueuedClosure::create($closure); - $job->setMaxAttempts(3); - - $this->assertInstanceOf(CallQueuedClosure::class, $job); - $this->assertEquals(3, $job->getMaxAttempts()); - } - - public function testPendingAsyncQueueDispatchConfiguration() - { - $job = CallQueuedClosure::create(function () { - return 'test'; - }); - - $dispatch = new PendingAsyncQueueDispatch($job); - - // Test configuration methods - $result = $dispatch->onPool('test-connection') - ->delay(30) - ->setMaxAttempts(7); - - $this->assertSame($dispatch, $result); - $this->assertEquals('test-connection', $this->getProperty($dispatch, 'pool')); - $this->assertEquals(30, $this->getProperty($dispatch, 'delay')); - $this->assertEquals(7, $job->getMaxAttempts()); - } - - public function testDispatchFunctionCreatesCorrectObjects() - { - $closure = function () { - return 'dispatch test'; - }; - - $dispatch = \FriendsOfHyperf\AsyncQueueClosureJob\dispatch($closure); - $dispatch->setMaxAttempts(4); - - $this->assertInstanceOf(PendingAsyncQueueDispatch::class, $dispatch); - - $job = $this->getProperty($dispatch, 'job'); - $this->assertInstanceOf(CallQueuedClosure::class, $job); - $this->assertEquals(4, $job->getMaxAttempts()); - } - - public function testDispatchFunctionWithDefaultMaxAttempts() - { - $closure = function () { - return 'dispatch test'; - }; - - $dispatch = \FriendsOfHyperf\AsyncQueueClosureJob\dispatch($closure); - - $this->assertInstanceOf(PendingAsyncQueueDispatch::class, $dispatch); - - $job = $this->getProperty($dispatch, 'job'); - $this->assertInstanceOf(CallQueuedClosure::class, $job); - $this->assertEquals(0, $job->getMaxAttempts()); - } - - public function testFluentMethodChaining() - { - $closure = function () { - return 'chaining test'; - }; - - $dispatch = \FriendsOfHyperf\AsyncQueueClosureJob\dispatch($closure) - ->onPool('chained-connection') - ->delay(60) - ->setMaxAttempts(8); // Override initial value - - $this->assertEquals('chained-connection', $this->getProperty($dispatch, 'pool')); - $this->assertEquals(60, $this->getProperty($dispatch, 'delay')); - - $job = $this->getProperty($dispatch, 'job'); - $this->assertEquals(8, $job->getMaxAttempts()); - } - - public function testConditionableTraitFunctionality() - { - $closure = function () { - return 'conditionable test'; - }; - - // Test when() with true condition - $dispatch1 = \FriendsOfHyperf\AsyncQueueClosureJob\dispatch($closure) - ->when(true, function ($dispatch) { - $dispatch->onPool('when-true-connection'); - }); - - $this->assertEquals('when-true-connection', $this->getProperty($dispatch1, 'pool')); - - // Test when() with false condition - $dispatch2 = \FriendsOfHyperf\AsyncQueueClosureJob\dispatch($closure) - ->when(false, function ($dispatch) { - $dispatch->onPool('when-false-connection'); - }); - - $this->assertEquals('default', $this->getProperty($dispatch2, 'pool')); - - // Test unless() with true condition - $dispatch3 = \FriendsOfHyperf\AsyncQueueClosureJob\dispatch($closure) - ->unless(true, function ($dispatch) { - $dispatch->onPool('unless-true-connection'); - }); - - $this->assertEquals('default', $this->getProperty($dispatch3, 'pool')); - - // Test unless() with false condition - $dispatch4 = \FriendsOfHyperf\AsyncQueueClosureJob\dispatch($closure) - ->unless(false, function ($dispatch) { - $dispatch->onPool('unless-false-connection'); - }); - - $this->assertEquals('unless-false-connection', $this->getProperty($dispatch4, 'pool')); - } - - public function testJobExecutionWithMaxAttempts() - { - $executed = false; - - $job = CallQueuedClosure::create(function () use (&$executed) { - $executed = true; - return 'executed'; - }); - $job->setMaxAttempts(6); - - $this->assertEquals(6, $job->getMaxAttempts()); - - // Mock container for execution - $container = m::mock(ContainerInterface::class); - $container->shouldReceive('has') - ->with(\Hyperf\Di\ClosureDefinitionCollectorInterface::class) - ->andReturn(false); - - ApplicationContext::setContainer($container); - - $result = $job->handle(); - - $this->assertTrue($executed); - $this->assertEquals('executed', $result); - } - - public function testMultipleMaxAttemptsValues() - { - $closure = function () { return 'test'; }; - - $job1 = CallQueuedClosure::create($closure); - $job1->setMaxAttempts(1); - $job2 = CallQueuedClosure::create($closure); - $job2->setMaxAttempts(5); - $job3 = CallQueuedClosure::create($closure); - $job3->setMaxAttempts(10); - $job4 = CallQueuedClosure::create($closure); - $job4->setMaxAttempts(0); - $job5 = CallQueuedClosure::create($closure); - $job5->setMaxAttempts(-1); - - $this->assertEquals(1, $job1->getMaxAttempts()); - $this->assertEquals(5, $job2->getMaxAttempts()); - $this->assertEquals(10, $job3->getMaxAttempts()); - $this->assertEquals(0, $job4->getMaxAttempts()); - $this->assertEquals(-1, $job5->getMaxAttempts()); - } - - /** - * Helper method to get protected/private property value. - */ - protected function getProperty(object $object, string $property): mixed - { - $reflection = new ReflectionClass($object); - $property = $reflection->getProperty($property); - $property->setAccessible(true); - - return $property->getValue($object); - } -} diff --git a/tests/AsyncQueueClosureJob/DispatchFunctionSimpleTest.php b/tests/AsyncQueueClosureJob/DispatchFunctionSimpleTest.php deleted file mode 100644 index 0deb2adc8..000000000 --- a/tests/AsyncQueueClosureJob/DispatchFunctionSimpleTest.php +++ /dev/null @@ -1,192 +0,0 @@ -shouldReceive('get') - ->with(DriverFactory::class) - ->andReturn($driverFactory); - - $driverFactory->shouldReceive('get') - ->withAnyArgs() - ->andReturn($driver); - - $driver->shouldReceive('push') - ->andReturnTrue(); - - ApplicationContext::setContainer($container); - } - - protected function tearDown(): void - { - parent::tearDown(); - m::close(); - } - - public function testDispatchFunctionWithDefaultMaxAttempts() - { - $closure = function () { - return 'test'; - }; - - $dispatch = \FriendsOfHyperf\AsyncQueueClosureJob\dispatch($closure); - - $this->assertInstanceOf(PendingAsyncQueueDispatch::class, $dispatch); - - // Verify the job has default maxAttempts (0) - $job = $this->getProperty($dispatch, 'job'); - $this->assertInstanceOf(CallQueuedClosure::class, $job); - $this->assertEquals(0, $job->getMaxAttempts()); - } - - public function testDispatchFunctionWithCustomMaxAttempts() - { - $closure = function () { - return 'test with max attempts'; - }; - - $dispatch = \FriendsOfHyperf\AsyncQueueClosureJob\dispatch($closure); - $dispatch->setMaxAttempts(5); - - $this->assertInstanceOf(PendingAsyncQueueDispatch::class, $dispatch); - - // Verify the job has the specified maxAttempts - $job = $this->getProperty($dispatch, 'job'); - $this->assertInstanceOf(CallQueuedClosure::class, $job); - $this->assertEquals(5, $job->getMaxAttempts()); - } - - public function testDispatchFunctionWithZeroMaxAttempts() - { - $closure = function () { - return 'zero attempts'; - }; - - $dispatch = \FriendsOfHyperf\AsyncQueueClosureJob\dispatch($closure); - $dispatch->setMaxAttempts(0); - - $this->assertInstanceOf(PendingAsyncQueueDispatch::class, $dispatch); - - // Verify the job has zero maxAttempts - $job = $this->getProperty($dispatch, 'job'); - $this->assertInstanceOf(CallQueuedClosure::class, $job); - $this->assertEquals(0, $job->getMaxAttempts()); - } - - public function testDispatchFunctionChainingWithMaxAttempts() - { - $closure = function () { - return 'chained dispatch'; - }; - - $dispatch = \FriendsOfHyperf\AsyncQueueClosureJob\dispatch($closure) - ->onPool('delayed-connection') - ->delay(120) - ->setMaxAttempts(5); // Override the initial maxAttempts - - $this->assertInstanceOf(PendingAsyncQueueDispatch::class, $dispatch); - - // Verify the job has the overridden maxAttempts - $job = $this->getProperty($dispatch, 'job'); - $this->assertInstanceOf(CallQueuedClosure::class, $job); - $this->assertEquals(5, $job->getMaxAttempts()); // Should be overridden to 5 - - // Verify fluent configuration - $this->assertEquals('delayed-connection', $this->getProperty($dispatch, 'pool')); - $this->assertEquals(120, $this->getProperty($dispatch, 'delay')); - } - - public function testDispatchFunctionConditionableMethods() - { - $closure = function () { - return 'conditional'; - }; - - $dispatch = \FriendsOfHyperf\AsyncQueueClosureJob\dispatch($closure) - ->when(true, function ($dispatch) { - $dispatch->onPool('conditional-connection'); - }) - ->unless(false, function ($dispatch) { - $dispatch->delay(45); - }) - ->setMaxAttempts(1); - - $this->assertInstanceOf(PendingAsyncQueueDispatch::class, $dispatch); - - // Verify configuration - $this->assertEquals('conditional-connection', $this->getProperty($dispatch, 'pool')); - $this->assertEquals(45, $this->getProperty($dispatch, 'delay')); - - // Verify the job has the specified maxAttempts - $job = $this->getProperty($dispatch, 'job'); - $this->assertInstanceOf(CallQueuedClosure::class, $job); - $this->assertEquals(1, $job->getMaxAttempts()); - } - - public function testDispatchFunctionWithMultipleConfigurations() - { - $closure = function () { - return 'multi-config test'; - }; - - // Test multiple method calls and overrides - $dispatch = \FriendsOfHyperf\AsyncQueueClosureJob\dispatch($closure) - ->onPool('initial-connection') - ->delay(60) - ->setMaxAttempts(8) // Override maxAttempts - ->onPool('multi-config-connection') // Override connection - ->delay(300) // Override delay - ->setMaxAttempts(10); // Final maxAttempts - - $this->assertEquals('multi-config-connection', $this->getProperty($dispatch, 'pool')); - $this->assertEquals(300, $this->getProperty($dispatch, 'delay')); - - $job = $this->getProperty($dispatch, 'job'); - $this->assertEquals(10, $job->getMaxAttempts()); - } - - /** - * Helper method to get protected/private property value. - */ - protected function getProperty(object $object, string $property): mixed - { - $reflection = new ReflectionClass($object); - $property = $reflection->getProperty($property); - $property->setAccessible(true); - - return $property->getValue($object); - } -} diff --git a/tests/AsyncQueueClosureJob/DispatchFunctionTest.php b/tests/AsyncQueueClosureJob/DispatchFunctionTest.php deleted file mode 100644 index 176cd7eaf..000000000 --- a/tests/AsyncQueueClosureJob/DispatchFunctionTest.php +++ /dev/null @@ -1,289 +0,0 @@ -shouldReceive('get') - ->with(DriverFactory::class) - ->andReturn($driverFactory); - - $driverFactory->shouldReceive('get') - ->withAnyArgs() - ->andReturn($driver); - - $driver->shouldReceive('push') - ->andReturnTrue(); - - ApplicationContext::setContainer($container); - - $closure = function () { - return 'test'; - }; - - $dispatch = \FriendsOfHyperf\AsyncQueueClosureJob\dispatch($closure); - - $this->assertInstanceOf(PendingAsyncQueueDispatch::class, $dispatch); - - // Verify the job has default maxAttempts (0) - $job = $this->getProperty($dispatch, 'job'); - $this->assertInstanceOf(CallQueuedClosure::class, $job); - $this->assertEquals(0, $job->getMaxAttempts()); - } - - public function testDispatchFunctionWithCustomMaxAttempts() - { - // Mock the container and driver factory to prevent actual dispatch - $container = m::mock(ContainerInterface::class); - $driverFactory = m::mock(DriverFactory::class); - $driver = m::mock(Driver::class); - - $container->shouldReceive('get') - ->with(DriverFactory::class) - ->andReturn($driverFactory); - - $driverFactory->shouldReceive('get') - ->withAnyArgs() - ->andReturn($driver); - - $driver->shouldReceive('push') - ->andReturnTrue(); - - ApplicationContext::setContainer($container); - - $closure = function () { - return 'test with max attempts'; - }; - - $dispatch = \FriendsOfHyperf\AsyncQueueClosureJob\dispatch($closure); - $dispatch->setMaxAttempts(5); - - $this->assertInstanceOf(PendingAsyncQueueDispatch::class, $dispatch); - - // Verify the job has the specified maxAttempts - $job = $this->getProperty($dispatch, 'job'); - $this->assertInstanceOf(CallQueuedClosure::class, $job); - $this->assertEquals(5, $job->getMaxAttempts()); - } - - public function testDispatchFunctionWithFluentConfiguration() - { - $executed = false; - - // Mock the container and driver factory - $container = m::mock(ContainerInterface::class); - $driverFactory = m::mock(DriverFactory::class); - $driver = m::mock(Driver::class); - - $container->shouldReceive('get') - ->with(DriverFactory::class) - ->once() - ->andReturn($driverFactory); - - $driverFactory->shouldReceive('get') - ->with('high-priority') - ->once() - ->andReturn($driver); - - $driver->shouldReceive('push') - ->once() - ->with(m::type(CallQueuedClosure::class), 30) - ->andReturnTrue(); - - ApplicationContext::setContainer($container); - - $closure = function () use (&$executed) { - $executed = true; - }; - - $dispatch = \FriendsOfHyperf\AsyncQueueClosureJob\dispatch($closure) - ->onPool('high-priority') - ->delay(30) - ->setMaxAttempts(3); - - $this->assertInstanceOf(PendingAsyncQueueDispatch::class, $dispatch); - - // Verify the job has the specified maxAttempts - $job = $this->getProperty($dispatch, 'job'); - $this->assertInstanceOf(CallQueuedClosure::class, $job); - $this->assertEquals(3, $job->getMaxAttempts()); - - // Trigger destruct to verify dispatch - unset($dispatch); - $this->assertFalse($executed); // Job should be queued, not executed immediately - } - - public function testDispatchFunctionChainingWithMaxAttempts() - { - $container = m::mock(ContainerInterface::class); - $driverFactory = m::mock(DriverFactory::class); - $driver = m::mock(Driver::class); - - $container->shouldReceive('get') - ->with(DriverFactory::class) - ->once() - ->andReturn($driverFactory); - - $driverFactory->shouldReceive('get') - ->with('delayed-connection') - ->once() - ->andReturn($driver); - - $driver->shouldReceive('push') - ->once() - ->with(m::type(CallQueuedClosure::class), 120) - ->andReturnTrue(); - - ApplicationContext::setContainer($container); - - $closure = function () { - return 'chained dispatch'; - }; - - $dispatch = \FriendsOfHyperf\AsyncQueueClosureJob\dispatch($closure) - ->onPool('delayed-connection') - ->delay(120) - ->setMaxAttempts(5); // Override the initial maxAttempts - - $this->assertInstanceOf(PendingAsyncQueueDispatch::class, $dispatch); - - // Verify the job has the overridden maxAttempts - $job = $this->getProperty($dispatch, 'job'); - $this->assertInstanceOf(CallQueuedClosure::class, $job); - $this->assertEquals(5, $job->getMaxAttempts()); // Should be overridden to 5 - - // Trigger destruct - unset($dispatch); - } - - public function testDispatchFunctionWithZeroMaxAttempts() - { - $container = m::mock(ContainerInterface::class); - $driverFactory = m::mock(DriverFactory::class); - $driver = m::mock(Driver::class); - - $container->shouldReceive('get') - ->with(DriverFactory::class) - ->andReturn($driverFactory); - - $driverFactory->shouldReceive('get') - ->withAnyArgs() - ->andReturn($driver); - - $driver->shouldReceive('push') - ->andReturnTrue(); - - ApplicationContext::setContainer($container); - - $closure = function () { - return 'zero attempts'; - }; - - $dispatch = \FriendsOfHyperf\AsyncQueueClosureJob\dispatch($closure); - $dispatch->setMaxAttempts(0); - - $this->assertInstanceOf(PendingAsyncQueueDispatch::class, $dispatch); - - // Verify the job has zero maxAttempts - $job = $this->getProperty($dispatch, 'job'); - $this->assertInstanceOf(CallQueuedClosure::class, $job); - $this->assertEquals(0, $job->getMaxAttempts()); - } - - public function testDispatchFunctionConditionableMethods() - { - $container = m::mock(ContainerInterface::class); - $driverFactory = m::mock(DriverFactory::class); - $driver = m::mock(Driver::class); - - $container->shouldReceive('get') - ->with(DriverFactory::class) - ->once() - ->andReturn($driverFactory); - - $driverFactory->shouldReceive('get') - ->with('conditional-connection') - ->once() - ->andReturn($driver); - - $driver->shouldReceive('push') - ->once() - ->andReturnTrue(); - - ApplicationContext::setContainer($container); - - $closure = function () { - return 'conditional'; - }; - - $dispatch = \FriendsOfHyperf\AsyncQueueClosureJob\dispatch($closure) - ->when(true, function ($dispatch) { - $dispatch->onPool('conditional-connection'); - }) - ->unless(false, function ($dispatch) { - $dispatch->delay(45); - }) - ->setMaxAttempts(1); - - $this->assertInstanceOf(PendingAsyncQueueDispatch::class, $dispatch); - - // Verify configuration - $this->assertEquals('conditional-connection', $this->getProperty($dispatch, 'pool')); - $this->assertEquals(45, $this->getProperty($dispatch, 'delay')); - - // Verify the job has the specified maxAttempts - $job = $this->getProperty($dispatch, 'job'); - $this->assertInstanceOf(CallQueuedClosure::class, $job); - $this->assertEquals(1, $job->getMaxAttempts()); - - unset($dispatch); - } - - /** - * Helper method to get protected/private property value. - */ - protected function getProperty(object $object, string $property): mixed - { - $reflection = new ReflectionClass($object); - $property = $reflection->getProperty($property); - $property->setAccessible(true); - - return $property->getValue($object); - } -} diff --git a/tests/AsyncQueueClosureJob/FluentDispatchIntegrationTest.php b/tests/AsyncQueueClosureJob/FluentDispatchIntegrationTest.php deleted file mode 100644 index 38d12f25a..000000000 --- a/tests/AsyncQueueClosureJob/FluentDispatchIntegrationTest.php +++ /dev/null @@ -1,434 +0,0 @@ -setupDefaultContainerMock(); - } - - protected function tearDown(): void - { - parent::tearDown(); - m::close(); - } - - public function testCompleteFluentDispatchWorkflow() - { - $executionOrder = []; - - // Mock the container and driver factory - $container = m::mock(ContainerInterface::class); - $driverFactory = m::mock(DriverFactory::class); - $driver = m::mock(Driver::class); - - $container->shouldReceive('get') - ->with(DriverFactory::class) - ->once() - ->andReturn($driverFactory); - - $container->shouldReceive('has') - ->with(\Hyperf\Di\ClosureDefinitionCollectorInterface::class) - ->andReturn(false); - - $driverFactory->shouldReceive('get') - ->with('integration-connection') - ->once() - ->andReturn($driver); - - // Capture the job that gets pushed to verify it can be executed - $driver->shouldReceive('push') - ->once() - ->with(m::type(CallQueuedClosure::class), 90) - ->andReturnUsing(function ($job) use (&$executionOrder) { - $executionOrder[] = 'job_pushed'; - // Simulate what would happen when the job is processed - $this->simulateJobExecution($job, $executionOrder); - return true; - }); - - ApplicationContext::setContainer($container); - - // Create a closure that tracks its execution - $testValue = null; - $closure = function () use (&$testValue, &$executionOrder) { - $executionOrder[] = 'closure_executed'; - $testValue = 'integration test success'; - return $testValue; - }; - - $executionOrder[] = 'dispatch_started'; - - // Use the fluent dispatch API - $dispatch = \FriendsOfHyperf\AsyncQueueClosureJob\dispatch($closure) - ->onPool('integration-connection') - ->delay(90) - ->setMaxAttempts(3); - - $executionOrder[] = 'dispatch_configured'; - - // Verify the job configuration - $job = $this->getProperty($dispatch, 'job'); - $this->assertInstanceOf(CallQueuedClosure::class, $job); - $this->assertEquals(3, $job->getMaxAttempts()); - - // Trigger destruct to simulate the job being pushed to queue - unset($dispatch); - $executionOrder[] = 'dispatch_completed'; - - // Verify the execution order - $expectedOrder = [ - 'dispatch_started', - 'dispatch_configured', - 'job_pushed', - 'closure_executed', - 'dispatch_completed', - ]; - - $this->assertEquals($expectedOrder, $executionOrder); - $this->assertEquals('integration test success', $testValue); - } - - public function testFluentDispatchWithDependencyInjection() - { - $container = m::mock(ContainerInterface::class); - $driverFactory = m::mock(DriverFactory::class); - $driver = m::mock(Driver::class); - - $container->shouldReceive('get') - ->with(DriverFactory::class) - ->once() - ->andReturn($driverFactory); - - $driverFactory->shouldReceive('get') - ->with('di-connection') - ->once() - ->andReturn($driver); - - $driver->shouldReceive('push') - ->once() - ->andReturnUsing(function ($job) { - $this->simulateJobExecutionWithDI($job); - return true; - }); - - ApplicationContext::setContainer($container); - - $injectedService = new stdClass(); - $injectedService->value = 'injected service'; - - $result = null; - $closure = function (stdClass $service) use (&$result) { - $result = $service->value; - }; - - // Set up the container and driver factory for this test - $container = m::mock(ContainerInterface::class); - $driverFactory = m::mock(DriverFactory::class); - $driver = m::mock(Driver::class); - - // Set up the container to handle dependency injection and driver factory - $container->shouldReceive('get') - ->with(DriverFactory::class) - ->zeroOrMoreTimes() - ->andReturn($driverFactory); - - $container->shouldReceive('has') - ->with(stdClass::class) - ->andReturn(true); - - $container->shouldReceive('get') - ->with(stdClass::class) - ->andReturn($injectedService); - - // Add missing expectations for the destructor call - $container->shouldReceive('has') - ->with(\Hyperf\Di\ClosureDefinitionCollectorInterface::class) - ->andReturn(false); - - $driverFactory->shouldReceive('get') - ->with('di-connection') - ->andReturn($driver); - - $driver->shouldReceive('push') - ->andReturnUsing(function ($job) use (&$result) { - $this->simulateJobExecutionWithDI($job); - return true; - }); - - // Dispatch with dependency injection - $dispatch = \FriendsOfHyperf\AsyncQueueClosureJob\dispatch($closure) - ->onPool('di-connection') - ->delay(60) - ->setMaxAttempts(1); - - unset($dispatch); // Trigger execution - - $this->assertEquals('injected service', $result); - } - - public function testFluentDispatchWithConditionalLogic() - { - $container = m::mock(ContainerInterface::class); - $driverFactory = m::mock(DriverFactory::class); - $highPriorityDriver = m::mock(Driver::class); - $lowPriorityDriver = m::mock(Driver::class); - - $container->shouldReceive('get') - ->with(DriverFactory::class) - ->zeroOrMoreTimes() - ->andReturn($driverFactory); - - // Test with condition = true (should use high priority) - $driverFactory->shouldReceive('get') - ->with('high-priority') - ->once() - ->andReturn($highPriorityDriver); - - $highPriorityDriver->shouldReceive('push') - ->once() - ->andReturnTrue(); - - ApplicationContext::setContainer($container); - - $executed = false; - $condition = true; - - $dispatch = \FriendsOfHyperf\AsyncQueueClosureJob\dispatch(function () use (&$executed) { - $executed = true; - }) - ->when($condition, function ($dispatch) { - $dispatch->onPool('high-priority'); - }) - ->unless(! $condition, function ($dispatch) { - $dispatch->delay(30); - }) - ->setMaxAttempts(2); - - $this->assertEquals('high-priority', $this->getProperty($dispatch, 'pool')); - $this->assertEquals(30, $this->getProperty($dispatch, 'delay')); - - unset($dispatch); - } - - public function testFluentDispatchWithMultipleConfigurations() - { - $container = m::mock(ContainerInterface::class); - $driverFactory = m::mock(DriverFactory::class); - $driver = m::mock(Driver::class); - - $container->shouldReceive('get') - ->with(DriverFactory::class) - ->once() - ->andReturn($driverFactory); - - $driverFactory->shouldReceive('get') - ->with('multi-config-connection') - ->once() - ->andReturn($driver); - - $driver->shouldReceive('push') - ->once() - ->with(m::type(CallQueuedClosure::class), 300) - ->andReturnUsing(function ($job) { - // Verify the job has the correct maxAttempts - $this->assertEquals(10, $job->getMaxAttempts()); - return true; - }); - - ApplicationContext::setContainer($container); - - $closure = function () { - return 'multi-config test'; - }; - - // Test multiple method calls and overrides - $dispatch = \FriendsOfHyperf\AsyncQueueClosureJob\dispatch($closure) - ->onPool('initial-connection') - ->delay(60) - ->setMaxAttempts(8) // Override maxAttempts - ->onPool('multi-config-connection') // Override queue - ->delay(300) // Override delay - ->setMaxAttempts(10); // Final maxAttempts - - $this->assertEquals('multi-config-connection', $this->getProperty($dispatch, 'pool')); - $this->assertEquals(300, $this->getProperty($dispatch, 'delay')); - - $job = $this->getProperty($dispatch, 'job'); - $this->assertEquals(10, $job->getMaxAttempts()); - - // Avoid triggering destructor which would try to dispatch the job - // Instead, just verify the configuration - } - - public function testFluentDispatchErrorHandling() - { - $container = m::mock(ContainerInterface::class); - $driverFactory = m::mock(DriverFactory::class); - - $container->shouldReceive('get') - ->with(DriverFactory::class) - ->once() - ->andReturn($driverFactory); - - $driverFactory->shouldReceive('get') - ->with('error-connection') - ->once() - ->andThrow(new Exception('Driver not found')); - - ApplicationContext::setContainer($container); - - $this->expectException(Exception::class); - $this->expectExceptionMessage('Driver not found'); - - $closure = function () { - return 'error test'; - }; - - $dispatch = \FriendsOfHyperf\AsyncQueueClosureJob\dispatch($closure) - ->onPool('error-connection') - ->setMaxAttempts(1); - - unset($dispatch); // This should trigger the exception - } - - protected function setupDefaultContainerMock(): void - { - $container = m::mock(ContainerInterface::class); - $driverFactory = m::mock(DriverFactory::class); - $driver = m::mock(Driver::class); - - $container->shouldReceive('get') - ->with(DriverFactory::class) - ->zeroOrMoreTimes() - ->andReturn($driverFactory); - - $container->shouldReceive('has') - ->with(\Hyperf\Di\ClosureDefinitionCollectorInterface::class) - ->andReturn(false) - ->byDefault(); - - $driverFactory->shouldReceive('get') - ->withAnyArgs() - ->zeroOrMoreTimes() - ->byDefault() - ->andReturn($driver); - - $driver->shouldReceive('push') - ->zeroOrMoreTimes() - ->byDefault() - ->andReturnTrue(); - - ApplicationContext::setContainer($container); - } - - /** - * Simulate job execution for testing. - * @param mixed $job - */ - protected function simulateJobExecution($job, array &$executionOrder): void - { - // The container should already be set up with proper mocks - // Just execute the job - $job->handle(); - } - - /** - * Simulate job execution with dependency injection. - * @param mixed $job - */ - protected function simulateJobExecutionWithDI($job): void - { - // Set up container expectations for dependency injection - $container = m::mock(ContainerInterface::class); - - // Mock the ClosureDefinitionCollectorInterface - $definitionCollector = m::mock(\Hyperf\Di\ClosureDefinitionCollectorInterface::class); - $definition = m::mock(\Hyperf\Di\Definition\DefinitionInterface::class); - - $container->shouldReceive('has') - ->with(\Hyperf\Di\ClosureDefinitionCollectorInterface::class) - ->andReturn(true); - - $container->shouldReceive('get') - ->with(\Hyperf\Di\ClosureDefinitionCollectorInterface::class) - ->andReturn($definitionCollector); - - // Mock the definition for stdClass parameter - $definitionCollector->shouldReceive('getParameters') - ->withAnyArgs() - ->andReturn([$definition]); - - $definition->shouldReceive('getMeta') - ->with('name') - ->andReturn('service'); - - $definition->shouldReceive('getName') - ->andReturn(stdClass::class); - - $definition->shouldReceive('getMeta') - ->with('defaultValueAvailable') - ->andReturn(false); - - $definition->shouldReceive('allowsNull') - ->andReturn(false); - - // Set up dependency injection for stdClass - $container->shouldReceive('has') - ->with(stdClass::class) - ->andReturn(true); - - $injectedService = new stdClass(); - $injectedService->value = 'injected service'; - - $container->shouldReceive('get') - ->with(stdClass::class) - ->andReturn($injectedService); - - ApplicationContext::setContainer($container); - - // Execute the job - $job->handle(); - } - - /** - * Helper method to get protected/private property value. - */ - protected function getProperty(object $object, string $property): mixed - { - $reflection = new ReflectionClass($object); - $property = $reflection->getProperty($property); - $property->setAccessible(true); - - return $property->getValue($object); - } -} From 196a80c427911965bd208dc67ec3a5ca2ea43b86 Mon Sep 17 00:00:00 2001 From: Deeka Wong <8337659+huangdijia@users.noreply.github.com> Date: Fri, 14 Nov 2025 21:33:43 +0800 Subject: [PATCH 11/11] =?UTF-8?q?=E6=B7=BB=E5=8A=A0=20AsyncQueueClosureJob?= =?UTF-8?q?=20=E7=9A=84=E5=8A=9F=E8=83=BD=E6=B5=8B=E8=AF=95=EF=BC=8C?= =?UTF-8?q?=E9=AA=8C=E8=AF=81=20dispatch=20=E6=96=B9=E6=B3=95=E5=8F=8A?= =?UTF-8?q?=E5=85=B6=E9=93=BE=E5=BC=8F=E8=B0=83=E7=94=A8?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- types/AsyncQueueClosureJob/Functions.php | 64 ++++++++++++++++++++++++ 1 file changed, 64 insertions(+) create mode 100644 types/AsyncQueueClosureJob/Functions.php diff --git a/types/AsyncQueueClosureJob/Functions.php b/types/AsyncQueueClosureJob/Functions.php new file mode 100644 index 000000000..11eca253a --- /dev/null +++ b/types/AsyncQueueClosureJob/Functions.php @@ -0,0 +1,64 @@ + 'result')); +assertType('FriendsOfHyperf\Support\Bus\PendingAsyncQueueDispatch', dispatch(function () { + return 'test'; +})); + +// Method chaining tests - setMaxAttempts() +assertType('FriendsOfHyperf\Support\Bus\PendingAsyncQueueDispatch', dispatch(fn () => true)->setMaxAttempts(3)); + +// Method chaining tests - onPool() +assertType('FriendsOfHyperf\Support\Bus\PendingAsyncQueueDispatch', dispatch(fn () => null)->onPool('default')); +assertType('FriendsOfHyperf\Support\Bus\PendingAsyncQueueDispatch', dispatch(fn () => [])->onPool('custom-pool')); + +// Method chaining tests - delay() +assertType('FriendsOfHyperf\Support\Bus\PendingAsyncQueueDispatch', dispatch(fn () => 123)->delay(10)); +assertType('FriendsOfHyperf\Support\Bus\PendingAsyncQueueDispatch', dispatch(fn () => new stdClass())->delay(0)); + +// Complex method chaining +assertType( + 'FriendsOfHyperf\Support\Bus\PendingAsyncQueueDispatch', + dispatch(fn () => 'multi-chain') + ->setMaxAttempts(5) + ->onPool('worker') + ->delay(30) +); + +assertType( + 'FriendsOfHyperf\Support\Bus\PendingAsyncQueueDispatch', + dispatch(function () { + return ['key' => 'value']; + }) + ->delay(60) + ->setMaxAttempts(3) +); + +// Different closure return types +assertType('FriendsOfHyperf\Support\Bus\PendingAsyncQueueDispatch', dispatch(fn (): string => 'typed return')); +assertType('FriendsOfHyperf\Support\Bus\PendingAsyncQueueDispatch', dispatch(fn (): int => 42)); +assertType('FriendsOfHyperf\Support\Bus\PendingAsyncQueueDispatch', dispatch(fn (): array => [])); +assertType('FriendsOfHyperf\Support\Bus\PendingAsyncQueueDispatch', dispatch(fn (): bool => true)); +assertType('FriendsOfHyperf\Support\Bus\PendingAsyncQueueDispatch', dispatch(fn (): ?string => null)); +assertType('FriendsOfHyperf\Support\Bus\PendingAsyncQueueDispatch', dispatch(function (): void { + // void return type +})); + +// Closures with parameters +assertType('FriendsOfHyperf\Support\Bus\PendingAsyncQueueDispatch', dispatch(fn ($param) => $param)); +assertType('FriendsOfHyperf\Support\Bus\PendingAsyncQueueDispatch', dispatch(fn (string $name, int $age) => "{$name} is {$age}")); +assertType('FriendsOfHyperf\Support\Bus\PendingAsyncQueueDispatch', dispatch(function ($a, $b) { + return $a + $b; +}));