Merge branch 'refactor-usage-sn' of https://github.com/appwrite/appwrite into refactor-usage-sn-collection-not-found-error

 Conflicts:
	composer.lock
	src/Appwrite/Platform/Workers/Deletes.php
This commit is contained in:
fogelito
2024-05-21 11:38:49 +03:00
24 changed files with 210 additions and 135 deletions
+5
View File
@@ -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 => [
+9 -4
View File
@@ -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();
+2 -2
View File
@@ -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'
) ||
+10 -4
View File
@@ -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', '');
@@ -725,6 +730,7 @@ App::error()
$classname = '\\Utopia\\Logger\\Adapter\\' . \ucfirst($providerName);
$adapter = new $classname($providerConfig);
$logger = new Logger($adapter);
$logger->setSample(0.04);
$publish = true;
}
}
+1 -1
View File
@@ -32,7 +32,7 @@ $http = new Server(
mode: SWOOLE_PROCESS,
);
$payloadSize = 6 * (1024 * 1024); // 6MB
$payloadSize = 12 * (1024 * 1024); // 12MB - adding slight buffer for headers and other data that might be sent with the payload - update later with valid testing
$workerNumber = swoole_cpu_num() * intval(System::getEnv('_APP_WORKER_PER_CORE', 6));
$http
+11 -1
View File
@@ -203,7 +203,7 @@ const APP_AUTH_TYPE_JWT = 'JWT';
const APP_AUTH_TYPE_KEY = 'Key';
const APP_AUTH_TYPE_ADMIN = 'Admin';
// Response related
const MAX_OUTPUT_CHUNK_SIZE = 2 * 1024 * 1024; // 2MB
const MAX_OUTPUT_CHUNK_SIZE = 10 * 1024 * 1024; // 10MB
// Function headers
const FUNCTION_ALLOWLIST_HEADERS_REQUEST = ['content-type', 'agent', 'content-length', 'host'];
const FUNCTION_ALLOWLIST_HEADERS_RESPONSE = ['content-type', 'content-length'];
@@ -735,6 +735,16 @@ $register->set('logger', function () {
throw new Exception(Exception::GENERAL_SERVER_ERROR, "Logging provider not supported. Logging is disabled");
}
// Old Sentry Format conversion. Fallback until the old syntax is completely deprecated.
if (str_contains($providerConfig, ';') && strtolower($providerName) == 'sentry') {
$configChunks = \explode(";", $providerConfig);
$sentryKey = $configChunks[0];
$projectId = $configChunks[1];
$providerConfig = 'https://' . $sentryKey . '@sentry.io/' . $projectId;
}
$classname = '\\Utopia\\Logger\\Adapter\\' . \ucfirst($providerName);
$adapter = new $classname($providerConfig);
return new Logger($adapter);
+49 -43
View File
@@ -268,54 +268,54 @@ $server->onWorkerStart(function (int $workerId) use ($server, $register, $stats,
/**
* Sending current connections to project channels on the console project every 5 seconds.
*/
if ($realtime->hasSubscriber('console', Role::users()->toString(), 'project')) {
$database = getConsoleDB();
// if ($realtime->hasSubscriber('console', Role::users()->toString(), 'project')) {
// $database = getConsoleDB();
$payload = [];
// $payload = [];
$list = Authorization::skip(fn () => $database->find('realtime', [
Query::greaterThan('timestamp', DateTime::addSeconds(new \DateTime(), -15)),
]));
// $list = Authorization::skip(fn () => $database->find('realtime', [
// Query::greaterThan('timestamp', DateTime::addSeconds(new \DateTime(), -15)),
// ]));
/**
* Aggregate stats across containers.
*/
foreach ($list as $document) {
foreach (json_decode($document->getAttribute('value')) as $projectId => $value) {
if (array_key_exists($projectId, $payload)) {
$payload[$projectId] += $value;
} else {
$payload[$projectId] = $value;
}
}
}
// /**
// * Aggregate stats across containers.
// */
// foreach ($list as $document) {
// foreach (json_decode($document->getAttribute('value')) as $projectId => $value) {
// if (array_key_exists($projectId, $payload)) {
// $payload[$projectId] += $value;
// } else {
// $payload[$projectId] = $value;
// }
// }
// }
foreach ($stats as $projectId => $value) {
if (!array_key_exists($projectId, $payload)) {
continue;
}
// foreach ($stats as $projectId => $value) {
// if (!array_key_exists($projectId, $payload)) {
// continue;
// }
$event = [
'project' => 'console',
'roles' => ['team:' . $stats->get($projectId, 'teamId')],
'data' => [
'events' => ['stats.connections'],
'channels' => ['project'],
'timestamp' => DateTime::formatTz(DateTime::now()),
'payload' => [
$projectId => $payload[$projectId]
]
]
];
// $event = [
// 'project' => 'console',
// 'roles' => ['team:' . $stats->get($projectId, 'teamId')],
// 'data' => [
// 'events' => ['stats.connections'],
// 'channels' => ['project'],
// 'timestamp' => DateTime::formatTz(DateTime::now()),
// 'payload' => [
// $projectId => $payload[$projectId]
// ]
// ]
// ];
$server->send($realtime->getSubscribers($event), json_encode([
'type' => 'event',
'data' => $event['data']
]));
}
// $server->send($realtime->getSubscribers($event), json_encode([
// 'type' => 'event',
// 'data' => $event['data']
// ]));
// }
$register->get('pools')->reclaim();
}
// $register->get('pools')->reclaim();
// }
/**
* Sending test message for SDK E2E tests every 5 seconds.
*/
@@ -511,16 +511,22 @@ $server->onOpen(function (int $connection, SwooleRequest $request) use ($server,
} catch (Throwable $th) {
call_user_func($logError, $th, "initServer");
// Handle SQL error code is 'HY000'
$code = $th->getCode();
if (!is_int($code)) {
$code = 500;
}
$response = [
'type' => 'error',
'data' => [
'code' => $th->getCode(),
'code' => $code,
'message' => $th->getMessage()
]
];
$server->send([$connection], json_encode($response));
$server->close($connection, $th->getCode());
$server->close($connection, $code);
if (App::isDevelopment()) {
Console::error('[Error] Connection Error');
+2 -2
View File
@@ -727,11 +727,11 @@ services:
openruntimes-executor:
container_name: openruntimes-executor
hostname: appwrite-executor
hostname: exc1
<<: *x-logging
restart: unless-stopped
stop_signal: SIGINT
image: openruntimes/executor:0.4.12
image: openruntimes/executor:0.5.5
networks:
- appwrite
- runtimes
+1 -1
View File
@@ -57,7 +57,7 @@
"utopia-php/fetch": "0.2.*",
"utopia-php/image": "0.6.*",
"utopia-php/locale": "0.4.*",
"utopia-php/logger": "0.3.*",
"utopia-php/logger": "0.5.*",
"utopia-php/messaging": "0.10.*",
"utopia-php/migration": "0.4.*",
"utopia-php/orchestration": "0.9.*",
Generated
+27 -27
View File
@@ -4,7 +4,7 @@
"Read more about it at https://getcomposer.org/doc/01-basic-usage.md#installing-dependencies",
"This file is @generated automatically"
],
"content-hash": "6ce62f5b54254e5023c5ace349a0ced7",
"content-hash": "e3975335737921ddfe4e35d891ea222a",
"packages": [
{
"name": "adhocore/jwt",
@@ -1556,16 +1556,16 @@
},
{
"name": "utopia-php/database",
"version": "0.49.7",
"version": "0.49.10",
"source": {
"type": "git",
"url": "https://github.com/utopia-php/database.git",
"reference": "69b9cb52cc81a7f606ea7586f6c0af3394cc3601"
"reference": "216209121bc97a2010f67a39c561fafe1e936bec"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/utopia-php/database/zipball/69b9cb52cc81a7f606ea7586f6c0af3394cc3601",
"reference": "69b9cb52cc81a7f606ea7586f6c0af3394cc3601",
"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.7"
"source": "https://github.com/utopia-php/database/tree/0.49.10"
},
"time": "2024-05-08T09:04:08+00:00"
"time": "2024-05-20T02:14:20+00:00"
},
{
"name": "utopia-php/domains",
@@ -1902,22 +1902,23 @@
},
{
"name": "utopia-php/logger",
"version": "0.3.2",
"version": "0.5.2",
"source": {
"type": "git",
"url": "https://github.com/utopia-php/logger.git",
"reference": "ba763c10688fe2ed715ad2bed3f13d18dfec6253"
"reference": "c6dfdb672e41364c309b0c30dc03bc6d45446dba"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/utopia-php/logger/zipball/ba763c10688fe2ed715ad2bed3f13d18dfec6253",
"reference": "ba763c10688fe2ed715ad2bed3f13d18dfec6253",
"url": "https://api.github.com/repos/utopia-php/logger/zipball/c6dfdb672e41364c309b0c30dc03bc6d45446dba",
"reference": "c6dfdb672e41364c309b0c30dc03bc6d45446dba",
"shasum": ""
},
"require": {
"php": ">=8.0"
},
"require-dev": {
"laravel/pint": "1.2.*",
"phpstan/phpstan": "1.9.x-dev",
"phpunit/phpunit": "^9.3",
"vimeo/psalm": "4.0.1"
@@ -1949,9 +1950,9 @@
],
"support": {
"issues": "https://github.com/utopia-php/logger/issues",
"source": "https://github.com/utopia-php/logger/tree/0.3.2"
"source": "https://github.com/utopia-php/logger/tree/0.5.2"
},
"time": "2023-11-22T14:45:43+00:00"
"time": "2024-05-17T09:32:59+00:00"
},
{
"name": "utopia-php/messaging",
@@ -2005,22 +2006,21 @@
},
{
"name": "utopia-php/migration",
"version": "0.4.1",
"version": "0.4.4",
"source": {
"type": "git",
"url": "https://github.com/utopia-php/migration.git",
"reference": "ae3cfe93f6d313105d226aeb68806660c806a925"
"reference": "a8a5d392bebf082faf289f4dfe09d9fd76844c33"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/utopia-php/migration/zipball/ae3cfe93f6d313105d226aeb68806660c806a925",
"reference": "ae3cfe93f6d313105d226aeb68806660c806a925",
"url": "https://api.github.com/repos/utopia-php/migration/zipball/a8a5d392bebf082faf289f4dfe09d9fd76844c33",
"reference": "a8a5d392bebf082faf289f4dfe09d9fd76844c33",
"shasum": ""
},
"require": {
"appwrite/appwrite": "10.1.0",
"php": "8.*",
"utopia-php/cli": "0.*"
"php": "8.*"
},
"require-dev": {
"laravel/pint": "1.*",
@@ -2047,9 +2047,9 @@
],
"support": {
"issues": "https://github.com/utopia-php/migration/issues",
"source": "https://github.com/utopia-php/migration/tree/0.4.1"
"source": "https://github.com/utopia-php/migration/tree/0.4.4"
},
"time": "2024-05-01T13:19:18+00:00"
"time": "2024-05-17T05:25:31+00:00"
},
{
"name": "utopia-php/mongo",
@@ -2823,16 +2823,16 @@
"packages-dev": [
{
"name": "appwrite/sdk-generator",
"version": "0.38.2",
"version": "0.38.5",
"source": {
"type": "git",
"url": "https://github.com/appwrite/sdk-generator.git",
"reference": "51284668529e2b10ed933412a42b603c76cded23"
"reference": "830a46cc8e34ee096a76d4af6f00adf008a7cbf8"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/appwrite/sdk-generator/zipball/51284668529e2b10ed933412a42b603c76cded23",
"reference": "51284668529e2b10ed933412a42b603c76cded23",
"url": "https://api.github.com/repos/appwrite/sdk-generator/zipball/830a46cc8e34ee096a76d4af6f00adf008a7cbf8",
"reference": "830a46cc8e34ee096a76d4af6f00adf008a7cbf8",
"shasum": ""
},
"require": {
@@ -2868,9 +2868,9 @@
"description": "Appwrite PHP library for generating API SDKs for multiple programming languages and platforms",
"support": {
"issues": "https://github.com/appwrite/sdk-generator/issues",
"source": "https://github.com/appwrite/sdk-generator/tree/0.38.2"
"source": "https://github.com/appwrite/sdk-generator/tree/0.38.5"
},
"time": "2024-04-25T07:49:29+00:00"
"time": "2024-05-17T00:59:59+00:00"
},
{
"name": "doctrine/deprecations",
+3 -3
View File
@@ -791,10 +791,10 @@ services:
openruntimes-executor:
container_name: openruntimes-executor
hostname: appwrite-executor
hostname: exc1
<<: *x-logging
stop_signal: SIGINT
image: openruntimes/executor:0.5.1
image: openruntimes/executor:0.5.5
restart: unless-stopped
networks:
- appwrite
@@ -857,7 +857,7 @@ services:
- OPR_PROXY_LOGGING_PROVIDER=$_APP_LOGGING_PROVIDER
- OPR_PROXY_LOGGING_CONFIG=$_APP_LOGGING_CONFIG
- OPR_PROXY_ALGORITHM=random
- OPR_PROXY_EXECUTORS=appwrite-executor
- OPR_PROXY_EXECUTORS=exc1
- OPR_PROXY_HEALTHCHECK_INTERVAL=10000
- OPR_PROXY_MAX_TIMEOUT=600
- OPR_PROXY_HEALTHCHECK=enabled
+1 -1
View File
@@ -263,7 +263,7 @@ class Phpass extends Hash
*/
$itoa64 = './ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789';
$output = '$2a$';
$output .= chr(ord('0') + $options['iteration_count_log2'] / 10);
$output .= chr(ord('0') + intval($options['iteration_count_log2'] / 10));
$output .= chr(ord('0') + $options['iteration_count_log2'] % 10);
$output .= '$';
$i = 0;
+1 -1
View File
@@ -34,7 +34,7 @@ class Event extends Validator
public function isValid($value): bool
{
$events = Config::getParam('events', []);
$parts = \explode('.', $value);
$parts = \explode('.', $value ?? '');
$count = \count($parts);
if ($count < 2 || $count > 7) {
@@ -13,7 +13,7 @@ class FunctionEvent extends Event
*/
public function isValid($value): bool
{
if (str_starts_with($value, 'functions.')) {
if (str_starts_with($value ?? false, 'functions.')) {
$this->message = 'Triggering a function on a function event is not allowed.';
return false;
}
+1
View File
@@ -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';
+2
View File
@@ -433,6 +433,8 @@ class Builds extends Action
throw new \Exception('Build not found', 404);
}
$logs = \mb_substr($logs, 0, null, 'UTF-8'); // Get only valid UTF8 part - removes leftover half-multibytes causing SQL errors
$build = $build->setAttribute('logs', $build->getAttribute('logs', '') . $logs);
$build = $dbForProject->updateDocument('builds', $build->getId(), $build);
+56 -23
View File
@@ -12,6 +12,7 @@ use Utopia\Audit\Audit;
use Utopia\Cache\Adapter\Filesystem;
use Utopia\Cache\Cache;
use Utopia\CLI\Console;
use Utopia\Config\Config;
use Utopia\Database\Database;
use Utopia\Database\DateTime;
use Utopia\Database\Document;
@@ -21,6 +22,7 @@ use Utopia\Database\Exception\Conflict;
use Utopia\Database\Exception\Restricted;
use Utopia\Database\Exception\Structure;
use Utopia\Database\Query;
use Utopia\DSN\DSN;
use Utopia\Logger\Log;
use Utopia\Platform\Action;
use Utopia\Queue\Message;
@@ -441,7 +443,7 @@ class Deletes extends Action
* @param Document $document
* @return void
* @throws Authorization
* @throws \Utopia\Database\Exception
* @throws DatabaseException
* @throws Conflict
* @throws Restricted
* @throws Structure
@@ -469,26 +471,49 @@ class Deletes extends Action
* @return void
* @throws Exception
* @throws Authorization
* @throws \Utopia\Database\Exception
* @throws DatabaseException
*/
private function deleteProject(Database $dbForConsole, callable $getProjectDB, Device $deviceForFiles, Device $deviceForFunctions, Device $deviceForBuilds, Device $deviceForCache, Document $document): void
{
$projectId = $document->getId();
$projectInternalId = $document->getInternalId();
// Delete project tables
try {
$dsn = new DSN($document->getAttribute('database', 'console'));
} catch (\InvalidArgumentException) {
// TODO: Temporary until all projects are using shared tables
$dsn = new DSN('mysql://' . $document->getAttribute('database', 'console'));
}
/** @var Database $dbForProject */
$dbForProject = $getProjectDB($document);
while (true) {
$collections = $dbForProject->listCollections();
$projectCollectionIds = [
...\array_keys(Config::getParam('collections', [])['projects']),
Audit::COLLECTION,
TimeLimit::COLLECTION,
];
if (empty($collections)) {
break;
}
$limit = \count($projectCollectionIds) + 25;
while (true) {
$collections = $dbForProject->listCollections($limit);
foreach ($collections as $collection) {
$dbForProject->deleteCollection($collection->getId());
if ($dsn->getHost() !== DATABASE_SHARED_TABLES || !\in_array($collection->getId(), $projectCollectionIds)) {
$dbForProject->deleteCollection($collection->getId());
} else {
$this->deleteByGroup($collection->getId(), [], database: $dbForProject);
}
}
if ($dsn->getHost() === DATABASE_SHARED_TABLES) {
$collectionsIds = \array_map(fn ($collection) => $collection->getId(), $collections);
if (empty(\array_diff($collectionsIds, $projectCollectionIds))) {
break;
}
} elseif (empty($collections)) {
break;
}
}
@@ -524,17 +549,16 @@ class Deletes extends Action
Query::equal('projectInternalId', [$projectInternalId]),
], $dbForConsole);
// Delete VCS commments
// Delete VCS comments
$this->deleteByGroup('vcsComments', [
Query::equal('projectInternalId', [$projectInternalId]),
], $dbForConsole);
// Delete metadata tables
try {
// Delete metadata table
if ($dsn->getHost() !== DATABASE_SHARED_TABLES) {
$dbForProject->deleteCollection('_metadata');
} catch (\Throwable) {
// Ignore: deleteCollection tries to delete a metadata entry after the collection is deleted,
// which will throw an exception here because the metadata collection is already deleted.
} else {
$this->deleteByGroup('_metadata', [], $dbForProject);
}
// Delete all storage directories
@@ -661,9 +685,11 @@ class Deletes extends Action
$dbForProject = $getProjectDB($project);
$timeLimit = new TimeLimit("", 0, 1, $dbForProject);
$abuse = new Abuse($timeLimit);
$status = $abuse->cleanup($abuseRetention);
if (!$status) {
throw new Exception('Failed to delete Abuse logs for project ' . $projectId);
try {
$abuse->cleanup($abuseRetention);
} catch (DatabaseException $e) {
Console::error('Failed to delete abuse logs for project ' . $projectId . ': ' . $e->getMessage());
}
}
@@ -679,9 +705,11 @@ class Deletes extends Action
$projectId = $project->getId();
$dbForProject = $getProjectDB($project);
$audit = new Audit($dbForProject);
$status = $audit->cleanup($auditRetention);
if (!$status) {
throw new Exception('Failed to delete Audit logs for project' . $projectId);
try {
$audit->cleanup($auditRetention);
} catch (DatabaseException $e) {
Console::error('Failed to delete audit logs for project ' . $projectId . ': ' . $e->getMessage());
}
}
@@ -936,7 +964,12 @@ class Deletes extends Action
while ($sum === $limit) {
$chunk++;
$results = $database->find($collection, \array_merge([Query::limit($limit)], $queries));
try {
$results = $database->find($collection, [Query::limit($limit), ...$queries]);
} catch (DatabaseException $e) {
Console::error('Failed to find documents for collection ' . $collection . ': ' . $e->getMessage());
return;
}
$sum = count($results);
+2 -2
View File
@@ -25,7 +25,7 @@ use Utopia\Messaging\Adapter\SMS as SMSAdapter;
use Utopia\Messaging\Adapter\SMS\Mock;
use Utopia\Messaging\Adapter\SMS\Msg91;
use Utopia\Messaging\Adapter\SMS\Telesign;
use Utopia\Messaging\Adapter\SMS\Textmagic;
use Utopia\Messaging\Adapter\SMS\TextMagic;
use Utopia\Messaging\Adapter\SMS\Twilio;
use Utopia\Messaging\Adapter\SMS\Vonage;
use Utopia\Messaging\Messages\Email;
@@ -459,7 +459,7 @@ class Messaging extends Action
return match ($provider->getAttribute('provider')) {
'mock' => new Mock('username', 'password'),
'twilio' => new Twilio($credentials['accountSid'], $credentials['authToken']),
'textmagic' => new Textmagic($credentials['username'], $credentials['apiKey']),
'textmagic' => new TextMagic($credentials['username'], $credentials['apiKey']),
'telesign' => new Telesign($credentials['customerId'], $credentials['apiKey']),
'msg91' => new Msg91($credentials['senderId'], $credentials['authKey'], $credentials['templateId']),
'vonage' => new Vonage($credentials['apiKey'], $credentials['apiSecret']),
+8 -3
View File
@@ -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);
+12 -11
View File
@@ -2128,16 +2128,17 @@ trait DatabasesBase
// Todo: Not sure what to do we with Query length Test VS old? JSON validator will fails if query string will be truncated?
//$this->assertEquals(400, $documents['headers']['status-code']);
$documents = $this->client->call(Client::METHOD_GET, '/databases/' . $databaseId . '/collections/' . $data['moviesId'] . '/documents', array_merge([
'content-type' => 'application/json',
'x-appwrite-project' => $this->getProject()['$id'],
], $this->getHeaders()), [
'queries' => [
Query::search('actors', 'Tom')->toString(),
],
]);
$this->assertEquals(400, $documents['headers']['status-code']);
$this->assertEquals('Invalid query: Cannot query search on attribute "actors" because it is an array.', $documents['body']['message']);
// Todo: Disabled for CL - Uncomment after ProxyDatabase cleanup for find method
// $documents = $this->client->call(Client::METHOD_GET, '/databases/' . $databaseId . '/collections/' . $data['moviesId'] . '/documents', array_merge([
// 'content-type' => 'application/json',
// 'x-appwrite-project' => $this->getProject()['$id'],
// ], $this->getHeaders()), [
// 'queries' => [
// Query::search('actors', 'Tom')->toString(),
// ],
// ]);
// $this->assertEquals(400, $documents['headers']['status-code']);
// $this->assertEquals('Invalid query: Cannot query search on attribute "actors" because it is an array.', $documents['body']['message']);
return [];
}
@@ -4401,7 +4402,7 @@ trait DatabasesBase
Query::isNotNull('$id')->toString(),
Query::startsWith('fullName', 'Stevie')->toString(),
Query::endsWith('fullName', 'Wonder')->toString(),
Query::between('$createdAt', '1975-12-06', '2050-12-0')->toString(),
Query::between('$createdAt', '1975-12-06', '2050-12-01')->toString(),
],
]);
@@ -297,6 +297,7 @@ class TeamsServerTest extends Scope
$this->assertEquals(204, $team['headers']['status-code']);
}
/** @group cl-ignore */
public function testDeleteTeam()
{
$team = $this->testCreateTeam();
@@ -951,7 +951,7 @@ class ProjectsConsoleClientTest extends Scope
public function testUpdateProjectOAuth($data): array
{
$id = $data['projectId'] ?? '';
$providers = require('app/config/oAuthProviders.php');
$providers = require(__DIR__ . '/../../../../app/config/oAuthProviders.php');
/**
* Test for SUCCESS
@@ -1317,7 +1317,7 @@ class RealtimeCustomClientTest extends Scope
'x-appwrite-key' => $this->getProject()['apiKey']
]), []);
$this->assertEquals($response['headers']['status-code'], 200);
$this->assertEquals(200, $response['headers']['status-code']);
$this->assertNotEmpty($response['body']['$id']);
$execution = $this->client->call(Client::METHOD_POST, '/functions/' . $functionId . '/executions', array_merge([
@@ -1327,7 +1327,7 @@ class RealtimeCustomClientTest extends Scope
'async' => true
]);
$this->assertEquals($execution['headers']['status-code'], 202);
$this->assertEquals(202, $execution['headers']['status-code']);
$this->assertNotEmpty($execution['body']['$id']);
$response = json_decode($client->receive(), true);
+2 -2
View File
@@ -125,11 +125,11 @@ trait StorageBase
/**
* Failure
* Test for Chunk above 5MB
* Test for Chunk above 10MB
*/
$source = __DIR__ . "/../../../resources/disk-a/large-file.mp4";
$totalSize = \filesize($source);
$chunkSize = 6 * 1024 * 1024;
$chunkSize = 12 * 1024 * 1024;
$handle = @fopen($source, "rb");
$fileId = 'unique()';
$mimeType = mime_content_type($source);