(fix): fix related collection lookup by sequence, increase schema timeouts

- Related collection lookup used internal name as document ID, but
  Appwrite collections have user-facing IDs. Extract sequence from
  internal name and use findOne by $sequence instead.
- Increase all schema polling timeouts from 240s to 360s for CI
  dedicated mode parallel load.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
This commit is contained in:
Jake Barnby
2026-04-02 03:40:01 +13:00
co-authored by Claude Opus 4.6
parent 61a623fcc0
commit 4d85ab0dcd
2 changed files with 28 additions and 18 deletions
+22 -12
View File
@@ -791,23 +791,33 @@ Http::setResource('getDatabasesDB', function (Group $pools, Database $dbForProje
continue;
}
$options = $attr->getAttribute('options', []);
$relatedId = \is_array($options) ? ($options['relatedCollection'] ?? null) : null;
$relatedId ??= $attr->getAttribute('relatedCollection');
if ($relatedId === null) {
$relatedInternalName = \is_array($options) ? ($options['relatedCollection'] ?? null) : null;
$relatedInternalName ??= $attr->getAttribute('relatedCollection');
if ($relatedInternalName === null) {
continue;
}
// Look up the related collection from dbForProject
$relatedCol = $authorization->skip(
fn () => $dbForProject->silent(
fn () => $dbForProject->getDocument($dbPrefix, $relatedId)
)
);
if (!$relatedCol->isEmpty()) {
$relSeq = $relatedCol->getSequence();
if ($relSeq !== null) {
// Extract sequence from internal name (e.g., 'collection_16' → '16')
$parts = \explode('_', $relatedInternalName);
$relSeq = \end($parts);
if (!\is_numeric($relSeq) && !\str_contains($relSeq, '-')) {
continue;
}
// Find the Appwrite collection document by sequence
try {
$relatedCol = $authorization->skip(
fn () => $dbForProject->silent(
fn () => $dbForProject->findOne($dbPrefix, [
\Utopia\Database\Query::equal('$sequence', [$relSeq]),
\Utopia\Database\Query::select(['$id', '$sequence']),
])
)
);
if ($relatedCol !== null && !$relatedCol->isEmpty()) {
$metadata->setCollectionId('collection_' . $relSeq, $relatedCol->getId());
$metadata->setCollectionId($dbPrefix . '_collection_' . $relSeq, $relatedCol->getId());
}
} catch (\Throwable) {
// Skip — related collection may not exist yet
}
}
}
+6 -6
View File
@@ -20,7 +20,7 @@ trait SchemaPolling
* @param int $timeoutMs Maximum time to wait in milliseconds
* @param int $waitMs Time between polling attempts in milliseconds
*/
protected function waitForAttribute(string $databaseId, string $containerId, string $attributeKey, int $timeoutMs = 240000, int $waitMs = 500): void
protected function waitForAttribute(string $databaseId, string $containerId, string $attributeKey, int $timeoutMs = 360000, int $waitMs = 500): void
{
if (!$this->getSupportForAttributes()) {
return;
@@ -56,7 +56,7 @@ trait SchemaPolling
* @param int $timeoutMs Maximum time to wait in milliseconds
* @param int $waitMs Time between polling attempts in milliseconds
*/
protected function waitForAttributes(string $databaseId, string $containerId, array $attributeKeys, int $timeoutMs = 240000, int $waitMs = 500): void
protected function waitForAttributes(string $databaseId, string $containerId, array $attributeKeys, int $timeoutMs = 360000, int $waitMs = 500): void
{
$this->assertEventually(function () use ($databaseId, $containerId, $attributeKeys) {
$container = $this->client->call(
@@ -100,7 +100,7 @@ trait SchemaPolling
* @param int $timeoutMs Maximum time to wait in milliseconds
* @param int $waitMs Time between polling attempts in milliseconds
*/
protected function waitForAttributeCount(string $databaseId, string $containerId, int $count, int $timeoutMs = 240000, int $waitMs = 500): void
protected function waitForAttributeCount(string $databaseId, string $containerId, int $count, int $timeoutMs = 360000, int $waitMs = 500): void
{
$this->assertEventually(function () use ($databaseId, $containerId, $count) {
$container = $this->client->call(
@@ -142,7 +142,7 @@ trait SchemaPolling
* @param int $timeoutMs Maximum time to wait in milliseconds
* @param int $waitMs Time between polling attempts in milliseconds
*/
protected function waitForIndex(string $databaseId, string $containerId, string $indexKey, int $timeoutMs = 240000, int $waitMs = 500): void
protected function waitForIndex(string $databaseId, string $containerId, string $indexKey, int $timeoutMs = 360000, int $waitMs = 500): void
{
$this->assertEventually(function () use ($databaseId, $containerId, $indexKey) {
$index = $this->client->call(
@@ -176,7 +176,7 @@ trait SchemaPolling
* @param int $timeoutMs Maximum time to wait in milliseconds
* @param int $waitMs Time between polling attempts in milliseconds
*/
protected function waitForAllIndexes(string $databaseId, string $containerId, int $timeoutMs = 240000, int $waitMs = 500): void
protected function waitForAllIndexes(string $databaseId, string $containerId, int $timeoutMs = 360000, int $waitMs = 500): void
{
$this->assertEventually(function () use ($databaseId, $containerId) {
$container = $this->client->call(
@@ -210,7 +210,7 @@ trait SchemaPolling
* @param int $timeoutMs Maximum time to wait in milliseconds
* @param int $waitMs Time between polling attempts in milliseconds
*/
protected function waitForAllAttributes(string $databaseId, string $containerId, int $timeoutMs = 240000, int $waitMs = 500): void
protected function waitForAllAttributes(string $databaseId, string $containerId, int $timeoutMs = 360000, int $waitMs = 500): void
{
$this->assertEventually(function () use ($databaseId, $containerId) {
$container = $this->client->call(