From 20ca61bd7fe0ec15bd7f5e33ddb60ca10c76388f Mon Sep 17 00:00:00 2001 From: David Callizaya Date: Fri, 14 Jul 2023 09:40:59 -0400 Subject: [PATCH 1/2] Script Executor used by Nayra service --- ProcessMaker/Jobs/RunNayraScriptTask.php | 129 ++++++++++++++++++ .../Nayra/Repositories/PersistenceHandler.php | 8 ++ 2 files changed, 137 insertions(+) create mode 100644 ProcessMaker/Jobs/RunNayraScriptTask.php diff --git a/ProcessMaker/Jobs/RunNayraScriptTask.php b/ProcessMaker/Jobs/RunNayraScriptTask.php new file mode 100644 index 0000000000..3e9ed525f7 --- /dev/null +++ b/ProcessMaker/Jobs/RunNayraScriptTask.php @@ -0,0 +1,129 @@ +tokenId = $token->getKey(); + } + + /** + * Execute the job. + * + * @return void + */ + public function handle() + { + // Get token + $token = ProcessRequestToken::find($this->tokenId); + $token->loadTokenProperties(); + $instance = $token->processRequest; + $processModel = $token->process; + $instance->loadProcessRequestInstance(); + $token->setInstance($instance); + $element = $token->getDefinition(true); + + // Exit if the task was completed or closed + if (!$token || !$element) { + return; + } + $scriptRef = $element->getProperty('scriptRef'); + $configuration = json_decode($element->getProperty('config'), true); + $errorHandling = json_decode($element->getProperty('errorHandling'), true); + if ($errorHandling === null) { + $errorHandling = []; + } + + // Check to see if we've failed parsing. If so, let's convert to empty array. + if ($configuration === null) { + $configuration = []; + } + try { + if (empty($scriptRef)) { + $code = $element->getScript(); + if (empty($code)) { + throw new ScriptException(__('No code or script assigned to ":name"', ['name' => $element->getName()])); + } + $language = Script::scriptFormat2Language($element->getProperty('scriptFormat', 'application/x-php')); + $script = new Script([ + 'code' => $code, + 'language' => $language, + 'run_as_user_id' => Script::defaultRunAsUser()->id, + 'script_executor_id' => ScriptExecutor::initialExecutor($language)->id, + ]); + } else { + $script = Script::findOrFail($scriptRef)->versionFor($instance); + } + + $dataManager = new DataManager(); + $data = $dataManager->getData($token); + $response = $script->runScript($data, $configuration, $token->getId(), $errorHandling); + + // Dispatch complete task action + WorkflowManager::completeTask($processModel, $instance, $token, $response['output']); + } catch (Throwable $exception) { + Log::error('Script failed: ' . $scriptRef . ' - ' . $exception->getMessage()); + Log::error($exception->getTraceAsString()); + WorkflowManager::taskFailed($instance, $token, $exception->getMessage()); + } + } + + /** + * When Job fails + */ + public function failed(Throwable $exception) + { + if (!$this->tokenId) { + Log::error('Script failed: ' . $exception->getMessage()); + + return; + } + Log::error('Script (#' . $this->tokenId . ') failed: ' . $exception->getMessage()); + $token = ProcessRequestToken::find($this->tokenId); + if ($token) { + $element = $token->getBpmnDefinition(); + $token->setStatus(ScriptTaskInterface::TOKEN_STATE_FAILING); + $error = $element->getRepository()->createError(); + $error->setName($exception->getMessage()); + $token->setProperty('error', $error); + Log::error($exception->getTraceAsString()); + $token->save(); + } + } +} diff --git a/ProcessMaker/Nayra/Repositories/PersistenceHandler.php b/ProcessMaker/Nayra/Repositories/PersistenceHandler.php index c202028b04..5fa4bdcf9f 100644 --- a/ProcessMaker/Nayra/Repositories/PersistenceHandler.php +++ b/ProcessMaker/Nayra/Repositories/PersistenceHandler.php @@ -5,6 +5,7 @@ use Exception; use Illuminate\Support\Facades\Auth; use Illuminate\Support\Facades\Log; +use ProcessMaker\Jobs\RunNayraScriptTask; use ProcessMaker\Listeners\BpmnSubscriber; use ProcessMaker\Managers\TaskSchedulerManager; use ProcessMaker\Models\ProcessRequest; @@ -137,6 +138,13 @@ public function save(array $transaction) $subscriber = new BpmnSubscriber(); $subscriber->onServiceTaskActivated($serviceTask, $token); break; + case 'script_task_executor': + // Get object instances + $token = $this->deserializer->unserializeToken($transaction['token']); + + // Trigger script task executor + RunNayraScriptTask::dispatch($token)->onQueue('bpmn'); + break; default: throw new Exception('Unknown transaction type ' . $transaction['type']); } From 890fb5dd9d598ca7a4f7bb518e2d0e323bdac11f Mon Sep 17 00:00:00 2001 From: David Callizaya Date: Fri, 14 Jul 2023 09:41:31 -0400 Subject: [PATCH 2/2] Implement TASK_FAILED action --- ProcessMaker/Facades/WorkflowManager.php | 2 + .../Managers/WorkflowManagerRabbitMq.php | 44 ++++++++++++++++--- 2 files changed, 39 insertions(+), 7 deletions(-) diff --git a/ProcessMaker/Facades/WorkflowManager.php b/ProcessMaker/Facades/WorkflowManager.php index e03bc9223f..7977ae4032 100644 --- a/ProcessMaker/Facades/WorkflowManager.php +++ b/ProcessMaker/Facades/WorkflowManager.php @@ -10,6 +10,8 @@ * * @method static mixed callProcess($filename, $processId) * @method static mixed triggerStartEvent($definitions, $event, array $data) + * @method static mixed completeTask(\ProcessMaker\Models\Process $definitions, \ProcessMaker\Nayra\Contracts\Bpmn\ExecutionInstanceInterface $instance, \ProcessMaker\Nayra\Contracts\Bpmn\TokenInterface $token, array $data) + * @method static mixed taskFailed(\ProcessMaker\Nayra\Contracts\Bpmn\ExecutionInstanceInterface $instance, \ProcessMaker\Nayra\Contracts\Bpmn\TokenInterface $token, string $error) * @method static mixed runScripTask(\ProcessMaker\Nayra\Contracts\Bpmn\ScriptTaskInterface $scriptTask, Token $token) * @method static mixed runServiceTask(\ProcessMaker\Nayra\Contracts\Bpmn\ServiceTaskInterface $serviceTask, Token $token) * @method static void throwSignalEventDefinition(\ProcessMaker\Nayra\Contracts\Bpmn\EventDefinitionInterface $sourceEventDefinition, \ProcessMaker\Nayra\Contracts\Bpmn\TokenInterface $token) diff --git a/ProcessMaker/Nayra/Managers/WorkflowManagerRabbitMq.php b/ProcessMaker/Nayra/Managers/WorkflowManagerRabbitMq.php index 52f3567c39..0de9bfe68a 100644 --- a/ProcessMaker/Nayra/Managers/WorkflowManagerRabbitMq.php +++ b/ProcessMaker/Nayra/Managers/WorkflowManagerRabbitMq.php @@ -44,6 +44,8 @@ class WorkflowManagerRabbitMq extends WorkflowManagerDefault implements Workflow const ACTION_TRIGGER_SIGNAL_EVENT = 'TRIGGER_SIGNAL_EVENT'; + const ACTION_TASK_FAILED = 'TASK_FAILED'; + /** * Trigger a start event and return the process request instance. * @@ -113,7 +115,7 @@ public function triggerStartEvent(Definitions $definitions, StartEventInterface * * @param Definitions $definitions * @param ExecutionInstanceInterface $instance - * @param TokenInterface $token + * @param TokenInterface|ProcessRequestToken $token * @param array $data * * @return void @@ -146,6 +148,39 @@ public function completeTask(Definitions $definitions, ExecutionInstanceInterfac ]); } + /** + * Fail a task. + * + * @param ExecutionInstanceInterface $instance + * @param TokenInterface|ProcessRequestToken $token + * @param string $error + * + * @return void + */ + public function taskFailed(ExecutionInstanceInterface $instance, TokenInterface $token, string $error) + { + // Get complementary information + $version = $instance->process_version_id; + $userId = $this->getCurrentUserId(); + $state = $this->serializeState($instance); + + // Dispatch complete task action + $this->dispatchAction([ + 'bpmn' => $version, + 'action' => self::ACTION_TASK_FAILED, + 'params' => [ + 'request_id' => $token->process_request_id, + 'token_id' => $token->uuid, + 'element_id' => $token->element_id, + 'error' => $error, + ], + 'state' => $state, + 'session' => [ + 'user_id' => $userId, + ], + ]); + } + /** * Complete a catch event. * @@ -312,15 +347,10 @@ public function handleServiceTask(ProcessRequestToken $token) ], ]); } catch (Throwable $exception) { - // Change to error status - $token->setStatus(ServiceTaskInterface::TOKEN_STATE_FAILING); - $error = $element->getRepository()->createError(); - $error->setName($exception->getMessage()); - $token->setProperty('error', $error); - // Log message errors Log::info('Service task failed: ' . $implementation . ' - ' . $exception->getMessage()); Log::error($exception->getTraceAsString()); + $this->taskFailed($instance, $token, $exception->getMessage()); } }