From 8a8a5f5add7b0d40cfe961078b36b0a4651d08d7 Mon Sep 17 00:00:00 2001 From: ArnabChatterjee20k Date: Tue, 27 Jan 2026 14:00:38 +0530 Subject: [PATCH 1/4] refactor: replace Lock with Channel for coroutine safety in Swoole adapter --- src/Pools/Adapter/Swoole.php | 14 ++++++++------ 1 file changed, 8 insertions(+), 6 deletions(-) diff --git a/src/Pools/Adapter/Swoole.php b/src/Pools/Adapter/Swoole.php index 2fc1d37..00124ff 100644 --- a/src/Pools/Adapter/Swoole.php +++ b/src/Pools/Adapter/Swoole.php @@ -4,19 +4,21 @@ use Utopia\Pools\Adapter; use Swoole\Coroutine\Channel; -use Swoole\Lock; class Swoole extends Adapter { protected Channel $pool; - /** @var Lock $lock */ - protected Lock $lock; + protected Channel $lock; public function initialize(int $size): static { $this->pool = new Channel($size); - $this->lock = new Lock(SWOOLE_MUTEX); + // using a coroutine mutex instead of lock as lock is process based and acquires os level lock + // result will be all the coroutines will be blocked(http, realtime running on the same event loop)s + // coroutine is coroutine safe + $this->lock = new Channel(1); + $this->lock->push(true); return $this; } @@ -60,7 +62,7 @@ public function count(): int */ public function synchronized(callable $callback, int $timeout): mixed { - $acquired = $this->lock->lockwait($timeout); + $acquired = $this->lock->pop($timeout); if (!$acquired) { throw new \RuntimeException("Failed to acquire lock within {$timeout} seconds"); @@ -69,7 +71,7 @@ public function synchronized(callable $callback, int $timeout): mixed try { return $callback(); } finally { - $this->lock->unlock(); + $this->lock->push(true, $timeout); } } } From 5063f063d6bb7f23de7ce4a46b40bdeacf161bda Mon Sep 17 00:00:00 2001 From: ArnabChatterjee20k Date: Tue, 27 Jan 2026 14:16:37 +0530 Subject: [PATCH 2/4] updated timeout --- src/Pools/Adapter/Swoole.php | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/Pools/Adapter/Swoole.php b/src/Pools/Adapter/Swoole.php index 00124ff..f4c53f3 100644 --- a/src/Pools/Adapter/Swoole.php +++ b/src/Pools/Adapter/Swoole.php @@ -71,7 +71,8 @@ public function synchronized(callable $callback, int $timeout): mixed try { return $callback(); } finally { - $this->lock->push(true, $timeout); + // guranteed to have space so no timeout otherwise there will be no token and results deadlock + $this->lock->push(true); } } } From fb8a07a28e3128012178028bee566e63c66e7e9f Mon Sep 17 00:00:00 2001 From: ArnabChatterjee20k Date: Tue, 27 Jan 2026 14:37:28 +0530 Subject: [PATCH 3/4] updated comment --- src/Pools/Adapter/Swoole.php | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/src/Pools/Adapter/Swoole.php b/src/Pools/Adapter/Swoole.php index f4c53f3..d23396a 100644 --- a/src/Pools/Adapter/Swoole.php +++ b/src/Pools/Adapter/Swoole.php @@ -14,9 +14,10 @@ public function initialize(int $size): static { $this->pool = new Channel($size); - // using a coroutine mutex instead of lock as lock is process based and acquires os level lock - // result will be all the coroutines will be blocked(http, realtime running on the same event loop)s - // coroutine is coroutine safe + // With channels, the current coroutine suspends and yields control to the event loop, + // allowing other coroutines to continue executing. + // Using a blocking lock freezes the worker thread, causing all coroutines in that + // worker to stop making progress. $this->lock = new Channel(1); $this->lock->push(true); From 2df189cb46e5bb3a4917ba1b4d48eab5a4148cec Mon Sep 17 00:00:00 2001 From: ArnabChatterjee20k Date: Tue, 27 Jan 2026 14:38:50 +0530 Subject: [PATCH 4/4] updated comments --- src/Pools/Adapter/Swoole.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Pools/Adapter/Swoole.php b/src/Pools/Adapter/Swoole.php index d23396a..240c267 100644 --- a/src/Pools/Adapter/Swoole.php +++ b/src/Pools/Adapter/Swoole.php @@ -72,7 +72,7 @@ public function synchronized(callable $callback, int $timeout): mixed try { return $callback(); } finally { - // guranteed to have space so no timeout otherwise there will be no token and results deadlock + // Guaranteed to have space here; avoid timeouts so the token isn't lost. $this->lock->push(true); } }