mirror of
https://github.com/appwrite/appwrite
synced 2026-05-23 00:49:02 +00:00
Merge remote-tracking branch 'origin/1.6.x' into feat-key-segmented-usage
# Conflicts: # composer.lock
This commit is contained in:
commit
390cdaa6a5
8 changed files with 173 additions and 117 deletions
|
|
@ -45,13 +45,13 @@
|
|||
"ext-sockets": "*",
|
||||
"appwrite/php-runtimes": "0.16.*",
|
||||
"appwrite/php-clamav": "2.0.*",
|
||||
"utopia-php/abuse": "0.49.*",
|
||||
"utopia-php/abuse": "0.50.*",
|
||||
"utopia-php/analytics": "0.10.*",
|
||||
"utopia-php/audit": "0.49.*",
|
||||
"utopia-php/audit": "0.51.*",
|
||||
"utopia-php/cache": "0.11.*",
|
||||
"utopia-php/cli": "0.15.*",
|
||||
"utopia-php/config": "0.2.*",
|
||||
"utopia-php/database": "0.58.5",
|
||||
"utopia-php/database": "0.59.0",
|
||||
"utopia-php/domains": "0.5.*",
|
||||
"utopia-php/dsn": "0.2.1",
|
||||
"utopia-php/framework": "0.33.*",
|
||||
|
|
|
|||
80
composer.lock
generated
80
composer.lock
generated
|
|
@ -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": "a7081f31ed2111c7b3a5a9c25b69bf80",
|
||||
"content-hash": "b17c58729c4380afcba7714e9bced863",
|
||||
"packages": [
|
||||
{
|
||||
"name": "adhocore/jwt",
|
||||
|
|
@ -3377,16 +3377,16 @@
|
|||
},
|
||||
{
|
||||
"name": "utopia-php/abuse",
|
||||
"version": "0.49.0",
|
||||
"version": "0.50.0",
|
||||
"source": {
|
||||
"type": "git",
|
||||
"url": "https://github.com/utopia-php/abuse.git",
|
||||
"reference": "76612c274b895aa3d4d1fa27557a6402463eea99"
|
||||
"reference": "3ff67819e9de61506c5ca070a70552f7ebe99f80"
|
||||
},
|
||||
"dist": {
|
||||
"type": "zip",
|
||||
"url": "https://api.github.com/repos/utopia-php/abuse/zipball/76612c274b895aa3d4d1fa27557a6402463eea99",
|
||||
"reference": "76612c274b895aa3d4d1fa27557a6402463eea99",
|
||||
"url": "https://api.github.com/repos/utopia-php/abuse/zipball/3ff67819e9de61506c5ca070a70552f7ebe99f80",
|
||||
"reference": "3ff67819e9de61506c5ca070a70552f7ebe99f80",
|
||||
"shasum": ""
|
||||
},
|
||||
"require": {
|
||||
|
|
@ -3394,7 +3394,7 @@
|
|||
"ext-pdo": "*",
|
||||
"ext-redis": "*",
|
||||
"php": ">=8.0",
|
||||
"utopia-php/database": "0.58.*"
|
||||
"utopia-php/database": "0.59.*"
|
||||
},
|
||||
"require-dev": {
|
||||
"laravel/pint": "1.*",
|
||||
|
|
@ -3422,9 +3422,9 @@
|
|||
],
|
||||
"support": {
|
||||
"issues": "https://github.com/utopia-php/abuse/issues",
|
||||
"source": "https://github.com/utopia-php/abuse/tree/0.49.0"
|
||||
"source": "https://github.com/utopia-php/abuse/tree/0.50.0"
|
||||
},
|
||||
"time": "2025-02-04T07:33:59+00:00"
|
||||
"time": "2025-02-12T09:13:59+00:00"
|
||||
},
|
||||
{
|
||||
"name": "utopia-php/analytics",
|
||||
|
|
@ -3474,21 +3474,21 @@
|
|||
},
|
||||
{
|
||||
"name": "utopia-php/audit",
|
||||
"version": "0.49.0",
|
||||
"version": "0.51.0",
|
||||
"source": {
|
||||
"type": "git",
|
||||
"url": "https://github.com/utopia-php/audit.git",
|
||||
"reference": "9d5c5e0cf0f6d9157b911fc3971da4331d71c96d"
|
||||
"reference": "a5a4b73a57e27a0fac8025b1d6038e145a1ca04e"
|
||||
},
|
||||
"dist": {
|
||||
"type": "zip",
|
||||
"url": "https://api.github.com/repos/utopia-php/audit/zipball/9d5c5e0cf0f6d9157b911fc3971da4331d71c96d",
|
||||
"reference": "9d5c5e0cf0f6d9157b911fc3971da4331d71c96d",
|
||||
"url": "https://api.github.com/repos/utopia-php/audit/zipball/a5a4b73a57e27a0fac8025b1d6038e145a1ca04e",
|
||||
"reference": "a5a4b73a57e27a0fac8025b1d6038e145a1ca04e",
|
||||
"shasum": ""
|
||||
},
|
||||
"require": {
|
||||
"php": ">=8.0",
|
||||
"utopia-php/database": "0.58.*"
|
||||
"utopia-php/database": "0.59.*"
|
||||
},
|
||||
"require-dev": {
|
||||
"laravel/pint": "1.*",
|
||||
|
|
@ -3515,9 +3515,9 @@
|
|||
],
|
||||
"support": {
|
||||
"issues": "https://github.com/utopia-php/audit/issues",
|
||||
"source": "https://github.com/utopia-php/audit/tree/0.49.0"
|
||||
"source": "https://github.com/utopia-php/audit/tree/0.51.0"
|
||||
},
|
||||
"time": "2025-02-04T07:27:18+00:00"
|
||||
"time": "2025-02-12T09:12:44+00:00"
|
||||
},
|
||||
{
|
||||
"name": "utopia-php/cache",
|
||||
|
|
@ -3717,16 +3717,16 @@
|
|||
},
|
||||
{
|
||||
"name": "utopia-php/database",
|
||||
"version": "0.58.5",
|
||||
"version": "0.59.0",
|
||||
"source": {
|
||||
"type": "git",
|
||||
"url": "https://github.com/utopia-php/database.git",
|
||||
"reference": "55308014c697639c6cb270cb5a33cc88fc1ef839"
|
||||
"reference": "0eed7f1ad3eb66ff4a7d73b68dd9d3e05089eb18"
|
||||
},
|
||||
"dist": {
|
||||
"type": "zip",
|
||||
"url": "https://api.github.com/repos/utopia-php/database/zipball/55308014c697639c6cb270cb5a33cc88fc1ef839",
|
||||
"reference": "55308014c697639c6cb270cb5a33cc88fc1ef839",
|
||||
"url": "https://api.github.com/repos/utopia-php/database/zipball/0eed7f1ad3eb66ff4a7d73b68dd9d3e05089eb18",
|
||||
"reference": "0eed7f1ad3eb66ff4a7d73b68dd9d3e05089eb18",
|
||||
"shasum": ""
|
||||
},
|
||||
"require": {
|
||||
|
|
@ -3767,9 +3767,9 @@
|
|||
],
|
||||
"support": {
|
||||
"issues": "https://github.com/utopia-php/database/issues",
|
||||
"source": "https://github.com/utopia-php/database/tree/0.58.5"
|
||||
"source": "https://github.com/utopia-php/database/tree/0.59.0"
|
||||
},
|
||||
"time": "2025-02-10T08:26:52+00:00"
|
||||
"time": "2025-02-12T08:08:29+00:00"
|
||||
},
|
||||
{
|
||||
"name": "utopia-php/domains",
|
||||
|
|
@ -4170,16 +4170,16 @@
|
|||
},
|
||||
{
|
||||
"name": "utopia-php/migration",
|
||||
"version": "0.6.17",
|
||||
"version": "0.6.19",
|
||||
"source": {
|
||||
"type": "git",
|
||||
"url": "https://github.com/utopia-php/migration.git",
|
||||
"reference": "677a5c4688d7f54d1631a91f76a35d51346cf96b"
|
||||
"reference": "3c9497f7a54ef88b1077c48d8326893133ad78eb"
|
||||
},
|
||||
"dist": {
|
||||
"type": "zip",
|
||||
"url": "https://api.github.com/repos/utopia-php/migration/zipball/677a5c4688d7f54d1631a91f76a35d51346cf96b",
|
||||
"reference": "677a5c4688d7f54d1631a91f76a35d51346cf96b",
|
||||
"url": "https://api.github.com/repos/utopia-php/migration/zipball/3c9497f7a54ef88b1077c48d8326893133ad78eb",
|
||||
"reference": "3c9497f7a54ef88b1077c48d8326893133ad78eb",
|
||||
"shasum": ""
|
||||
},
|
||||
"require": {
|
||||
|
|
@ -4187,7 +4187,7 @@
|
|||
"ext-curl": "*",
|
||||
"ext-openssl": "*",
|
||||
"php": ">=8.1",
|
||||
"utopia-php/database": "0.58.*",
|
||||
"utopia-php/database": "0.59.*",
|
||||
"utopia-php/dsn": "0.2.*",
|
||||
"utopia-php/framework": "0.33.*",
|
||||
"utopia-php/storage": "0.18.*"
|
||||
|
|
@ -4220,9 +4220,9 @@
|
|||
],
|
||||
"support": {
|
||||
"issues": "https://github.com/utopia-php/migration/issues",
|
||||
"source": "https://github.com/utopia-php/migration/tree/0.6.17"
|
||||
"source": "https://github.com/utopia-php/migration/tree/0.6.19"
|
||||
},
|
||||
"time": "2025-02-05T05:27:29+00:00"
|
||||
"time": "2025-02-13T07:50:21+00:00"
|
||||
},
|
||||
{
|
||||
"name": "utopia-php/mongo",
|
||||
|
|
@ -5560,16 +5560,16 @@
|
|||
},
|
||||
{
|
||||
"name": "myclabs/deep-copy",
|
||||
"version": "1.12.1",
|
||||
"version": "1.13.0",
|
||||
"source": {
|
||||
"type": "git",
|
||||
"url": "https://github.com/myclabs/DeepCopy.git",
|
||||
"reference": "123267b2c49fbf30d78a7b2d333f6be754b94845"
|
||||
"reference": "024473a478be9df5fdaca2c793f2232fe788e414"
|
||||
},
|
||||
"dist": {
|
||||
"type": "zip",
|
||||
"url": "https://api.github.com/repos/myclabs/DeepCopy/zipball/123267b2c49fbf30d78a7b2d333f6be754b94845",
|
||||
"reference": "123267b2c49fbf30d78a7b2d333f6be754b94845",
|
||||
"url": "https://api.github.com/repos/myclabs/DeepCopy/zipball/024473a478be9df5fdaca2c793f2232fe788e414",
|
||||
"reference": "024473a478be9df5fdaca2c793f2232fe788e414",
|
||||
"shasum": ""
|
||||
},
|
||||
"require": {
|
||||
|
|
@ -5608,7 +5608,7 @@
|
|||
],
|
||||
"support": {
|
||||
"issues": "https://github.com/myclabs/DeepCopy/issues",
|
||||
"source": "https://github.com/myclabs/DeepCopy/tree/1.12.1"
|
||||
"source": "https://github.com/myclabs/DeepCopy/tree/1.13.0"
|
||||
},
|
||||
"funding": [
|
||||
{
|
||||
|
|
@ -5616,7 +5616,7 @@
|
|||
"type": "tidelift"
|
||||
}
|
||||
],
|
||||
"time": "2024-11-08T17:47:46+00:00"
|
||||
"time": "2025-02-12T12:17:51+00:00"
|
||||
},
|
||||
{
|
||||
"name": "nikic/php-parser",
|
||||
|
|
@ -6190,16 +6190,16 @@
|
|||
},
|
||||
{
|
||||
"name": "phpstan/phpdoc-parser",
|
||||
"version": "2.0.0",
|
||||
"version": "2.0.1",
|
||||
"source": {
|
||||
"type": "git",
|
||||
"url": "https://github.com/phpstan/phpdoc-parser.git",
|
||||
"reference": "c00d78fb6b29658347f9d37ebe104bffadf36299"
|
||||
"reference": "72e51f7c32c5aef7c8b462195b8c599b11199893"
|
||||
},
|
||||
"dist": {
|
||||
"type": "zip",
|
||||
"url": "https://api.github.com/repos/phpstan/phpdoc-parser/zipball/c00d78fb6b29658347f9d37ebe104bffadf36299",
|
||||
"reference": "c00d78fb6b29658347f9d37ebe104bffadf36299",
|
||||
"url": "https://api.github.com/repos/phpstan/phpdoc-parser/zipball/72e51f7c32c5aef7c8b462195b8c599b11199893",
|
||||
"reference": "72e51f7c32c5aef7c8b462195b8c599b11199893",
|
||||
"shasum": ""
|
||||
},
|
||||
"require": {
|
||||
|
|
@ -6231,9 +6231,9 @@
|
|||
"description": "PHPDoc parser with support for nullable, intersection and generic types",
|
||||
"support": {
|
||||
"issues": "https://github.com/phpstan/phpdoc-parser/issues",
|
||||
"source": "https://github.com/phpstan/phpdoc-parser/tree/2.0.0"
|
||||
"source": "https://github.com/phpstan/phpdoc-parser/tree/2.0.1"
|
||||
},
|
||||
"time": "2024-10-13T11:29:49+00:00"
|
||||
"time": "2025-02-13T12:25:43+00:00"
|
||||
},
|
||||
{
|
||||
"name": "phpunit/php-code-coverage",
|
||||
|
|
|
|||
|
|
@ -6,15 +6,33 @@ use Appwrite\Auth\Auth;
|
|||
use Exception;
|
||||
use Throwable;
|
||||
use Utopia\Audit\Audit;
|
||||
use Utopia\CLI\Console;
|
||||
use Utopia\Database\Database;
|
||||
use Utopia\Database\DateTime;
|
||||
use Utopia\Database\Document;
|
||||
use Utopia\Database\Exception\Authorization;
|
||||
use Utopia\Database\Exception\Structure;
|
||||
use Utopia\Platform\Action;
|
||||
use Utopia\Queue\Message;
|
||||
use Utopia\System\System;
|
||||
|
||||
class Audits extends Action
|
||||
{
|
||||
private const BATCH_SIZE_DEVELOPMENT = 1; // smaller batch size for development
|
||||
private const BATCH_SIZE_PRODUCTION = 5_000;
|
||||
private const BATCH_AGGREGATION_INTERVAL = 60; // in seconds
|
||||
|
||||
private int $lastTriggeredTime = 0;
|
||||
|
||||
private array $logs = [];
|
||||
|
||||
private function getBatchSize(): int
|
||||
{
|
||||
return System::getEnv('_APP_ENV', 'development') === 'development'
|
||||
? self::BATCH_SIZE_DEVELOPMENT
|
||||
: self::BATCH_SIZE_PRODUCTION;
|
||||
}
|
||||
|
||||
public static function getName(): string
|
||||
{
|
||||
return 'audits';
|
||||
|
|
@ -30,6 +48,8 @@ class Audits extends Action
|
|||
->inject('message')
|
||||
->inject('dbForProject')
|
||||
->callback(fn ($message, $dbForProject) => $this->action($message, $dbForProject));
|
||||
|
||||
$this->lastTriggeredTime = time();
|
||||
}
|
||||
|
||||
|
||||
|
|
@ -44,13 +64,14 @@ class Audits extends Action
|
|||
*/
|
||||
public function action(Message $message, Database $dbForProject): void
|
||||
{
|
||||
|
||||
$payload = $message->getPayload() ?? [];
|
||||
|
||||
if (empty($payload)) {
|
||||
throw new Exception('Missing payload');
|
||||
}
|
||||
|
||||
Console::info('Aggregating audit logs');
|
||||
|
||||
$event = $payload['event'] ?? '';
|
||||
$auditPayload = $payload['payload'] ?? '';
|
||||
$mode = $payload['mode'] ?? '';
|
||||
|
|
@ -63,23 +84,48 @@ class Audits extends Action
|
|||
$userEmail = $user->getAttribute('email', '');
|
||||
$userType = $user->getAttribute('type', Auth::ACTIVITY_TYPE_USER);
|
||||
|
||||
$audit = new Audit($dbForProject);
|
||||
$audit->log(
|
||||
userId: $user->getInternalId(),
|
||||
// Pass first, most verbose event pattern
|
||||
event: $event,
|
||||
resource: $resource,
|
||||
userAgent: $userAgent,
|
||||
ip: $ip,
|
||||
location: '',
|
||||
data: [
|
||||
// Create event data
|
||||
$eventData = [
|
||||
'userId' => $user->getInternalId(),
|
||||
'event' => $event,
|
||||
'resource' => $resource,
|
||||
'userAgent' => $userAgent,
|
||||
'ip' => $ip,
|
||||
'location' => '',
|
||||
'data' => [
|
||||
'userId' => $user->getId(),
|
||||
'userName' => $userName,
|
||||
'userEmail' => $userEmail,
|
||||
'userType' => $userType,
|
||||
'mode' => $mode,
|
||||
'data' => $auditPayload,
|
||||
]
|
||||
);
|
||||
],
|
||||
'timestamp' => DateTime::formatTz(DateTime::now())
|
||||
];
|
||||
|
||||
$this->logs[] = $eventData;
|
||||
|
||||
// Check if we should process the batch by checking both for the batch size and the elapsed time
|
||||
$batchSize = $this->getBatchSize();
|
||||
$shouldProcessBatch = count($this->logs) >= $batchSize;
|
||||
if (!$shouldProcessBatch && count($this->logs) > 0) {
|
||||
$shouldProcessBatch = (time() - $this->lastTriggeredTime) >= self::BATCH_AGGREGATION_INTERVAL;
|
||||
}
|
||||
|
||||
if ($shouldProcessBatch) {
|
||||
Console::log('Processing batch with ' . count($this->logs) . ' events');
|
||||
$audit = new Audit($dbForProject);
|
||||
|
||||
try {
|
||||
$audit->logBatch($this->logs);
|
||||
Console::success('Audit logs processed successfully');
|
||||
} catch (Throwable $e) {
|
||||
Console::error('Error processing audit logs: ' . $e->getMessage());
|
||||
} finally {
|
||||
// Clear the pending events after successful batch processing
|
||||
$this->logs = [];
|
||||
$this->lastTriggeredTime = time();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -54,8 +54,10 @@ class Builds extends Action
|
|||
->inject('cache')
|
||||
->inject('dbForProject')
|
||||
->inject('deviceForFunctions')
|
||||
->inject('isResourceBlocked')
|
||||
->inject('log')
|
||||
->callback(fn ($message, Document $project, Database $dbForPlatform, Event $queueForEvents, Func $queueForFunctions, StatsUsage $usage, Cache $cache, Database $dbForProject, Device $deviceForFunctions, Log $log) => $this->action($message, $project, $dbForPlatform, $queueForEvents, $queueForFunctions, $usage, $cache, $dbForProject, $deviceForFunctions, $log));
|
||||
->callback(fn ($message, Document $project, Database $dbForPlatform, Event $queueForEvents, Func $queueForFunctions, StatsUsage $usage, Cache $cache, Database $dbForProject, Device $deviceForFunctions, callable $isResourceBlocked, Log $log) =>
|
||||
$this->action($message, $project, $dbForPlatform, $queueForEvents, $queueForFunctions, $usage, $cache, $dbForProject, $deviceForFunctions, $isResourceBlocked, $log));
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
@ -72,7 +74,7 @@ class Builds extends Action
|
|||
* @return void
|
||||
* @throws \Utopia\Database\Exception
|
||||
*/
|
||||
public function action(Message $message, Document $project, Database $dbForPlatform, Event $queueForEvents, Func $queueForFunctions, StatsUsage $queueForStatsUsage, Cache $cache, Database $dbForProject, Device $deviceForFunctions, Log $log): void
|
||||
public function action(Message $message, Document $project, Database $dbForPlatform, Event $queueForEvents, Func $queueForFunctions, StatsUsage $queueForStatsUsage, Cache $cache, Database $dbForProject, Device $deviceForFunctions, callable $isResourceBlocked, Log $log): void
|
||||
{
|
||||
$payload = $message->getPayload() ?? [];
|
||||
|
||||
|
|
@ -93,7 +95,7 @@ class Builds extends Action
|
|||
case BUILD_TYPE_RETRY:
|
||||
Console::info('Creating build for deployment: ' . $deployment->getId());
|
||||
$github = new GitHub($cache);
|
||||
$this->buildDeployment($deviceForFunctions, $queueForFunctions, $queueForEvents, $queueForStatsUsage, $dbForPlatform, $dbForProject, $github, $project, $resource, $deployment, $template, $log);
|
||||
$this->buildDeployment($deviceForFunctions, $queueForFunctions, $queueForEvents, $queueForStatsUsage, $dbForPlatform, $dbForProject, $github, $project, $resource, $deployment, $template, $isResourceBlocked, $log);
|
||||
break;
|
||||
|
||||
default:
|
||||
|
|
@ -118,7 +120,7 @@ class Builds extends Action
|
|||
* @throws \Utopia\Database\Exception
|
||||
* @throws Exception
|
||||
*/
|
||||
protected function buildDeployment(Device $deviceForFunctions, Func $queueForFunctions, Event $queueForEvents, StatsUsage $queueForStatsUsage, Database $dbForPlatform, Database $dbForProject, GitHub $github, Document $project, Document $function, Document $deployment, Document $template, Log $log): void
|
||||
protected function buildDeployment(Device $deviceForFunctions, Func $queueForFunctions, Event $queueForEvents, StatsUsage $queueForStatsUsage, Database $dbForPlatform, Database $dbForProject, GitHub $github, Document $project, Document $function, Document $deployment, Document $template, callable $isResourceBlocked, Log $log): void
|
||||
{
|
||||
$executor = new Executor(System::getEnv('_APP_EXECUTOR_HOST'));
|
||||
|
||||
|
|
@ -127,7 +129,11 @@ class Builds extends Action
|
|||
|
||||
$function = $dbForProject->getDocument('functions', $functionId);
|
||||
if ($function->isEmpty()) {
|
||||
throw new \Exception('Function not found', 404);
|
||||
throw new \Exception('Function not found');
|
||||
}
|
||||
|
||||
if ($isResourceBlocked($project, RESOURCE_TYPE_FUNCTIONS, $functionId)) {
|
||||
throw new \Exception('Function blocked');
|
||||
}
|
||||
|
||||
$deploymentId = $deployment->getId();
|
||||
|
|
@ -135,15 +141,15 @@ class Builds extends Action
|
|||
|
||||
$deployment = $dbForProject->getDocument('deployments', $deploymentId);
|
||||
if ($deployment->isEmpty()) {
|
||||
throw new \Exception('Deployment not found', 404);
|
||||
throw new \Exception('Deployment not found');
|
||||
}
|
||||
|
||||
if (empty($deployment->getAttribute('entrypoint', ''))) {
|
||||
throw new \Exception('Entrypoint for your Appwrite Function is missing. Please specify it when making deployment or update the entrypoint under your function\'s "Settings" > "Configuration" > "Entrypoint".', 500);
|
||||
throw new \Exception('Entrypoint for your Appwrite Function is missing. Please specify it when making deployment or update the entrypoint under your function\'s "Settings" > "Configuration" > "Entrypoint".');
|
||||
}
|
||||
|
||||
$version = $function->getAttribute('version', 'v2');
|
||||
$spec = Config::getParam('runtime-specifications')[$function->getAttribute('specifications', APP_FUNCTION_SPECIFICATION_DEFAULT)];
|
||||
$spec = Config::getParam('runtime-specifications')[$function->getAttribute('specification', APP_FUNCTION_SPECIFICATION_DEFAULT)];
|
||||
$runtimes = Config::getParam($version === 'v2' ? 'runtimes-v2' : 'runtimes', []);
|
||||
$key = $function->getAttribute('runtime');
|
||||
$runtime = $runtimes[$key] ?? null;
|
||||
|
|
@ -571,7 +577,7 @@ class Builds extends Action
|
|||
$build = $dbForProject->getDocument('builds', $build->getId());
|
||||
|
||||
if ($build->isEmpty()) {
|
||||
throw new \Exception('Build not found', 404);
|
||||
throw new \Exception('Build not found');
|
||||
}
|
||||
|
||||
if ($build->getAttribute('status') === 'canceled') {
|
||||
|
|
|
|||
|
|
@ -214,47 +214,17 @@ class StatsResources extends Action
|
|||
protected function countImageTransformations(Database $dbForProject, Database $dbForLogs, string $region)
|
||||
{
|
||||
$totalImageTransformations = 0;
|
||||
$totalDailyImageTransformations = 0;
|
||||
$totalHourlyImageTransformations = 0;
|
||||
$this->foreachDocument($dbForProject, 'buckets', [], function ($bucket) use ($dbForProject, $dbForLogs, $region, &$totalDailyImageTransformations, &$totalHourlyImageTransformations, &$totalImageTransformations) {
|
||||
$last30Days = (new \DateTime())->sub(\DateInterval::createFromDateString('30 days'))->format('Y-m-d 00:00:00');
|
||||
$this->foreachDocument($dbForProject, 'buckets', [], function ($bucket) use ($dbForProject, $last30Days, $region, &$totalImageTransformations) {
|
||||
$imageTransformations = $dbForProject->count('bucket_' . $bucket->getInternalId(), [
|
||||
Query::isNotNull('transformedAt')
|
||||
Query::greaterThanEqual('transformedAt', $last30Days),
|
||||
]);
|
||||
$metric = str_replace('{bucketInternalId}', $bucket->getInternalId(), METRIC_BUCKET_ID_FILES_IMAGES_TRANSFORMED);
|
||||
$this->createStatsDocuments($region, $metric, $imageTransformations, 'inf');
|
||||
$this->createStatsDocuments($region, $metric, $imageTransformations);
|
||||
$totalImageTransformations += $imageTransformations;
|
||||
|
||||
// hourly
|
||||
$time = \date($this->periods['1h'], \time());
|
||||
$start = $time;
|
||||
$end = (new \DateTime($start))->format('Y-m-d H:59:59');
|
||||
$hourlyImageTransformations = $dbForProject->count('bucket_' . $bucket->getInternalId(), [
|
||||
Query::greaterThanEqual('transformedAt', $start),
|
||||
Query::lessThanEqual('transformedAt', $end),
|
||||
]);
|
||||
$metric = str_replace('{bucketInternalId}', $bucket->getInternalId(), METRIC_BUCKET_ID_FILES_IMAGES_TRANSFORMED);
|
||||
$this->createStatsDocuments($region, $metric, $hourlyImageTransformations, '1h');
|
||||
$totalHourlyImageTransformations += $hourlyImageTransformations;
|
||||
|
||||
// daily
|
||||
$time = \date($this->periods['1d'], \time());
|
||||
$start = $time;
|
||||
$end = (new \DateTime($start))->format('Y-m-d 11:59:59');
|
||||
|
||||
$dailyImageTransformations = $dbForProject->count('bucket_' . $bucket->getInternalId(), [
|
||||
Query::greaterThanEqual('transformedAt', $start),
|
||||
Query::lessThanEqual('transformedAt', $end),
|
||||
]);
|
||||
$metric = str_replace('{bucketInternalId}', $bucket->getInternalId(), METRIC_BUCKET_ID_FILES_IMAGES_TRANSFORMED);
|
||||
$this->createStatsDocuments($region, $metric, $dailyImageTransformations, '1d');
|
||||
$totalDailyImageTransformations += $dailyImageTransformations;
|
||||
|
||||
});
|
||||
|
||||
$this->createStatsDocuments($region, METRIC_FILES_IMAGES_TRANSFORMED, $totalImageTransformations, 'inf');
|
||||
$this->createStatsDocuments($region, METRIC_FILES_IMAGES_TRANSFORMED, $totalDailyImageTransformations, '1d');
|
||||
$this->createStatsDocuments($region, METRIC_FILES_IMAGES_TRANSFORMED, $totalHourlyImageTransformations, '1h');
|
||||
|
||||
$this->createStatsDocuments($region, METRIC_FILES_IMAGES_TRANSFORMED, $totalImageTransformations);
|
||||
}
|
||||
|
||||
protected function countForDatabase(Database $dbForProject, Database $dbForLogs, string $region)
|
||||
|
|
@ -341,30 +311,19 @@ class StatsResources extends Action
|
|||
});
|
||||
}
|
||||
|
||||
protected function createStatsDocuments(string $region, string $metric, int $value, ?string $period = null)
|
||||
protected function createStatsDocuments(string $region, string $metric, int $value)
|
||||
{
|
||||
if ($period === null) {
|
||||
foreach ($this->periods as $period => $format) {
|
||||
$time = 'inf' === $period ? null : \date($format, \time());
|
||||
$id = \md5("{$time}_{$period}_{$metric}");
|
||||
|
||||
$this->documents[] = new Document([
|
||||
'$id' => $id,
|
||||
'metric' => $metric,
|
||||
'period' => $period,
|
||||
'region' => $region,
|
||||
'value' => $value,
|
||||
]);
|
||||
}
|
||||
} else {
|
||||
$time = 'inf' === $period ? null : \date($this->periods[$period], \time());
|
||||
foreach ($this->periods as $period => $format) {
|
||||
$time = 'inf' === $period ? null : \date($format, \time());
|
||||
$id = \md5("{$time}_{$period}_{$metric}");
|
||||
|
||||
$this->documents[] = new Document([
|
||||
'$id' => $id,
|
||||
'metric' => $metric,
|
||||
'period' => $period,
|
||||
'region' => $region,
|
||||
'value' => $value,
|
||||
'time' => $time,
|
||||
]);
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -463,7 +463,7 @@ trait DatabasesBase
|
|||
]);
|
||||
|
||||
$this->assertEquals(400, $attribute['headers']['status-code']);
|
||||
$this->assertEquals('Index length is longer than the maximum: 768', $attribute['body']['message']);
|
||||
$this->assertStringContainsString('Index length is longer than the maximum: 76', $attribute['body']['message']);
|
||||
}
|
||||
|
||||
public function testUpdateAttributeEnum(): void
|
||||
|
|
|
|||
|
|
@ -1984,4 +1984,47 @@ class FunctionsCustomServerTest extends Scope
|
|||
|
||||
$this->cleanupFunction($functionId);
|
||||
}
|
||||
|
||||
public function testFunctionSpecifications()
|
||||
{
|
||||
// Check if the function specifications are correctly set in builds
|
||||
$function = $this->createFunction([
|
||||
'functionId' => ID::unique(),
|
||||
'runtime' => 'node-18.0',
|
||||
'name' => 'Specification Test',
|
||||
'entrypoint' => 'index.js',
|
||||
'logging' => false,
|
||||
'execute' => ['any'],
|
||||
'specification' => Specification::S_2VCPU_2GB,
|
||||
'commands' => 'echo $APPWRITE_FUNCTION_MEMORY:$APPWRITE_FUNCTION_CPUS',
|
||||
]);
|
||||
|
||||
$this->assertEquals(201, $function['headers']['status-code']);
|
||||
$this->assertEquals(Specification::S_2VCPU_2GB, $function['body']['specification']);
|
||||
$this->assertNotEmpty($function['body']['$id']);
|
||||
|
||||
$functionId = $functionId = $function['body']['$id'] ?? '';
|
||||
|
||||
$deploymentId = $this->setupDeployment($functionId, [
|
||||
'code' => $this->packageFunction('node'),
|
||||
'activate' => true
|
||||
]);
|
||||
|
||||
$this->assertEventually(function () use ($functionId, $deploymentId) {
|
||||
$deployment = $this->getDeployment($functionId, $deploymentId);
|
||||
$this->assertTrue(str_contains($deployment['body']['buildLogs'], '2048:2'));
|
||||
}, 10000, 500);
|
||||
|
||||
// Check if the function specifications are correctly set in executions
|
||||
$execution = $this->createExecution($functionId);
|
||||
|
||||
$this->assertEquals(201, $execution['headers']['status-code']);
|
||||
$this->assertNotEmpty($execution['body']['$id']);
|
||||
|
||||
$executionResponse = json_decode($execution['body']['responseBody'], true);
|
||||
$this->assertEquals('2048', $executionResponse['APPWRITE_FUNCTION_MEMORY']);
|
||||
$this->assertEquals('2', $executionResponse['APPWRITE_FUNCTION_CPUS']);
|
||||
|
||||
$this->cleanupFunction($functionId);
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -14,6 +14,8 @@ module.exports = async(context) => {
|
|||
'APPWRITE_FUNCTION_USER_ID' : context.req.headers['x-appwrite-user-id'] ?? '',
|
||||
'APPWRITE_FUNCTION_JWT' : context.req.headers['x-appwrite-user-jwt'] ?? '',
|
||||
'APPWRITE_FUNCTION_PROJECT_ID' : process.env.APPWRITE_FUNCTION_PROJECT_ID,
|
||||
'APPWRITE_FUNCTION_MEMORY' : process.env.APPWRITE_FUNCTION_MEMORY,
|
||||
'APPWRITE_FUNCTION_CPUS' : process.env.APPWRITE_FUNCTION_CPUS,
|
||||
'CUSTOM_VARIABLE' : process.env.CUSTOM_VARIABLE
|
||||
});
|
||||
}
|
||||
Loading…
Reference in a new issue