From fe28af292be088ec6aa24ab010f42167630b7279 Mon Sep 17 00:00:00 2001 From: Fabian Gruber Date: Wed, 23 Apr 2025 16:42:39 +0200 Subject: [PATCH 1/2] feat: allow non-critical events to ignore exceptions when enqueuing the message --- src/Appwrite/Event/Audit.php | 2 + src/Appwrite/Event/Event.php | 12 +++++- src/Appwrite/Event/Realtime.php | 11 ++++- src/Appwrite/Event/StatsResources.php | 2 + src/Appwrite/Event/StatsUsage.php | 2 + src/Appwrite/Messaging/Adapter.php | 2 +- src/Appwrite/Messaging/Adapter/Realtime.php | 45 +++++++++++---------- 7 files changed, 51 insertions(+), 25 deletions(-) diff --git a/src/Appwrite/Event/Audit.php b/src/Appwrite/Event/Audit.php index 6c2a9c3086..dd48093dc5 100644 --- a/src/Appwrite/Event/Audit.php +++ b/src/Appwrite/Event/Audit.php @@ -12,6 +12,8 @@ class Audit extends Event protected string $ip = ''; protected string $hostname = ''; + protected bool $critical = false; + public function __construct(protected Publisher $publisher) { parent::__construct($publisher); diff --git a/src/Appwrite/Event/Event.php b/src/Appwrite/Event/Event.php index 08faeea485..d699a45417 100644 --- a/src/Appwrite/Event/Event.php +++ b/src/Appwrite/Event/Event.php @@ -57,6 +57,9 @@ class Event protected ?string $userId = null; protected bool $paused = false; + /** @var bool Non-critical events will not throw an exception when enqueuing of the event fails. */ + protected bool $critical = true; + /** * @param Publisher $publisher * @return void @@ -351,7 +354,14 @@ class Event // Merge the base payload with any trimmed values $payload = array_merge($this->preparePayload(), $this->trimPayload()); - return $this->publisher->enqueue($queue, $payload); + try { + return $this->publisher->enqueue($queue, $payload); + } catch (\Throwable $th) { + if ($this->critical) { + throw $th; + } + return false; + } } /** diff --git a/src/Appwrite/Event/Realtime.php b/src/Appwrite/Event/Realtime.php index 28a1bb6a6d..b77df580f8 100644 --- a/src/Appwrite/Event/Realtime.php +++ b/src/Appwrite/Event/Realtime.php @@ -2,15 +2,22 @@ namespace Appwrite\Event; +use Appwrite\Messaging\Adapter; use Appwrite\Messaging\Adapter\Realtime as RealtimeAdapter; use Utopia\Database\Document; +use Utopia\Database\Exception; class Realtime extends Event { protected array $subscribers = []; + private Adapter $realtime; + + protected bool $critical = false; + public function __construct() { + $this->realtime = new Adapter\Realtime(); } /** @@ -57,7 +64,7 @@ class Realtime extends Event * Execute Event. * * @return string|bool - * @throws InvalidArgumentException + * @throws Exception */ public function trigger(): string|bool { @@ -87,7 +94,7 @@ class Realtime extends Event : [$target['projectId'] ?? $this->getProject()->getId()]; foreach ($projectIds as $projectId) { - RealtimeAdapter::send( + $this->realtime->send( projectId: $projectId, payload: $this->getRealtimePayload(), events: $allEvents, diff --git a/src/Appwrite/Event/StatsResources.php b/src/Appwrite/Event/StatsResources.php index e7a3df97e0..c4f7ac1690 100644 --- a/src/Appwrite/Event/StatsResources.php +++ b/src/Appwrite/Event/StatsResources.php @@ -6,6 +6,8 @@ use Utopia\Queue\Publisher; class StatsResources extends Event { + protected bool $critical = false; + public function __construct(protected Publisher $publisher) { parent::__construct($publisher); diff --git a/src/Appwrite/Event/StatsUsage.php b/src/Appwrite/Event/StatsUsage.php index e259ba5e04..f6b1d695f4 100644 --- a/src/Appwrite/Event/StatsUsage.php +++ b/src/Appwrite/Event/StatsUsage.php @@ -11,6 +11,8 @@ class StatsUsage extends Event protected array $reduce = []; protected array $disabled = []; + protected bool $critical = false; + public function __construct(protected Publisher $publisher) { parent::__construct($publisher); diff --git a/src/Appwrite/Messaging/Adapter.php b/src/Appwrite/Messaging/Adapter.php index 27dd7f68eb..40169bd1a9 100644 --- a/src/Appwrite/Messaging/Adapter.php +++ b/src/Appwrite/Messaging/Adapter.php @@ -6,5 +6,5 @@ abstract class Adapter { abstract public function subscribe(string $projectId, mixed $identifier, array $roles, array $channels): void; abstract public function unsubscribe(mixed $identifier): void; - abstract public static function send(string $projectId, array $payload, array $events, array $channels, array $roles, array $options): void; + abstract public function send(string $projectId, array $payload, array $events, array $channels, array $roles, array $options): void; } diff --git a/src/Appwrite/Messaging/Adapter/Realtime.php b/src/Appwrite/Messaging/Adapter/Realtime.php index dceafacf6e..1963bdedd6 100644 --- a/src/Appwrite/Messaging/Adapter/Realtime.php +++ b/src/Appwrite/Messaging/Adapter/Realtime.php @@ -7,6 +7,7 @@ use Utopia\Database\DateTime; use Utopia\Database\Document; use Utopia\Database\Helpers\ID; use Utopia\Database\Helpers\Role; +use Utopia\Pools\Pool; class Realtime extends Adapter { @@ -35,6 +36,14 @@ class Realtime extends Adapter */ public array $subscriptions = []; + private Pool $pubsubPool; + + public function __construct() + { + global $register; + $this->pubsubPool = $register->get('pools')->get('pubsub'); + } + /** * Adds a subscription. * @@ -129,7 +138,7 @@ class Realtime extends Adapter * @param array $options * @return void */ - public static function send(string $projectId, array $payload, array $events, array $channels, array $roles, array $options = []): void + public function send(string $projectId, array $payload, array $events, array $channels, array $roles, array $options = []): void { if (empty($channels) || empty($roles) || empty($projectId)) { return; @@ -138,26 +147,20 @@ class Realtime extends Adapter $permissionsChanged = array_key_exists('permissionsChanged', $options) && $options['permissionsChanged']; $userId = array_key_exists('userId', $options) ? $options['userId'] : null; - global $register; - $pubsub = $register->get('pools')->get('pubsub')->pop(); - try { - /** @var \Appwrite\PubSub\Adapter $redis */ - $redis = $pubsub->getResource(); - $redis->publish('realtime', json_encode([ - 'project' => $projectId, - 'roles' => $roles, - 'permissionsChanged' => $permissionsChanged, - 'userId' => $userId, - 'data' => [ - 'events' => $events, - 'channels' => $channels, - 'timestamp' => DateTime::formatTz(DateTime::now()), - 'payload' => $payload - ] - ])); - } finally { - $pubsub->reclaim(); - } + $message = [ + 'project' => $projectId, + 'roles' => $roles, + 'permissionsChanged' => $permissionsChanged, + 'userId' => $userId, + 'data' => [ + 'events' => $events, + 'channels' => $channels, + 'timestamp' => DateTime::formatTz(DateTime::now()), + 'payload' => $payload + ] + ]; + + $this->pubsubPool->use(fn (\Appwrite\PubSub\Adapter $pubsub) => $pubsub->publish('realtime', json_encode($message))); } /** From b0eb6434b800066b013149559bb8d7205b98d35e Mon Sep 17 00:00:00 2001 From: Fabian Gruber Date: Wed, 23 Apr 2025 17:12:34 +0200 Subject: [PATCH 2/2] fix: nullable group field in SDK\Method --- src/Appwrite/SDK/Method.php | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/Appwrite/SDK/Method.php b/src/Appwrite/SDK/Method.php index b0afd2ee58..2fec726e44 100644 --- a/src/Appwrite/SDK/Method.php +++ b/src/Appwrite/SDK/Method.php @@ -16,7 +16,7 @@ class Method * Initialise a new SDK method * * @param string $namespace - * @param string|null $group + * @param ?string $group * @param string $name * @param string $description * @param array $auth @@ -34,7 +34,7 @@ class Method */ public function __construct( protected string $namespace, - protected string|null $group, + protected ?string $group, protected string $name, protected string $description, protected array $auth, @@ -128,7 +128,7 @@ class Method return $this->namespace; } - public function getGroup(): string|null + public function getGroup(): ?string { return $this->group; }