diff --git a/src/Appwrite/Platform/Workers/Functions.php b/src/Appwrite/Platform/Workers/Functions.php index bde5644ade..2ae644a24e 100644 --- a/src/Appwrite/Platform/Workers/Functions.php +++ b/src/Appwrite/Platform/Workers/Functions.php @@ -194,6 +194,70 @@ class Functions extends Action } } + /** + * @param string $message + * @param Document $function + * @param string $trigger + * @param string $path + * @param string $method + * @param Document $user + * @param string|null $jwt + * @param string|null $event + * @throws Exception + */ + private function fail( + string $message, + Database $dbForProject, + Document $function, + string $trigger, + string $path, + string $method, + Document $user, + string $jwt = null, + string $event = null, + ): void { + $headers['x-appwrite-trigger'] = $trigger; + $headers['x-appwrite-event'] = $event ?? ''; + $headers['x-appwrite-user-id'] = $user->getId() ?? ''; + $headers['x-appwrite-user-jwt'] = $jwt ?? ''; + + $headersFiltered = []; + foreach ($headers as $key => $value) { + if (\in_array(\strtolower($key), FUNCTION_ALLOWLIST_HEADERS_REQUEST)) { + $headersFiltered[] = ['name' => $key, 'value' => $value]; + } + } + + $executionId = ID::unique(); + $execution = new Document([ + '$id' => $executionId, + '$permissions' => $user->isEmpty() ? [] : [Permission::read(Role::user($user->getId()))], + 'functionInternalId' => $function->getInternalId(), + 'functionId' => $function->getId(), + 'deploymentInternalId' => '', + 'deploymentId' => '', + 'trigger' => $trigger, + 'status' => 'failed', + 'responseStatusCode' => 0, + 'responseHeaders' => [], + 'requestPath' => $path, + 'requestMethod' => $method, + 'requestHeaders' => $headersFiltered, + 'errors' => $message, + 'logs' => '', + 'duration' => 0.0, + 'search' => implode(' ', [$function->getId(), $executionId]), + ]); + + if ($function->getAttribute('logging')) { + $execution = $dbForProject->createDocument('executions', $execution); + } + + if ($execution->isEmpty()) { + throw new Exception('Failed to create execution'); + } + } + /** * @param Log $log * @param Database $dbForProject @@ -248,24 +312,32 @@ class Functions extends Action $deployment = $dbForProject->getDocument('deployments', $deploymentId); if ($deployment->getAttribute('resourceId') !== $functionId) { - throw new Exception('Deployment not found. Create deployment before trying to execute a function'); + $errorMessage = 'The execution could not be completed because a corresponding deployment was not found. A function deployment needs to be created before it can be executed. Please create a deployment for your function and try again.'; + $this->fail($errorMessage, $dbForProject, $function, $trigger, $path, $method, $user, $jwt, $event); + return; } if ($deployment->isEmpty()) { - throw new Exception('Deployment not found. Create deployment before trying to execute a function'); + $errorMessage = 'The execution could not be completed because a corresponding deployment was not found. A function deployment needs to be created before it can be executed. Please create a deployment for your function and try again.'; + $this->fail($errorMessage, $dbForProject, $function, $trigger, $path, $method, $user, $jwt, $event); + return; } - /** Check if build has exists */ - $build = $dbForProject->getDocument('builds', $deployment->getAttribute('buildId', '')); + /** Check if the build exists */ + $build = $dbForProject->getDocument('builds', $deployment->getAttribute('buildId', '')); if ($build->isEmpty()) { - throw new Exception('Build not found'); + $errorMessage = 'The execution could not be completed because a corresponding deployment was not found. A function deployment needs to be created before it can be executed. Please create a deployment for your function and try again.'; + $this->fail($errorMessage, $dbForProject, $function, $trigger, $path, $method, $user, $jwt, $event); + return; } if ($build->getAttribute('status') !== 'ready') { - throw new Exception('Build not ready'); + $errorMessage = 'The execution could not be completed because the build is not ready. Please wait for the build to complete and try again.'; + $this->fail($errorMessage, $dbForProject, $function, $trigger, $path, $method, $user, $jwt, $event); + return; } - /** Check if runtime is supported */ + /** Check if runtime is supported */ $version = $function->getAttribute('version', 'v2'); $runtimes = Config::getParam($version === 'v2' ? 'runtimes-v2' : 'runtimes', []); @@ -280,7 +352,6 @@ class Functions extends Action $headers['x-appwrite-user-id'] = $user->getId() ?? ''; $headers['x-appwrite-user-jwt'] = $jwt ?? ''; - /** Create execution or update execution status */ /** Create execution or update execution status */ $execution = $dbForProject->getDocument('executions', $executionId ?? ''); if ($execution->isEmpty()) {