From 6b69322a66cbce47f5bca5aa008812d323b7b863 Mon Sep 17 00:00:00 2001 From: Gustavo Silva Date: Tue, 29 Sep 2026 09:38:48 -0400 Subject: [PATCH] Add RequestExecption catch Code improvements --- ProcessMaker/Jobs/RunScriptTask.php | 9 ++- tests/Jobs/RunScriptTaskTest.php | 106 +++++++++++++++++++++++++++- 2 files changed, 111 insertions(+), 4 deletions(-) diff --git a/ProcessMaker/Jobs/RunScriptTask.php b/ProcessMaker/Jobs/RunScriptTask.php index 08b8400b41..96db25a383 100644 --- a/ProcessMaker/Jobs/RunScriptTask.php +++ b/ProcessMaker/Jobs/RunScriptTask.php @@ -2,12 +2,12 @@ namespace ProcessMaker\Jobs; +use Exception; use Illuminate\Contracts\Queue\ShouldQueue; use Illuminate\Database\Eloquent\ModelNotFoundException; use Illuminate\Support\Facades\Log; use ProcessMaker\Enums\ScriptExecutorType; use ProcessMaker\Exception\ConfigurationException; -use ProcessMaker\Exception\ScriptException; use ProcessMaker\Facades\Metrics; use ProcessMaker\Facades\WorkflowManager; use ProcessMaker\Managers\DataManager; @@ -144,8 +144,11 @@ public function action(ProcessRequestToken $token = null, ScriptTaskInterface $e $error->setName($message); $token->setProperty('error', $error); - $exceptionClass = get_class($exception); - $modifiedException = new $exceptionClass($message); + if ($message !== $exception->getMessage()) { + $modifiedException = new Exception($message, $exception->getCode(), $exception); + } else { + $modifiedException = $exception; + } $token->logError($modifiedException, $element); Log::error('Script failed: ' . $scriptRef . ' - ' . $message); diff --git a/tests/Jobs/RunScriptTaskTest.php b/tests/Jobs/RunScriptTaskTest.php index 6e44152f95..c398369504 100644 --- a/tests/Jobs/RunScriptTaskTest.php +++ b/tests/Jobs/RunScriptTaskTest.php @@ -2,12 +2,13 @@ namespace Tests\Jobs; +use Illuminate\Http\Client\RequestException; +use Illuminate\Http\Client\Response; use Illuminate\Support\Facades\Auth; use Illuminate\Support\Facades\Queue; use Mockery; use PHPUnit\Framework\Attributes\DataProvider; use ProcessMaker\Facades\WorkflowManager; -use ProcessMaker\Jobs\ErrorHandling; use ProcessMaker\Jobs\RunNayraScriptTask; use ProcessMaker\Jobs\RunScriptTask; use ProcessMaker\Models\Process; @@ -15,6 +16,8 @@ use ProcessMaker\Models\ProcessRequestToken; use ProcessMaker\Models\Script; use ProcessMaker\Models\User; +use ProcessMaker\Nayra\Contracts\Bpmn\ScriptTaskInterface; +use ProcessMaker\ScriptRunners\MockRunner; use Tests\TestCase; class RunScriptTaskTest extends TestCase @@ -47,6 +50,68 @@ public function testRunAsUserNotFound($class) $this->assertEquals('my node (node_2): A user is required to run scripts', $request->data['_configuration_error_node_2']); } + public function testRequestExceptionMarksTokenFailingAndStoresError(): void + { + $this->mockScriptRunnerThrowingRequestException(503); + + $request = $this->startScriptWithErrorHandling([ + 'retry_attempts' => 0, + 'retry_wait_time' => 1, + ]); + + $token = $request->tokens()->where('element_id', 'node_54')->first(); + + $this->assertNotNull($token); + $this->assertEquals(ScriptTaskInterface::TOKEN_STATE_FAILING, $token->status); + $this->assertNotEmpty($request->refresh()->errors); + $this->assertStringContainsString('HTTP request returned status code 503', $request->errors[0]['message']); + } + + public function testRequestExceptionUsesConfiguredRetries(): void + { + Queue::fake(); + $this->mockScriptRunnerThrowingRequestException(503); + + $user = User::factory()->create(); + Auth::login($user); + + $script = Script::factory()->create([ + 'retry_attempts' => 0, + 'retry_wait_time' => 1, + ]); + $bpmn = file_get_contents(__DIR__ . '/../Fixtures/ScriptWithErrorHandling.bpmn'); + $bpmn = str_replace('[script_id]', $script->id, $bpmn); + $errorHandlingValue = str_replace('"', '"', json_encode([ + 'retry_attempts' => 2, + 'retry_wait_time' => 5, + ])); + $bpmn = str_replace('[error_handling]', $errorHandlingValue, $bpmn); + + $process = Process::factory()->create(['bpmn' => $bpmn]); + $request = ProcessRequest::factory()->create([ + 'process_id' => $process->id, + 'status' => 'ACTIVE', + ]); + $token = ProcessRequestToken::factory()->create([ + 'process_request_id' => $request->id, + 'element_id' => 'node_54', + 'element_type' => 'scriptTask', + 'element_name' => 'Script Task', + 'status' => 'ACTIVE', + ]); + + (new RunScriptTask($process, $request, $token, [], 1))->handle(); + + Queue::assertPushed(RunScriptTask::class, function ($job) { + return $job->attemptNum === 2 && $job->delay === 5; + }); + + $this->assertNotEquals( + ScriptTaskInterface::TOKEN_STATE_FAILING, + $token->refresh()->status + ); + } + private function runJob($class, $scriptId) { $user = User::factory()->create(); @@ -78,6 +143,45 @@ private function runJob($class, $scriptId) return $request->refresh(); } + private function startScriptWithErrorHandling(array $errorHandling): ProcessRequest + { + $user = User::factory()->create(); + Auth::login($user); + + $script = Script::factory()->create([]); + $bpmn = file_get_contents(__DIR__ . '/../Fixtures/ScriptWithErrorHandling.bpmn'); + $bpmn = str_replace('[script_id]', $script->id, $bpmn); + $errorHandlingValue = str_replace('"', '"', json_encode($errorHandling)); + $bpmn = str_replace('[error_handling]', $errorHandlingValue, $bpmn); + + $process = Process::factory()->create([ + 'bpmn' => $bpmn, + 'properties' => [ + 'manager_id' => $user->id, + ], + ]); + $event = $process->getDefinitions()->getEvent('node_45'); + + return WorkflowManager::triggerStartEvent($process, $event, []); + } + + private function mockScriptRunnerThrowingRequestException(int $status = 503): void + { + $mock = Mockery::mock(MockRunner::class); + $mock->shouldReceive('setTokenId'); + $mock->shouldReceive('run')->andReturnUsing(function () use ($status) { + $response = new Response( + new \GuzzleHttp\Psr7\Response($status, [], 'Service Unavailable') + ); + + throw new RequestException($response); + }); + + app()->bind(MockRunner::class, function () use ($mock) { + return $mock; + }); + } + public static function jobTypes() { return [