(perf): Parallelize usage endpoint queries with Promise::map

This commit is contained in:
Jake Barnby
2026-03-25 14:27:06 +13:00
parent fd80884d4f
commit 33566f2052
11 changed files with 155 additions and 77 deletions
+14 -6
View File
@@ -6,6 +6,7 @@ use Appwrite\SDK\ContentType;
use Appwrite\SDK\Method;
use Appwrite\SDK\Response as SDKResponse;
use Appwrite\Utopia\Response;
use Utopia\Async\Promise;
use Utopia\Database\Database;
use Utopia\Database\Document;
use Utopia\Database\Exception\Duplicate as DuplicateException;
@@ -104,20 +105,19 @@ Http::get('/v1/project/usage')
};
$authorization->skip(function () use ($dbForProject, $dbForLogs, $firstDay, $lastDay, $period, $metrics, $limit, &$total, &$stats) {
$tasks = [];
foreach ($metrics['total'] as $metric) {
$db = ($metric === METRIC_FILES_IMAGES_TRANSFORMED) ? $dbForLogs : $dbForProject;
$result = $db->findOne('stats', [
$tasks['total_' . $metric] = fn () => $db->findOne('stats', [
Query::equal('metric', [$metric]),
Query::equal('period', ['inf'])
]);
$total[$metric] = $result['value'] ?? 0;
}
foreach ($metrics['period'] as $metric) {
$db = ($metric === METRIC_FILES_IMAGES_TRANSFORMED) ? $dbForLogs : $dbForProject;
$results = $db->find('stats', [
$tasks['period_' . $metric] = fn () => $db->find('stats', [
Query::equal('metric', [$metric]),
Query::equal('period', [$period]),
Query::greaterThanEqual('time', $firstDay),
@@ -125,9 +125,17 @@ Http::get('/v1/project/usage')
Query::limit($limit),
Query::orderDesc('time'),
]);
}
$results = Promise::map($tasks)->await();
foreach ($metrics['total'] as $metric) {
$total[$metric] = $results['total_' . $metric]['value'] ?? 0;
}
foreach ($metrics['period'] as $metric) {
$stats[$metric] = [];
foreach ($results as $result) {
foreach ($results['period_' . $metric] as $result) {
$stats[$metric][$result->getAttribute('time')] = [
'value' => $result->getAttribute('value'),
];
+15 -8
View File
@@ -29,6 +29,7 @@ use Appwrite\Utopia\Database\Validator\Queries\Users;
use Appwrite\Utopia\Request;
use Appwrite\Utopia\Response;
use MaxMind\Db\Reader;
use Utopia\Async\Promise;
use Utopia\Audit\Audit;
use Utopia\Auth\Hash;
use Utopia\Auth\Hashes\Argon2;
@@ -2709,23 +2710,29 @@ Http::get('/v1/users/usage')
];
$authorization->skip(function () use ($dbForProject, $days, $metrics, &$stats) {
foreach ($metrics as $count => $metric) {
$result = $dbForProject->findOne('stats', [
$limit = $days['limit'];
$period = $days['period'];
$tasks = [];
foreach ($metrics as $metric) {
$tasks[$metric . '_total'] = fn () => $dbForProject->findOne('stats', [
Query::equal('metric', [$metric]),
Query::equal('period', ['inf'])
]);
$stats[$metric]['total'] = $result['value'] ?? 0;
$limit = $days['limit'];
$period = $days['period'];
$results = $dbForProject->find('stats', [
$tasks[$metric . '_data'] = fn () => $dbForProject->find('stats', [
Query::equal('metric', [$metric]),
Query::equal('period', [$period]),
Query::limit($limit),
Query::orderDesc('time'),
]);
}
$results = Promise::map($tasks)->await();
foreach ($metrics as $metric) {
$stats[$metric]['total'] = $results[$metric . '_total']['value'] ?? 0;
$stats[$metric]['data'] = [];
foreach ($results as $result) {
foreach ($results[$metric . '_data'] as $result) {
$stats[$metric]['data'][$result->getAttribute('time')] = [
'value' => $result->getAttribute('value'),
];
@@ -10,6 +10,7 @@ use Appwrite\SDK\Deprecated;
use Appwrite\SDK\Method;
use Appwrite\SDK\Response as SDKResponse;
use Appwrite\Utopia\Response as UtopiaResponse;
use Utopia\Async\Promise;
use Utopia\Config\Config;
use Utopia\Database\Database;
use Utopia\Database\Document;
@@ -85,23 +86,29 @@ class Get extends Action
];
$authorization->skip(function () use ($dbForProject, $days, $metrics, &$stats) {
$limit = $days['limit'];
$period = $days['period'];
$tasks = [];
foreach ($metrics as $metric) {
$result = $dbForProject->findOne('stats', [
$tasks[$metric . '_total'] = fn () => $dbForProject->findOne('stats', [
Query::equal('metric', [$metric]),
Query::equal('period', ['inf'])
]);
$stats[$metric]['total'] = $result['value'] ?? 0;
$limit = $days['limit'];
$period = $days['period'];
$results = $dbForProject->find('stats', [
$tasks[$metric . '_data'] = fn () => $dbForProject->find('stats', [
Query::equal('metric', [$metric]),
Query::equal('period', [$period]),
Query::limit($limit),
Query::orderDesc('time'),
]);
}
$results = Promise::map($tasks)->await();
foreach ($metrics as $metric) {
$stats[$metric]['total'] = $results[$metric . '_total']['value'] ?? 0;
$stats[$metric]['data'] = [];
foreach ($results as $result) {
foreach ($results[$metric . '_data'] as $result) {
$stats[$metric]['data'][$result->getAttribute('time')] = [
'value' => $result->getAttribute('value'),
];
@@ -9,6 +9,7 @@ use Appwrite\SDK\Deprecated;
use Appwrite\SDK\Method;
use Appwrite\SDK\Response as SDKResponse;
use Appwrite\Utopia\Response as UtopiaResponse;
use Utopia\Async\Promise;
use Utopia\Config\Config;
use Utopia\Database\Database;
use Utopia\Database\Document;
@@ -83,23 +84,29 @@ class Get extends Action
];
$authorization->skip(function () use ($dbForProject, $days, $metrics, &$stats) {
$limit = $days['limit'];
$period = $days['period'];
$tasks = [];
foreach ($metrics as $metric) {
$result = $dbForProject->findOne('stats', [
$tasks[$metric . '_total'] = fn () => $dbForProject->findOne('stats', [
Query::equal('metric', [$metric]),
Query::equal('period', ['inf'])
]);
$stats[$metric]['total'] = $result['value'] ?? 0;
$limit = $days['limit'];
$period = $days['period'];
$results = $dbForProject->find('stats', [
$tasks[$metric . '_data'] = fn () => $dbForProject->find('stats', [
Query::equal('metric', [$metric]),
Query::equal('period', [$period]),
Query::limit($limit),
Query::orderDesc('time'),
]);
}
$results = Promise::map($tasks)->await();
foreach ($metrics as $metric) {
$stats[$metric]['total'] = $results[$metric . '_total']['value'] ?? 0;
$stats[$metric]['data'] = [];
foreach ($results as $result) {
foreach ($results[$metric . '_data'] as $result) {
$stats[$metric]['data'][$result->getAttribute('time')] = [
'value' => $result->getAttribute('value'),
];
@@ -8,6 +8,7 @@ use Appwrite\SDK\Deprecated;
use Appwrite\SDK\Method;
use Appwrite\SDK\Response as SDKResponse;
use Appwrite\Utopia\Response as UtopiaResponse;
use Utopia\Async\Promise;
use Utopia\Config\Config;
use Utopia\Database\Database;
use Utopia\Database\Document;
@@ -76,23 +77,29 @@ class XList extends Action
];
$authorization->skip(function () use ($dbForProject, $days, $metrics, &$stats) {
$limit = $days['limit'];
$period = $days['period'];
$tasks = [];
foreach ($metrics as $metric) {
$result = $dbForProject->findOne('stats', [
$tasks[$metric . '_total'] = fn () => $dbForProject->findOne('stats', [
Query::equal('metric', [$metric]),
Query::equal('period', ['inf'])
]);
$stats[$metric]['total'] = $result['value'] ?? 0;
$limit = $days['limit'];
$period = $days['period'];
$results = $dbForProject->find('stats', [
$tasks[$metric . '_data'] = fn () => $dbForProject->find('stats', [
Query::equal('metric', [$metric]),
Query::equal('period', [$period]),
Query::limit($limit),
Query::orderDesc('time'),
]);
}
$results = Promise::map($tasks)->await();
foreach ($metrics as $metric) {
$stats[$metric]['total'] = $results[$metric . '_total']['value'] ?? 0;
$stats[$metric]['data'] = [];
foreach ($results as $result) {
foreach ($results[$metric . '_data'] as $result) {
$stats[$metric]['data'][$result->getAttribute('time')] = [
'value' => $result->getAttribute('value'),
];
@@ -8,6 +8,7 @@ use Appwrite\SDK\AuthType;
use Appwrite\SDK\Method;
use Appwrite\SDK\Response as SDKResponse;
use Appwrite\Utopia\Response;
use Utopia\Async\Promise;
use Utopia\Config\Config;
use Utopia\Database\Database;
use Utopia\Database\Document;
@@ -85,23 +86,29 @@ class Get extends Base
];
$authorization->skip(function () use ($dbForProject, $days, $metrics, &$stats) {
$limit = $days['limit'];
$period = $days['period'];
$tasks = [];
foreach ($metrics as $metric) {
$result = $dbForProject->findOne('stats', [
$tasks[$metric . '_total'] = fn () => $dbForProject->findOne('stats', [
Query::equal('metric', [$metric]),
Query::equal('period', ['inf'])
]);
$stats[$metric]['total'] = $result['value'] ?? 0;
$limit = $days['limit'];
$period = $days['period'];
$results = $dbForProject->find('stats', [
$tasks[$metric . '_data'] = fn () => $dbForProject->find('stats', [
Query::equal('metric', [$metric]),
Query::equal('period', [$period]),
Query::limit($limit),
Query::orderDesc('time'),
]);
}
$results = Promise::map($tasks)->await();
foreach ($metrics as $metric) {
$stats[$metric]['total'] = $results[$metric . '_total']['value'] ?? 0;
$stats[$metric]['data'] = [];
foreach ($results as $result) {
foreach ($results[$metric . '_data'] as $result) {
$stats[$metric]['data'][$result->getAttribute('time')] = [
'value' => $result->getAttribute('value'),
];
@@ -7,6 +7,7 @@ use Appwrite\SDK\AuthType;
use Appwrite\SDK\Method;
use Appwrite\SDK\Response as SDKResponse;
use Appwrite\Utopia\Response;
use Utopia\Async\Promise;
use Utopia\Config\Config;
use Utopia\Database\Database;
use Utopia\Database\Document;
@@ -77,23 +78,29 @@ class XList extends Base
];
$authorization->skip(function () use ($dbForProject, $days, $metrics, &$stats) {
$limit = $days['limit'];
$period = $days['period'];
$tasks = [];
foreach ($metrics as $metric) {
$result = $dbForProject->findOne('stats', [
$tasks[$metric . '_total'] = fn () => $dbForProject->findOne('stats', [
Query::equal('metric', [$metric]),
Query::equal('period', ['inf'])
]);
$stats[$metric]['total'] = $result['value'] ?? 0;
$limit = $days['limit'];
$period = $days['period'];
$results = $dbForProject->find('stats', [
$tasks[$metric . '_data'] = fn () => $dbForProject->find('stats', [
Query::equal('metric', [$metric]),
Query::equal('period', [$period]),
Query::limit($limit),
Query::orderDesc('time'),
]);
}
$results = Promise::map($tasks)->await();
foreach ($metrics as $metric) {
$stats[$metric]['total'] = $results[$metric . '_total']['value'] ?? 0;
$stats[$metric]['data'] = [];
foreach ($results as $result) {
foreach ($results[$metric . '_data'] as $result) {
$stats[$metric]['data'][$result->getAttribute('time')] = [
'value' => $result->getAttribute('value'),
];
@@ -8,6 +8,7 @@ use Appwrite\SDK\AuthType;
use Appwrite\SDK\Method;
use Appwrite\SDK\Response as SDKResponse;
use Appwrite\Utopia\Response;
use Utopia\Async\Promise;
use Utopia\Config\Config;
use Utopia\Database\Database;
use Utopia\Database\Document;
@@ -94,23 +95,29 @@ class Get extends Base
];
$authorization->skip(function () use ($dbForProject, $days, $metrics, &$stats) {
$limit = $days['limit'];
$period = $days['period'];
$tasks = [];
foreach ($metrics as $metric) {
$result = $dbForProject->findOne('stats', [
$tasks[$metric . '_total'] = fn () => $dbForProject->findOne('stats', [
Query::equal('metric', [$metric]),
Query::equal('period', ['inf'])
]);
$stats[$metric]['total'] = $result['value'] ?? 0;
$limit = $days['limit'];
$period = $days['period'];
$results = $dbForProject->find('stats', [
$tasks[$metric . '_data'] = fn () => $dbForProject->find('stats', [
Query::equal('metric', [$metric]),
Query::equal('period', [$period]),
Query::limit($limit),
Query::orderDesc('time'),
]);
}
$results = Promise::map($tasks)->await();
foreach ($metrics as $metric) {
$stats[$metric]['total'] = $results[$metric . '_total']['value'] ?? 0;
$stats[$metric]['data'] = [];
foreach ($results as $result) {
foreach ($results[$metric . '_data'] as $result) {
$stats[$metric]['data'][$result->getAttribute('time')] = [
'value' => $result->getAttribute('value'),
];
@@ -7,6 +7,7 @@ use Appwrite\SDK\AuthType;
use Appwrite\SDK\Method;
use Appwrite\SDK\Response as SDKResponse;
use Appwrite\Utopia\Response;
use Utopia\Async\Promise;
use Utopia\Config\Config;
use Utopia\Database\Database;
use Utopia\Database\Document;
@@ -80,23 +81,29 @@ class XList extends Base
];
$authorization->skip(function () use ($dbForProject, $days, $metrics, &$stats) {
$limit = $days['limit'];
$period = $days['period'];
$tasks = [];
foreach ($metrics as $metric) {
$result = $dbForProject->findOne('stats', [
$tasks[$metric . '_total'] = fn () => $dbForProject->findOne('stats', [
Query::equal('metric', [$metric]),
Query::equal('period', ['inf'])
]);
$stats[$metric]['total'] = $result['value'] ?? 0;
$limit = $days['limit'];
$period = $days['period'];
$results = $dbForProject->find('stats', [
$tasks[$metric . '_data'] = fn () => $dbForProject->find('stats', [
Query::equal('metric', [$metric]),
Query::equal('period', [$period]),
Query::limit($limit),
Query::orderDesc('time'),
]);
}
$results = Promise::map($tasks)->await();
foreach ($metrics as $metric) {
$stats[$metric]['total'] = $results[$metric . '_total']['value'] ?? 0;
$stats[$metric]['data'] = [];
foreach ($results as $result) {
foreach ($results[$metric . '_data'] as $result) {
$stats[$metric]['data'][$result->getAttribute('time')] = [
'value' => $result->getAttribute('value'),
];
@@ -7,6 +7,7 @@ use Appwrite\SDK\AuthType;
use Appwrite\SDK\Method;
use Appwrite\SDK\Response as SDKResponse;
use Appwrite\Utopia\Response;
use Utopia\Async\Promise;
use Utopia\Config\Config;
use Utopia\Database\Database;
use Utopia\Database\Document;
@@ -77,27 +78,33 @@ class Get extends Action
];
$authorization->skip(function () use ($dbForProject, $dbForLogs, $bucket, $days, $metrics, &$stats) {
$limit = $days['limit'];
$period = $days['period'];
$tasks = [];
foreach ($metrics as $metric) {
$db = ($metric === str_replace('{bucketInternalId}', $bucket->getSequence(), METRIC_BUCKET_ID_FILES_IMAGES_TRANSFORMED))
? $dbForLogs
: $dbForProject;
$result = $db->findOne('stats', [
$tasks[$metric . '_total'] = fn () => $db->findOne('stats', [
Query::equal('metric', [$metric]),
Query::equal('period', ['inf'])
]);
$stats[$metric]['total'] = $result['value'] ?? 0;
$limit = $days['limit'];
$period = $days['period'];
$results = $db->find('stats', [
$tasks[$metric . '_data'] = fn () => $db->find('stats', [
Query::equal('metric', [$metric]),
Query::equal('period', [$period]),
Query::limit($limit),
Query::orderDesc('time'),
]);
}
$results = Promise::map($tasks)->await();
foreach ($metrics as $metric) {
$stats[$metric]['total'] = $results[$metric . '_total']['value'] ?? 0;
$stats[$metric]['data'] = [];
foreach ($results as $result) {
foreach ($results[$metric . '_data'] as $result) {
$stats[$metric]['data'][$result->getAttribute('time')] = [
'value' => $result->getAttribute('value'),
];
@@ -6,6 +6,7 @@ use Appwrite\SDK\AuthType;
use Appwrite\SDK\Method;
use Appwrite\SDK\Response as SDKResponse;
use Appwrite\Utopia\Response;
use Utopia\Async\Promise;
use Utopia\Config\Config;
use Utopia\Database\Database;
use Utopia\Database\Document;
@@ -65,23 +66,29 @@ class XList extends Action
];
$authorization->skip(function () use ($dbForProject, $days, $metrics, &$stats) {
$limit = $days['limit'];
$period = $days['period'];
$tasks = [];
foreach ($metrics as $metric) {
$result = $dbForProject->findOne('stats', [
$tasks[$metric . '_total'] = fn () => $dbForProject->findOne('stats', [
Query::equal('metric', [$metric]),
Query::equal('period', ['inf'])
]);
$stats[$metric]['total'] = $result['value'] ?? 0;
$limit = $days['limit'];
$period = $days['period'];
$results = $dbForProject->find('stats', [
$tasks[$metric . '_data'] = fn () => $dbForProject->find('stats', [
Query::equal('metric', [$metric]),
Query::equal('period', [$period]),
Query::limit($limit),
Query::orderDesc('time'),
]);
}
$results = Promise::map($tasks)->await();
foreach ($metrics as $metric) {
$stats[$metric]['total'] = $results[$metric . '_total']['value'] ?? 0;
$stats[$metric]['data'] = [];
foreach ($results as $result) {
foreach ($results[$metric . '_data'] as $result) {
$stats[$metric]['data'][$result->getAttribute('time')] = [
'value' => $result->getAttribute('value'),
];