From 8b297f5a8939e09226215f1426059c4e7f4bc416 Mon Sep 17 00:00:00 2001 From: Jake Barnby Date: Wed, 21 Jan 2026 22:48:30 +1300 Subject: [PATCH] Simplify all() to use SwoolePromise.then() directly Call then() on the adopted SwoolePromise directly instead of going through the GQLPromise wrapper. This ensures callbacks are properly registered and fired via SwoolePromise's processWaiting(). Co-Authored-By: Claude Opus 4.5 --- .../GraphQL/Promises/Adapter/Swoole.php | 81 +++++++++---------- 1 file changed, 37 insertions(+), 44 deletions(-) diff --git a/src/Appwrite/GraphQL/Promises/Adapter/Swoole.php b/src/Appwrite/GraphQL/Promises/Adapter/Swoole.php index 9acc53f349..5c07071c53 100644 --- a/src/Appwrite/GraphQL/Promises/Adapter/Swoole.php +++ b/src/Appwrite/GraphQL/Promises/Adapter/Swoole.php @@ -44,54 +44,47 @@ class Swoole extends Adapter return $this->createFulfilled([]); } - // Create a promise whose executor uses Channel to wait for all input promises - $promise = new SwoolePromise(function ($resolve, $reject) use ($promisesOrValues, $total) { - $channel = new \Swoole\Coroutine\Channel($total); - $result = []; - $error = null; + // Create the combined promise without executor + $combinedPromise = new SwoolePromise(); - foreach ($promisesOrValues as $index => $promiseOrValue) { - if ($promiseOrValue instanceof GQLPromise) { - $result[$index] = null; - // Spawn a coroutine to wait for each promise - \go(function () use ($promiseOrValue, $index, &$result, &$error, $channel) { - /** @var SwoolePromise $adopted */ - $adopted = $promiseOrValue->adoptedPromise; + $count = 0; + $result = []; + $rejected = false; - // Poll until the promise is settled - while ($adopted->isPending()) { - \Swoole\Coroutine::sleep(0.001); - } - - if ($adopted->isFulfilled()) { - $result[$index] = $adopted->getResult(); - } else { - if ($error === null) { - $error = $adopted->getResult(); - } - } - $channel->push(true); - }); - } else { - $result[$index] = $promiseOrValue; - $channel->push(true); - } - } - - // Wait for all coroutines to complete - for ($i = 0; $i < $total; $i++) { - $channel->pop(); - } - $channel->close(); - - if ($error !== null) { - $reject($error); - } else { + $checkComplete = static function () use (&$count, $total, &$result, &$rejected, $combinedPromise): void { + if (!$rejected && $count === $total) { \ksort($result); - $resolve($result); + $combinedPromise->resolve($result); } - }); + }; - return new GQLPromise($promise, $this); + foreach ($promisesOrValues as $index => $promiseOrValue) { + if ($promiseOrValue instanceof GQLPromise) { + $result[$index] = null; + /** @var SwoolePromise $adopted */ + $adopted = $promiseOrValue->adoptedPromise; + $adopted->then( + static function ($value) use (&$result, $index, &$count, $checkComplete) { + $result[$index] = $value; + ++$count; + $checkComplete(); + return $value; + }, + static function ($error) use (&$rejected, $combinedPromise) { + if (!$rejected) { + $rejected = true; + $combinedPromise->reject($error); + } + } + ); + } else { + $result[$index] = $promiseOrValue; + ++$count; + } + } + + $checkComplete(); + + return new GQLPromise($combinedPromise, $this); } }