From 0f873792ba844370bbd0d0e9bab2c367769fcf5a Mon Sep 17 00:00:00 2001 From: Bradley Schofield Date: Fri, 14 Feb 2025 17:16:40 +0900 Subject: [PATCH 1/2] Fix build memory and add tests to prevent future regressions --- src/Appwrite/Platform/Workers/Builds.php | 2 +- .../Functions/FunctionsCustomServerTest.php | 43 +++++++++++++++++++ tests/resources/functions/node/index.js | 2 + 3 files changed, 46 insertions(+), 1 deletion(-) diff --git a/src/Appwrite/Platform/Workers/Builds.php b/src/Appwrite/Platform/Workers/Builds.php index c21c28b517..c9833adcfb 100644 --- a/src/Appwrite/Platform/Workers/Builds.php +++ b/src/Appwrite/Platform/Workers/Builds.php @@ -149,7 +149,7 @@ class Builds extends Action } $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; diff --git a/tests/e2e/Services/Functions/FunctionsCustomServerTest.php b/tests/e2e/Services/Functions/FunctionsCustomServerTest.php index d8d1eb8eb5..3ed4ca727e 100644 --- a/tests/e2e/Services/Functions/FunctionsCustomServerTest.php +++ b/tests/e2e/Services/Functions/FunctionsCustomServerTest.php @@ -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); + } } diff --git a/tests/resources/functions/node/index.js b/tests/resources/functions/node/index.js index 041e4a8c12..e8eb938a15 100644 --- a/tests/resources/functions/node/index.js +++ b/tests/resources/functions/node/index.js @@ -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 }); } \ No newline at end of file From 3e5e5453049c32d6712a01084e7528507966b1b2 Mon Sep 17 00:00:00 2001 From: Damodar Lohani Date: Sun, 16 Feb 2025 11:31:46 +0000 Subject: [PATCH 2/2] Fix: image transformations metrics --- .../Platform/Workers/StatsResources.php | 61 +++---------------- 1 file changed, 9 insertions(+), 52 deletions(-) diff --git a/src/Appwrite/Platform/Workers/StatsResources.php b/src/Appwrite/Platform/Workers/StatsResources.php index f5e3d26b2a..a6101522fb 100644 --- a/src/Appwrite/Platform/Workers/StatsResources.php +++ b/src/Appwrite/Platform/Workers/StatsResources.php @@ -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,25 +311,12 @@ 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, - 'time' => $time, - ]); - } - } else { - $time = $period === 'inf' ? 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,