fix: drop expired presences at fetch time and clean up Presence model attributes

This commit is contained in:
ArnabChatterjee20k
2026-05-08 12:28:33 +05:30
parent 5767ab8ac7
commit 46e86ce854
2 changed files with 13 additions and 15 deletions
@@ -93,6 +93,13 @@ class XList extends PlatformAction
$groupedQueries = Query::groupByType($queries);
$filterQueries = $groupedQueries['filters'];
// should be excluded from the user provided query as user query would be used for caching only
// otherwise cache will always miss due to the datetime now
$expiryFilter = Query::or([
Query::isNull('expiresAt'),
Query::greaterThan('expiresAt', DateTime::now()),
]);
try {
if ((int)$ttl > 0) {
$presenceState = new PresenceState();
@@ -115,7 +122,7 @@ class XList extends PlatformAction
}, $cachedDocuments);
$documentsCacheHit = true;
} else {
$documents = $dbForProject->find('presenceLogs', $queries);
$documents = $dbForProject->find('presenceLogs', [...$queries, $expiryFilter]);
$documentsArray = \array_map(function ($doc) {
return $doc->getArrayCopy();
}, $documents);
@@ -139,7 +146,7 @@ class XList extends PlatformAction
if ($cachedTotal !== null && $cachedTotal !== false) {
$total = (int) $cachedTotal;
} else {
$total = $dbForProject->count('presenceLogs', $filterQueries, APP_LIMIT_COUNT);
$total = $dbForProject->count('presenceLogs', [...$filterQueries, $expiryFilter], APP_LIMIT_COUNT);
$presenceState->saveListCacheField(
$dbForProject,
$roles,
@@ -154,8 +161,8 @@ class XList extends PlatformAction
$response->addHeader('X-Appwrite-Cache', $documentsCacheHit ? 'hit' : 'miss');
} else {
$documents = $dbForProject->find('presenceLogs', $queries);
$total = $includeTotal ? $dbForProject->count('presenceLogs', $filterQueries, APP_LIMIT_COUNT) : 0;
$documents = $dbForProject->find('presenceLogs', [...$queries, $expiryFilter]);
$total = $includeTotal ? $dbForProject->count('presenceLogs', [...$filterQueries, $expiryFilter], APP_LIMIT_COUNT) : 0;
}
} catch (OrderException $e) {
throw new Exception(Exception::DATABASE_QUERY_ORDER_NULL, "The order attribute '{$e->getAttribute()}' had a null value. Cursor pagination requires all documents order attribute values are non-null.");
@@ -165,17 +172,6 @@ class XList extends PlatformAction
throw new Exception(Exception::RELATIONSHIP_VALUE_INVALID, $e->getMessage(), previous: $e);
}
// Post-filter expired presences in PHP rather than as a query so the cache key stays
// stable across requests (DateTime::now() in a query would bust the list cache every call).
// Null expiresAt is kept: realtime upserts leave it unset because the presence's lifetime
// is bound to the websocket connection. The maintenance worker prunes expired rows; until
// it runs, $total may be slightly inflated relative to the returned page.
$now = DateTime::now();
$documents = \array_values(\array_filter($documents, function (Document $document) use ($now): bool {
$expiresAt = $document->getAttribute('expiresAt');
return $expiresAt === null || $expiresAt > $now;
}));
$response->dynamic(new Document([
'presences' => $documents,
'total' => $total,
@@ -96,6 +96,8 @@ class Presence extends Any
{
$document->removeAttribute('$collection');
$document->removeAttribute('$tenant');
$document->removeAttribute('hostname');
$document->removeAttribute('perms_md5');
if (!$document->isEmpty()) {
$document->setAttribute('$sequence', (string) $document->getAttribute('$sequence', ''));