diff --git a/app/config/errors.php b/app/config/errors.php index 9e742d3296..fff274b2c3 100644 --- a/app/config/errors.php +++ b/app/config/errors.php @@ -134,7 +134,7 @@ return [ Exception::USER_COUNT_EXCEEDED => [ 'name' => Exception::USER_COUNT_EXCEEDED, 'description' => 'The current project has exceeded the maximum number of users. Please check your user limit in the Appwrite console.', - 'code' => 501, + 'code' => 400, ], Exception::USER_CONSOLE_COUNT_EXCEEDED => [ 'name' => Exception::USER_CONSOLE_COUNT_EXCEEDED, @@ -519,6 +519,11 @@ return [ 'description' => 'Entrypoint for your Appwrite Function is missing. Please specify it when making deployment or update the entrypoint under your function\'s "Settings" > "Configuration" > "Entrypoint".', 'code' => 404, ], + Exception::FUNCTION_SYNCHRONOUS_TIMEOUT => [ + 'name' => Exception::FUNCTION_SYNCHRONOUS_TIMEOUT, + 'description' => 'Synchronous function execution timed out. Use asynchronous execution instead, or ensure the execution duration doesn\'t exceed 30 seconds.', + 'code' => 408, + ], /** Builds */ Exception::BUILD_NOT_FOUND => [ diff --git a/app/controllers/api/functions.php b/app/controllers/api/functions.php index ed5af1d38a..a88d3815e9 100644 --- a/app/controllers/api/functions.php +++ b/app/controllers/api/functions.php @@ -9,6 +9,7 @@ use Appwrite\Event\Func; use Appwrite\Event\Usage; use Appwrite\Event\Validator\FunctionEvent; use Appwrite\Extend\Exception; +use Appwrite\Extend\Exception as AppwriteException; use Appwrite\Messaging\Adapter\Realtime; use Appwrite\Task\Validator\Cron; use Appwrite\Utopia\Database\Validator\CustomId; @@ -1750,6 +1751,10 @@ App::post('/v1/functions/:functionId/executions') ->setAttribute('responseStatusCode', 500) ->setAttribute('errors', $th->getMessage() . '\nError Code: ' . $th->getCode()); Console::error($th->getMessage()); + + if ($th instanceof AppwriteException) { + throw $th; + } } finally { $queueForUsage ->addMetric(METRIC_EXECUTIONS, 1) @@ -1757,11 +1762,11 @@ App::post('/v1/functions/:functionId/executions') ->addMetric(METRIC_EXECUTIONS_COMPUTE, (int)($execution->getAttribute('duration') * 1000)) // per project ->addMetric(str_replace('{functionInternalId}', $function->getInternalId(), METRIC_FUNCTION_ID_EXECUTIONS_COMPUTE), (int)($execution->getAttribute('duration') * 1000)) // per function ; - } - if ($function->getAttribute('logging')) { - /** @var Document $execution */ - $execution = Authorization::skip(fn () => $dbForProject->createDocument('executions', $execution)); + if ($function->getAttribute('logging')) { + /** @var Document $execution */ + $execution = Authorization::skip(fn () => $dbForProject->createDocument('executions', $execution)); + } } $roles = Authorization::getRoles(); diff --git a/app/controllers/api/projects.php b/app/controllers/api/projects.php index c51697bf95..5464014b48 100644 --- a/app/controllers/api/projects.php +++ b/app/controllers/api/projects.php @@ -152,10 +152,10 @@ App::post('/v1/projects') throw new Exception(Exception::PROJECT_RESERVED_PROJECT, "'console' is a reserved project."); } - // TODO: One in 20 projects use shared tables. Temporary until all projects are using shared tables. + // TODO: 1 in 5 projects use shared tables. Temporary until all projects are using shared tables. if ( ( - !\mt_rand(0, 19) + !\mt_rand(0, 4) && System::getEnv('_APP_DATABASE_SHARED_TABLES', 'enabled') === 'enabled' && System::getEnv('_APP_EDITION', 'self-hosted') !== 'self-hosted' ) || diff --git a/app/controllers/general.php b/app/controllers/general.php index 1fa70ed703..2c8a4f68aa 100644 --- a/app/controllers/general.php +++ b/app/controllers/general.php @@ -289,6 +289,7 @@ function router(App $utopia, Database $dbForConsole, callable $getProjectDB, Swo $execution->setAttribute('logs', $executionResponse['logs']); $execution->setAttribute('errors', $executionResponse['errors']); $execution->setAttribute('duration', $executionResponse['duration']); + } catch (\Throwable $th) { $durationEnd = \microtime(true); @@ -298,6 +299,10 @@ function router(App $utopia, Database $dbForConsole, callable $getProjectDB, Swo ->setAttribute('responseStatusCode', 500) ->setAttribute('errors', $th->getMessage() . '\nError Code: ' . $th->getCode()); Console::error($th->getMessage()); + + if ($th instanceof AppwriteException) { + throw $th; + } } finally { $queueForUsage ->addMetric(METRIC_EXECUTIONS, 1) @@ -305,11 +310,11 @@ function router(App $utopia, Database $dbForConsole, callable $getProjectDB, Swo ->addMetric(METRIC_EXECUTIONS_COMPUTE, (int)($execution->getAttribute('duration') * 1000)) // per project ->addMetric(str_replace('{functionInternalId}', $function->getInternalId(), METRIC_FUNCTION_ID_EXECUTIONS_COMPUTE), (int)($execution->getAttribute('duration') * 1000)) // per function ; - } - if ($function->getAttribute('logging')) { - /** @var Document $execution */ - $execution = Authorization::skip(fn () => $dbForProject->createDocument('executions', $execution)); + if ($function->getAttribute('logging')) { + /** @var Document $execution */ + $execution = Authorization::skip(fn () => $dbForProject->createDocument('executions', $execution)); + } } $execution->setAttribute('logs', ''); diff --git a/app/init.php b/app/init.php index 88e8de0ea2..8260707ef7 100644 --- a/app/init.php +++ b/app/init.php @@ -215,6 +215,7 @@ const MESSAGE_TYPE_PUSH = 'push'; const METRIC_TEAMS = 'teams'; const METRIC_USERS = 'users'; const METRIC_MESSAGES = 'messages'; +const METRIC_MESSAGES_COUNTRY_CODE = '{countryCode}.messages'; const METRIC_SESSIONS = 'sessions'; const METRIC_DATABASES = 'databases'; const METRIC_COLLECTIONS = 'collections'; diff --git a/app/views/install/compose.phtml b/app/views/install/compose.phtml index 711b46733f..9c0cc31bbf 100644 --- a/app/views/install/compose.phtml +++ b/app/views/install/compose.phtml @@ -731,7 +731,7 @@ services: <<: *x-logging restart: unless-stopped stop_signal: SIGINT - image: openruntimes/executor:0.4.12 + image: openruntimes/executor:0.5.5 networks: - appwrite - runtimes diff --git a/app/worker.php b/app/worker.php index d698a824ac..483aeb3352 100644 --- a/app/worker.php +++ b/app/worker.php @@ -337,10 +337,6 @@ $worker $pools->reclaim(); $version = System::getEnv('_APP_VERSION', 'UNKNOWN'); - if ($error instanceof PDOException) { - throw $error; - } - if ($logger) { $log->setNamespace("appwrite-worker"); $log->setServer(\gethostname()); diff --git a/composer.lock b/composer.lock index 7fc372d624..30d5ed74e0 100644 --- a/composer.lock +++ b/composer.lock @@ -1556,16 +1556,16 @@ }, { "name": "utopia-php/database", - "version": "0.49.9", + "version": "0.49.10", "source": { "type": "git", "url": "https://github.com/utopia-php/database.git", - "reference": "ee93c14b99820f791c669648854f094fe399a085" + "reference": "216209121bc97a2010f67a39c561fafe1e936bec" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/utopia-php/database/zipball/ee93c14b99820f791c669648854f094fe399a085", - "reference": "ee93c14b99820f791c669648854f094fe399a085", + "url": "https://api.github.com/repos/utopia-php/database/zipball/216209121bc97a2010f67a39c561fafe1e936bec", + "reference": "216209121bc97a2010f67a39c561fafe1e936bec", "shasum": "" }, "require": { @@ -1606,9 +1606,9 @@ ], "support": { "issues": "https://github.com/utopia-php/database/issues", - "source": "https://github.com/utopia-php/database/tree/0.49.9" + "source": "https://github.com/utopia-php/database/tree/0.49.10" }, - "time": "2024-05-12T23:58:34+00:00" + "time": "2024-05-20T02:14:20+00:00" }, { "name": "utopia-php/domains", diff --git a/docker-compose.yml b/docker-compose.yml index b3b197381b..1a38893f3a 100644 --- a/docker-compose.yml +++ b/docker-compose.yml @@ -794,7 +794,7 @@ services: hostname: exc1 <<: *x-logging stop_signal: SIGINT - image: openruntimes/executor:0.5.1 + image: openruntimes/executor:0.5.5 restart: unless-stopped networks: - appwrite diff --git a/src/Appwrite/Event/Usage.php b/src/Appwrite/Event/Usage.php index cf92e6ffef..4426f4ab1b 100644 --- a/src/Appwrite/Event/Usage.php +++ b/src/Appwrite/Event/Usage.php @@ -58,7 +58,6 @@ class Usage extends Event public function trigger(): string|bool { $client = new Client($this->queue, $this->connection); - return $client->enqueue([ 'project' => $this->getProject(), 'reduce' => $this->reduce, diff --git a/src/Appwrite/Extend/Exception.php b/src/Appwrite/Extend/Exception.php index 48409f06b1..d48787bb98 100644 --- a/src/Appwrite/Extend/Exception.php +++ b/src/Appwrite/Extend/Exception.php @@ -153,6 +153,7 @@ class Exception extends \Exception public const FUNCTION_NOT_FOUND = 'function_not_found'; public const FUNCTION_RUNTIME_UNSUPPORTED = 'function_runtime_unsupported'; public const FUNCTION_ENTRYPOINT_MISSING = 'function_entrypoint_missing'; + public const FUNCTION_SYNCHRONOUS_TIMEOUT = 'function_synchronous_timeout'; /** Deployments */ public const DEPLOYMENT_NOT_FOUND = 'deployment_not_found'; diff --git a/src/Appwrite/Platform/Workers/Messaging.php b/src/Appwrite/Platform/Workers/Messaging.php index 0399302e77..c8df169e28 100644 --- a/src/Appwrite/Platform/Workers/Messaging.php +++ b/src/Appwrite/Platform/Workers/Messaging.php @@ -441,17 +441,24 @@ class Messaging extends Action try { $adapter->send($data); + $countryCode = $adapter->getCountryCode($message['to'][0] ?? ''); + if (!empty($countryCode)) { + $queueForUsage + ->addMetric(str_replace('{countryCode}', $countryCode, METRIC_MESSAGES_COUNTRY_CODE), 1); + } $queueForUsage ->addMetric(METRIC_MESSAGES, 1) ->setProject($project) ->trigger(); - } catch (\Throwable $e) { - throw new \Exception('Failed sending to targets with error: ' . $e->getMessage()); + } catch (\Throwable $th) { + throw new \Exception('Failed sending to targets with error: ' . $th->getMessage()); } }; }, $batches)); } + + private function getSmsAdapter(Document $provider): ?SMSAdapter { $credentials = $provider->getAttribute('credentials'); diff --git a/src/Executor/Executor.php b/src/Executor/Executor.php index 76c66de231..e9b0ae016e 100644 --- a/src/Executor/Executor.php +++ b/src/Executor/Executor.php @@ -2,6 +2,7 @@ namespace Executor; +use Appwrite\Extend\Exception as AppwriteException; use Exception; use Utopia\System\System; @@ -193,7 +194,6 @@ class Executor 'path' => $path, 'method' => $method, 'headers' => $headers, - 'image' => $image, 'source' => $source, 'entrypoint' => $entrypoint, @@ -311,6 +311,8 @@ class Executor $responseType = $responseHeaders['content-type'] ?? ''; $responseStatus = curl_getinfo($ch, CURLINFO_HTTP_CODE); + $curlError = curl_errno($ch); + $curlErrorMessage = curl_error($ch); if ($decode) { switch (substr($responseType, 0, strpos($responseType, ';'))) { @@ -327,8 +329,11 @@ class Executor } } - if ((curl_errno($ch)/* || 200 != $responseStatus*/)) { - throw new Exception(curl_error($ch) . ' with status code ' . $responseStatus, $responseStatus); + if ($curlError) { + if ($curlError == CURLE_OPERATION_TIMEDOUT) { + throw new AppwriteException(AppwriteException::FUNCTION_SYNCHRONOUS_TIMEOUT); + } + throw new Exception($curlErrorMessage . ' with status code ' . $responseStatus, $responseStatus); } curl_close($ch);