diff --git a/docs/en/components/async-queue-closure-job.md b/docs/en/components/async-queue-closure-job.md index 9fb790f18..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,87 +42,87 @@ 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 }) - ->onConnection('high-priority') // Specify queue connection + ->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 -})->onConnection('high-priority'); + // High-priority task logic +})->onPool('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 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->onConnection('urgent'); + $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->onConnection('urgent'); + $dispatch->onPool('urgent'); }) ->unless($isUrgent, function ($dispatch) { $dispatch->delay(60); @@ -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; @@ -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 @@ -219,105 +219,95 @@ foreach ($userIds as $userId) { ## API Reference -### `dispatch(Closure $closure): PendingClosureDispatch` +### `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:** -- `PendingClosureDispatch` - Pending closure dispatch object - -### `PendingClosureDispatch` Methods - -#### `onConnection(string $connection): static` - -Set the queue connection name. +- `PendingAsyncQueueDispatch` - The pending closure dispatch object -**Parameters:** -- `$connection` - Queue connection name - -**Returns:** -- `static` - Current object for method chaining +### `PendingAsyncQueueDispatch` Methods #### `onPool(string $pool): static` -Set the queue connection name (alias for `onConnection`). +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 diff --git a/docs/zh-cn/components/async-queue-closure-job.md b/docs/zh-cn/components/async-queue-closure-job.md index d3b192f44..42365e1a0 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'); ``` ### 批量操作 @@ -219,7 +219,7 @@ foreach ($userIds as $userId) { ## API 参考 -### `dispatch(Closure $closure): PendingClosureDispatch` +### `dispatch(Closure $closure): PendingAsyncQueueDispatch` 主要的分发函数,用于创建闭包任务。 @@ -227,23 +227,13 @@ foreach ($userIds as $userId) { - `$closure` - 要执行的闭包 **返回:** -- `PendingClosureDispatch` - 待处理的闭包分发对象 +- `PendingAsyncQueueDispatch` - 待处理的闭包分发对象 -### `PendingClosureDispatch` 方法 - -#### `onConnection(string $connection): static` - -设置队列连接名称。 - -**参数:** -- `$connection` - 队列连接名称 - -**返回:** -- `static` - 当前对象,支持链式调用 +### `PendingAsyncQueueDispatch` 方法 #### `onPool(string $pool): static` -设置队列连接名称(`onConnection` 的别名)。 +设置队列连接名称。 **参数:** - `$pool` - 队列连接名称 diff --git a/docs/zh-hk/components/async-queue-closure-job.md b/docs/zh-hk/components/async-queue-closure-job.md index 5837099f7..435f5d820 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,22 +51,22 @@ use function FriendsOfHyperf\AsyncQueueClosureJob\dispatch; dispatch(function () { // 你的任務邏輯 }) - ->onConnection('high-priority') // 指定隊列連線 + ->onPool('high-priority') // 指定隊列連接 ->delay(60) // 延遲 60 秒執行 ->setMaxAttempts(5); // 最多重試 5 次 ``` -### 指定隊列連線 +### 指定隊列連接 -當你有多個隊列連線時,可以指定任務使用的連線: +當你有多個隊列連接時,可以指定任務使用的連接: ```php use function FriendsOfHyperf\AsyncQueueClosureJob\dispatch; -// 使用指定的隊列連線 +// 使用指定的隊列連接 dispatch(function () { // 高優先級任務邏輯 -})->onConnection('high-priority'); +})->onPool('high-priority'); // 或者使用 onPool 方法(別名) dispatch(function () { @@ -76,7 +76,7 @@ dispatch(function () { ### 延遲執行 -你可以設定任務在一段時間後才開始執行: +你可以設置任務在一段時間後才開始執行: ```php use function FriendsOfHyperf\AsyncQueueClosureJob\dispatch; @@ -101,15 +101,15 @@ use function FriendsOfHyperf\AsyncQueueClosureJob\dispatch; $isUrgent = true; -// 僅當條件為 true 時執行回撥 +// 僅當條件為 true 時執行回調 dispatch(function () { // 你的任務邏輯 }) ->when($isUrgent, function ($dispatch) { - $dispatch->onConnection('urgent'); + $dispatch->onPool('urgent'); }); -// 僅當條件為 false 時執行回撥 +// 僅當條件為 false 時執行回調 dispatch(function () { // 你的任務邏輯 }) @@ -122,7 +122,7 @@ dispatch(function () { // 你的任務邏輯 }) ->when($isUrgent, function ($dispatch) { - $dispatch->onConnection('urgent'); + $dispatch->onPool('urgent'); }) ->unless($isUrgent, function ($dispatch) { $dispatch->delay(60); @@ -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; @@ -200,10 +200,10 @@ use function FriendsOfHyperf\AsyncQueueClosureJob\dispatch; dispatch(function (StatisticsService $stats) use ($date) { $stats->calculateDailyReport($date); $stats->sendReport($date); -})->onConnection('statistics'); +})->onPool('statistics'); ``` -### 批次操作 +### 批量操作 ```php use function FriendsOfHyperf\AsyncQueueClosureJob\dispatch; @@ -213,111 +213,101 @@ $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); // 為每個任務設置不同的延遲 } ``` ## API 參考 -### `dispatch(Closure $closure): PendingClosureDispatch` +### `dispatch(Closure $closure): PendingAsyncQueueDispatch` -主要的分發函數,用於建立閉包任務。 +主要的分發函數,用於創建閉包任務。 **參數:** - `$closure` - 要執行的閉包 **返回:** -- `PendingClosureDispatch` - 待處理的閉包分發物件 - -### `PendingClosureDispatch` 方法 - -#### `onConnection(string $connection): static` +- `PendingAsyncQueueDispatch` - 待處理的閉包分發對象 -設定隊列連線名稱。 - -**參數:** -- `$connection` - 隊列連線名稱 - -**返回:** -- `static` - 目前物件,支援鏈式調用 +### `PendingAsyncQueueDispatch` 方法 #### `onPool(string $pool): static` -設定隊列連線名稱(`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 90e73823d..e6e405a79 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 配置 @@ -51,7 +51,7 @@ use function FriendsOfHyperf\AsyncQueueClosureJob\dispatch; dispatch(function () { // 你的任務邏輯 }) - ->onConnection('high-priority') // 指定佇列連線 + ->onPool('high-priority') // 指定佇列連線 ->delay(60) // 延遲 60 秒執行 ->setMaxAttempts(5); // 最多重試 5 次 ``` @@ -65,12 +65,12 @@ use function FriendsOfHyperf\AsyncQueueClosureJob\dispatch; // 使用指定的佇列連線 dispatch(function () { - // 高優先級任務邏輯 -})->onConnection('high-priority'); + // 高優先順序任務邏輯 +})->onPool('high-priority'); // 或者使用 onPool 方法(別名) dispatch(function () { - // 低優先級任務邏輯 + // 低優先順序任務邏輯 })->onPool('low-priority'); ``` @@ -101,15 +101,15 @@ use function FriendsOfHyperf\AsyncQueueClosureJob\dispatch; $isUrgent = true; -// 僅當條件為 true 時執行回呼 +// 僅當條件為 true 時執行回撥 dispatch(function () { // 你的任務邏輯 }) ->when($isUrgent, function ($dispatch) { - $dispatch->onConnection('urgent'); + $dispatch->onPool('urgent'); }); -// 僅當條件為 false 時執行回呼 +// 僅當條件為 false 時執行回撥 dispatch(function () { // 你的任務邏輯 }) @@ -122,7 +122,7 @@ dispatch(function () { // 你的任務邏輯 }) ->when($isUrgent, function ($dispatch) { - $dispatch->onConnection('urgent'); + $dispatch->onPool('urgent'); }) ->unless($isUrgent, function ($dispatch) { $dispatch->delay(60); @@ -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); } @@ -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'); ``` ### 批次操作 @@ -219,105 +219,95 @@ foreach ($userIds as $userId) { ## API 參考 -### `dispatch(Closure $closure): PendingClosureDispatch` +### `dispatch(Closure $closure): PendingAsyncQueueDispatch` 主要的分發函式,用於建立閉包任務。 -**參數:** +**引數:** - `$closure` - 要執行的閉包 -**回傳:** -- `PendingClosureDispatch` - 待處理的閉包分發物件 - -### `PendingClosureDispatch` 方法 - -#### `onConnection(string $connection): static` +**返回:** +- `PendingAsyncQueueDispatch` - 待處理的閉包分發物件 -設定佇列連線名稱。 - -**參數:** -- `$connection` - 佇列連線名稱 - -**回傳:** -- `static` - 目前物件,支援鏈式呼叫 +### `PendingAsyncQueueDispatch` 方法 #### `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)| 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/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 deleted file mode 100644 index f13408874..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 testPendingClosureDispatchConfiguration() - { - $job = CallQueuedClosure::create(function () { - return 'test'; - }); - - $dispatch = new PendingClosureDispatch($job); - - // Test configuration methods - $result = $dispatch->onConnection('test-connection') - ->delay(30) - ->setMaxAttempts(7); - - $this->assertSame($dispatch, $result); - $this->assertEquals('test-connection', $this->getProperty($dispatch, 'connection')); - $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(PendingClosureDispatch::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(PendingClosureDispatch::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) - ->onConnection('chained-connection') - ->delay(60) - ->setMaxAttempts(8); // Override initial value - - $this->assertEquals('chained-connection', $this->getProperty($dispatch, 'connection')); - $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->onConnection('when-true-connection'); - }); - - $this->assertEquals('when-true-connection', $this->getProperty($dispatch1, 'connection')); - - // Test when() with false condition - $dispatch2 = \FriendsOfHyperf\AsyncQueueClosureJob\dispatch($closure) - ->when(false, function ($dispatch) { - $dispatch->onConnection('when-false-connection'); - }); - - $this->assertEquals('default', $this->getProperty($dispatch2, 'connection')); - - // Test unless() with true condition - $dispatch3 = \FriendsOfHyperf\AsyncQueueClosureJob\dispatch($closure) - ->unless(true, function ($dispatch) { - $dispatch->onConnection('unless-true-connection'); - }); - - $this->assertEquals('default', $this->getProperty($dispatch3, 'connection')); - - // Test unless() with false condition - $dispatch4 = \FriendsOfHyperf\AsyncQueueClosureJob\dispatch($closure) - ->unless(false, function ($dispatch) { - $dispatch->onConnection('unless-false-connection'); - }); - - $this->assertEquals('unless-false-connection', $this->getProperty($dispatch4, 'connection')); - } - - 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 1177a18d4..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(PendingClosureDispatch::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(PendingClosureDispatch::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(PendingClosureDispatch::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) - ->onConnection('delayed-connection') - ->delay(120) - ->setMaxAttempts(5); // Override the initial maxAttempts - - $this->assertInstanceOf(PendingClosureDispatch::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, 'connection')); - $this->assertEquals(120, $this->getProperty($dispatch, 'delay')); - } - - public function testDispatchFunctionConditionableMethods() - { - $closure = function () { - return 'conditional'; - }; - - $dispatch = \FriendsOfHyperf\AsyncQueueClosureJob\dispatch($closure) - ->when(true, function ($dispatch) { - $dispatch->onConnection('conditional-connection'); - }) - ->unless(false, function ($dispatch) { - $dispatch->delay(45); - }) - ->setMaxAttempts(1); - - $this->assertInstanceOf(PendingClosureDispatch::class, $dispatch); - - // Verify configuration - $this->assertEquals('conditional-connection', $this->getProperty($dispatch, 'connection')); - $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) - ->onConnection('initial-connection') - ->delay(60) - ->setMaxAttempts(8) // Override maxAttempts - ->onConnection('multi-config-connection') // Override connection - ->delay(300) // Override delay - ->setMaxAttempts(10); // Final maxAttempts - - $this->assertEquals('multi-config-connection', $this->getProperty($dispatch, 'connection')); - $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 8166e1951..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(PendingClosureDispatch::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(PendingClosureDispatch::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) - ->onConnection('high-priority') - ->delay(30) - ->setMaxAttempts(3); - - $this->assertInstanceOf(PendingClosureDispatch::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) - ->onConnection('delayed-connection') - ->delay(120) - ->setMaxAttempts(5); // Override the initial maxAttempts - - $this->assertInstanceOf(PendingClosureDispatch::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(PendingClosureDispatch::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->onConnection('conditional-connection'); - }) - ->unless(false, function ($dispatch) { - $dispatch->delay(45); - }) - ->setMaxAttempts(1); - - $this->assertInstanceOf(PendingClosureDispatch::class, $dispatch); - - // Verify configuration - $this->assertEquals('conditional-connection', $this->getProperty($dispatch, 'connection')); - $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 16aa6789b..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) - ->onConnection('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) - ->onConnection('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->onConnection('high-priority'); - }) - ->unless(! $condition, function ($dispatch) { - $dispatch->delay(30); - }) - ->setMaxAttempts(2); - - $this->assertEquals('high-priority', $this->getProperty($dispatch, 'connection')); - $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) - ->onConnection('initial-connection') - ->delay(60) - ->setMaxAttempts(8) // Override maxAttempts - ->onConnection('multi-config-connection') // Override queue - ->delay(300) // Override delay - ->setMaxAttempts(10); // Final maxAttempts - - $this->assertEquals('multi-config-connection', $this->getProperty($dispatch, 'connection')); - $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) - ->onConnection('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); - } -} 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); - } -} 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; +}));