mirror of
https://github.com/appwrite/appwrite.git
synced 2026-05-26 13:51:13 +00:00
refactor: integrate EventProcessor for handling function and webhook events; streamline event triggering in database actions
This commit is contained in:
@@ -0,0 +1,106 @@
|
||||
<?php
|
||||
|
||||
namespace Appwrite\Functions;
|
||||
|
||||
use Utopia\Database\Database;
|
||||
use Utopia\Database\Document;
|
||||
use Utopia\Database\Query;
|
||||
|
||||
class EventProcessor
|
||||
{
|
||||
/**
|
||||
* Get function events for a project, using Redis cache
|
||||
* @param Document|null $project
|
||||
* @param Database $dbForProject
|
||||
* @return array<string, bool>
|
||||
*/
|
||||
public function getFunctionsEvents(?Document $project, Database $dbForProject): array
|
||||
{
|
||||
if ($project === null ||
|
||||
$project->isEmpty() ||
|
||||
$project->getId() === 'console') {
|
||||
return [];
|
||||
}
|
||||
|
||||
$hostname = $dbForProject->getAdapter()->getHostname();
|
||||
$cacheKey = \sprintf(
|
||||
'%s-cache-%s:%s:%s:project:%s:functions:events',
|
||||
$dbForProject->getCacheName(),
|
||||
$hostname ?? '',
|
||||
$dbForProject->getNamespace(),
|
||||
$dbForProject->getTenant(),
|
||||
$project->getId()
|
||||
);
|
||||
|
||||
$ttl = 3600; // 1 hour cache TTL
|
||||
$cachedFunctionEvents = $dbForProject->getCache()->load($cacheKey, $ttl);
|
||||
|
||||
if ($cachedFunctionEvents !== false) {
|
||||
return \json_decode($cachedFunctionEvents, true) ?? [];
|
||||
}
|
||||
|
||||
try {
|
||||
$events = [];
|
||||
$limit = 100;
|
||||
$sum = 100;
|
||||
$offset = 0;
|
||||
|
||||
while ($sum >= $limit) {
|
||||
$functions = $dbForProject->find('functions', [
|
||||
Query::select(['$id', 'events']),
|
||||
Query::limit($limit),
|
||||
Query::offset($offset),
|
||||
Query::orderAsc('$sequence'),
|
||||
]);
|
||||
|
||||
$sum = \count($functions);
|
||||
$offset = $offset + $limit;
|
||||
|
||||
foreach ($functions as $function) {
|
||||
$functionEvents = $function->getAttribute('events', []);
|
||||
if (!empty($functionEvents)) {
|
||||
$events = array_merge($events, $functionEvents);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
$uniqueEvents = \array_flip(\array_unique($events));
|
||||
$dbForProject->getCache()->save($cacheKey, \json_encode($uniqueEvents));
|
||||
|
||||
return $uniqueEvents;
|
||||
} catch (\Throwable $e) {
|
||||
return [];
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Get webhook events for a project from the project's webhooks attribute
|
||||
* @param Document|null $project
|
||||
* @return array<string, bool>
|
||||
*/
|
||||
public function getWebhooksEvents(?Document $project): array
|
||||
{
|
||||
if ($project === null || $project->isEmpty() || $project->getId() === 'console') {
|
||||
return [];
|
||||
}
|
||||
|
||||
$webhooks = $project->getAttribute('webhooks', []);
|
||||
if (empty($webhooks)) {
|
||||
return [];
|
||||
}
|
||||
|
||||
$events = [];
|
||||
foreach ($webhooks as $webhook) {
|
||||
if ($webhook->getAttribute('enabled', false) !== true) {
|
||||
continue;
|
||||
}
|
||||
|
||||
$webhookEvents = $webhook->getAttribute('events', []);
|
||||
if (!empty($webhookEvents)) {
|
||||
$events = array_merge($events, $webhookEvents);
|
||||
}
|
||||
}
|
||||
|
||||
return \array_flip(\array_unique($events));
|
||||
}
|
||||
}
|
||||
@@ -7,7 +7,6 @@ use Appwrite\Platform\Action as AppwriteAction;
|
||||
use Utopia\Database\Database;
|
||||
use Utopia\Database\Document;
|
||||
use Utopia\Database\Operator;
|
||||
use Utopia\Database\Query;
|
||||
|
||||
class Action extends AppwriteAction
|
||||
{
|
||||
@@ -96,100 +95,4 @@ class Action extends AppwriteAction
|
||||
return $data;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get function events for a project, using Redis cache
|
||||
* @param Document|null $project
|
||||
* @param Database $dbForProject
|
||||
* @return array<string, bool>
|
||||
*/
|
||||
protected function getFunctionsEvents(?Document $project, Database $dbForProject): array
|
||||
{
|
||||
if ($project === null ||
|
||||
$project->isEmpty() ||
|
||||
$project->getId() === 'console') {
|
||||
return [];
|
||||
}
|
||||
|
||||
$hostname = $dbForProject->getAdapter()->getHostname();
|
||||
$cacheKey = \sprintf(
|
||||
'%s-cache-%s:%s:%s:project:%s:functions:events',
|
||||
$dbForProject->getCacheName(),
|
||||
$hostname ?? '',
|
||||
$dbForProject->getNamespace(),
|
||||
$dbForProject->getTenant(),
|
||||
$project->getId()
|
||||
);
|
||||
|
||||
$ttl = 3600; // 1 hour cache TTL
|
||||
$cachedFunctionEvents = $dbForProject->getCache()->load($cacheKey, $ttl);
|
||||
|
||||
if ($cachedFunctionEvents !== false) {
|
||||
return \json_decode($cachedFunctionEvents, true) ?? [];
|
||||
|
||||
}
|
||||
|
||||
try {
|
||||
$events = [];
|
||||
$limit = 100;
|
||||
$sum = 100;
|
||||
$offset = 0;
|
||||
|
||||
while ($sum >= $limit) {
|
||||
$functions = $dbForProject->find('functions', [
|
||||
Query::select(['$id', 'events']),
|
||||
Query::limit($limit),
|
||||
Query::offset($offset),
|
||||
Query::orderAsc('$sequence'),
|
||||
]);
|
||||
|
||||
$sum = \count($functions);
|
||||
$offset = $offset + $limit;
|
||||
|
||||
foreach ($functions as $function) {
|
||||
$functionEvents = $function->getAttribute('events', []);
|
||||
if (!empty($functionEvents)) {
|
||||
$events = array_merge($events, $functionEvents);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
$uniqueEvents = \array_flip(\array_unique($events));
|
||||
$dbForProject->getCache()->save($cacheKey, \json_encode($uniqueEvents));
|
||||
|
||||
return $uniqueEvents;
|
||||
} catch (\Throwable $e) {
|
||||
return [];
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Get webhook events for a project from the project's webhooks attribute
|
||||
* @param Document|null $project
|
||||
* @return array<string, bool>
|
||||
*/
|
||||
protected function getWebhooksEvents(?Document $project): array
|
||||
{
|
||||
if ($project === null || $project->isEmpty() || $project->getId() === 'console') {
|
||||
return [];
|
||||
}
|
||||
|
||||
$webhooks = $project->getAttribute('webhooks', []);
|
||||
if (empty($webhooks)) {
|
||||
return [];
|
||||
}
|
||||
|
||||
$events = [];
|
||||
foreach ($webhooks as $webhook) {
|
||||
if ($webhook->getAttribute('enabled', false) !== true) {
|
||||
continue;
|
||||
}
|
||||
|
||||
$webhookEvents = $webhook->getAttribute('events', []);
|
||||
if (!empty($webhookEvents)) {
|
||||
$events = array_merge($events, $webhookEvents);
|
||||
}
|
||||
}
|
||||
|
||||
return \array_flip(\array_unique($events));
|
||||
}
|
||||
}
|
||||
|
||||
+7
-3
@@ -4,6 +4,7 @@ namespace Appwrite\Platform\Modules\Databases\Http\Databases\Collections\Documen
|
||||
|
||||
use Appwrite\Event\Event;
|
||||
use Appwrite\Extend\Exception;
|
||||
use Appwrite\Functions\EventProcessor;
|
||||
use Appwrite\Platform\Modules\Databases\Http\Databases\Action as DatabasesAction;
|
||||
use Utopia\Database\Database;
|
||||
use Utopia\Database\Document;
|
||||
@@ -349,6 +350,7 @@ abstract class Action extends DatabasesAction
|
||||
* @param Event $queueForFunctions
|
||||
* @param Event $queueForWebhooks
|
||||
* @param Database $dbForProject
|
||||
* @param EventProcessor $eventProcessor
|
||||
* @return void
|
||||
*/
|
||||
protected function triggerBulk(
|
||||
@@ -360,7 +362,8 @@ abstract class Action extends DatabasesAction
|
||||
Event $queueForRealtime,
|
||||
Event $queueForFunctions,
|
||||
Event $queueForWebhooks,
|
||||
Database $dbForProject
|
||||
Database $dbForProject,
|
||||
EventProcessor $eventProcessor
|
||||
): void {
|
||||
$queueForEvents
|
||||
->setEvent($event)
|
||||
@@ -372,8 +375,8 @@ abstract class Action extends DatabasesAction
|
||||
|
||||
// Get project and function events (cached)
|
||||
$project = $queueForEvents->getProject();
|
||||
$functionsEvents = $this->getFunctionsEvents($project, $dbForProject);
|
||||
$webhooksEvents = $this->getWebhooksEvents($project);
|
||||
$functionsEvents = $eventProcessor->getFunctionsEvents($project, $dbForProject);
|
||||
$webhooksEvents = $eventProcessor->getWebhooksEvents($project);
|
||||
|
||||
foreach ($documents as $document) {
|
||||
$queueForEvents
|
||||
@@ -391,6 +394,7 @@ abstract class Action extends DatabasesAction
|
||||
$queueForEvents->getParams()
|
||||
);
|
||||
|
||||
|
||||
if (!empty($functionsEvents)) {
|
||||
foreach ($generatedEvents as $event) {
|
||||
if (isset($functionsEvents[$event])) {
|
||||
|
||||
+5
-2
@@ -5,6 +5,7 @@ namespace Appwrite\Platform\Modules\Databases\Http\Databases\Collections\Documen
|
||||
use Appwrite\Event\Event;
|
||||
use Appwrite\Event\StatsUsage;
|
||||
use Appwrite\Extend\Exception;
|
||||
use Appwrite\Functions\EventProcessor;
|
||||
use Appwrite\Platform\Modules\Databases\Http\Databases\Collections\Documents\Action;
|
||||
use Appwrite\SDK\AuthType;
|
||||
use Appwrite\SDK\ContentType;
|
||||
@@ -81,10 +82,11 @@ class Delete extends Action
|
||||
->inject('queueForFunctions')
|
||||
->inject('queueForWebhooks')
|
||||
->inject('plan')
|
||||
->inject('eventProcessor')
|
||||
->callback($this->action(...));
|
||||
}
|
||||
|
||||
public function action(string $databaseId, string $collectionId, array $queries, ?string $transactionId, UtopiaResponse $response, Database $dbForProject, StatsUsage $queueForStatsUsage, Event $queueForEvents, Event $queueForRealtime, Event $queueForFunctions, Event $queueForWebhooks, array $plan): void
|
||||
public function action(string $databaseId, string $collectionId, array $queries, ?string $transactionId, UtopiaResponse $response, Database $dbForProject, StatsUsage $queueForStatsUsage, Event $queueForEvents, Event $queueForRealtime, Event $queueForFunctions, Event $queueForWebhooks, array $plan, EventProcessor $eventProcessor): void
|
||||
{
|
||||
$database = $dbForProject->getDocument('databases', $databaseId);
|
||||
if ($database->isEmpty()) {
|
||||
@@ -204,7 +206,8 @@ class Delete extends Action
|
||||
$queueForRealtime,
|
||||
$queueForFunctions,
|
||||
$queueForWebhooks,
|
||||
$dbForProject
|
||||
$dbForProject,
|
||||
$eventProcessor
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
+5
-2
@@ -5,6 +5,7 @@ namespace Appwrite\Platform\Modules\Databases\Http\Databases\Collections\Documen
|
||||
use Appwrite\Event\Event;
|
||||
use Appwrite\Event\StatsUsage;
|
||||
use Appwrite\Extend\Exception;
|
||||
use Appwrite\Functions\EventProcessor;
|
||||
use Appwrite\Platform\Modules\Databases\Http\Databases\Collections\Documents\Action;
|
||||
use Appwrite\SDK\AuthType;
|
||||
use Appwrite\SDK\ContentType;
|
||||
@@ -85,10 +86,11 @@ class Update extends Action
|
||||
->inject('queueForFunctions')
|
||||
->inject('queueForWebhooks')
|
||||
->inject('plan')
|
||||
->inject('eventProcessor')
|
||||
->callback($this->action(...));
|
||||
}
|
||||
|
||||
public function action(string $databaseId, string $collectionId, string|array $data, array $queries, ?string $transactionId, UtopiaResponse $response, Database $dbForProject, StatsUsage $queueForStatsUsage, Event $queueForEvents, Event $queueForRealtime, Event $queueForFunctions, Event $queueForWebhooks, array $plan): void
|
||||
public function action(string $databaseId, string $collectionId, string|array $data, array $queries, ?string $transactionId, UtopiaResponse $response, Database $dbForProject, StatsUsage $queueForStatsUsage, Event $queueForEvents, Event $queueForRealtime, Event $queueForFunctions, Event $queueForWebhooks, array $plan, EventProcessor $eventProcessor): void
|
||||
{
|
||||
$data = \is_string($data)
|
||||
? \json_decode($data, true)
|
||||
@@ -235,7 +237,8 @@ class Update extends Action
|
||||
$queueForRealtime,
|
||||
$queueForFunctions,
|
||||
$queueForWebhooks,
|
||||
$dbForProject
|
||||
$dbForProject,
|
||||
$eventProcessor
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
+5
-2
@@ -5,6 +5,7 @@ namespace Appwrite\Platform\Modules\Databases\Http\Databases\Collections\Documen
|
||||
use Appwrite\Event\Event;
|
||||
use Appwrite\Event\StatsUsage;
|
||||
use Appwrite\Extend\Exception;
|
||||
use Appwrite\Functions\EventProcessor;
|
||||
use Appwrite\Platform\Modules\Databases\Http\Databases\Collections\Documents\Action;
|
||||
use Appwrite\SDK\AuthType;
|
||||
use Appwrite\SDK\ContentType;
|
||||
@@ -83,10 +84,11 @@ class Upsert extends Action
|
||||
->inject('queueForFunctions')
|
||||
->inject('queueForWebhooks')
|
||||
->inject('plan')
|
||||
->inject('eventProcessor')
|
||||
->callback($this->action(...));
|
||||
}
|
||||
|
||||
public function action(string $databaseId, string $collectionId, array $documents, ?string $transactionId, UtopiaResponse $response, Database $dbForProject, StatsUsage $queueForStatsUsage, Event $queueForEvents, Event $queueForRealtime, Event $queueForFunctions, Event $queueForWebhooks, array $plan): void
|
||||
public function action(string $databaseId, string $collectionId, array $documents, ?string $transactionId, UtopiaResponse $response, Database $dbForProject, StatsUsage $queueForStatsUsage, Event $queueForEvents, Event $queueForRealtime, Event $queueForFunctions, Event $queueForWebhooks, array $plan, EventProcessor $eventProcessor): void
|
||||
{
|
||||
$database = $dbForProject->getDocument('databases', $databaseId);
|
||||
if ($database->isEmpty()) {
|
||||
@@ -210,7 +212,8 @@ class Upsert extends Action
|
||||
$queueForRealtime,
|
||||
$queueForFunctions,
|
||||
$queueForWebhooks,
|
||||
$dbForProject
|
||||
$dbForProject,
|
||||
$eventProcessor
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
+5
-2
@@ -5,6 +5,7 @@ namespace Appwrite\Platform\Modules\Databases\Http\Databases\Collections\Documen
|
||||
use Appwrite\Event\Event;
|
||||
use Appwrite\Event\StatsUsage;
|
||||
use Appwrite\Extend\Exception;
|
||||
use Appwrite\Functions\EventProcessor;
|
||||
use Appwrite\SDK\AuthType;
|
||||
use Appwrite\SDK\ContentType;
|
||||
use Appwrite\SDK\Deprecated;
|
||||
@@ -132,9 +133,10 @@ class Create extends Action
|
||||
->inject('queueForFunctions')
|
||||
->inject('queueForWebhooks')
|
||||
->inject('plan')
|
||||
->inject('eventProcessor')
|
||||
->callback($this->action(...));
|
||||
}
|
||||
public function action(string $databaseId, string $documentId, string $collectionId, string|array $data, ?array $permissions, ?array $documents, ?string $transactionId, UtopiaResponse $response, Database $dbForProject, Document $user, Event $queueForEvents, StatsUsage $queueForStatsUsage, Event $queueForRealtime, Event $queueForFunctions, Event $queueForWebhooks, array $plan): void
|
||||
public function action(string $databaseId, string $documentId, string $collectionId, string|array $data, ?array $permissions, ?array $documents, ?string $transactionId, UtopiaResponse $response, Database $dbForProject, Document $user, Event $queueForEvents, StatsUsage $queueForStatsUsage, Event $queueForRealtime, Event $queueForFunctions, Event $queueForWebhooks, array $plan, EventProcessor $eventProcessor): void
|
||||
{
|
||||
$data = \is_string($data)
|
||||
? \json_decode($data, true)
|
||||
@@ -492,7 +494,8 @@ class Create extends Action
|
||||
$queueForRealtime,
|
||||
$queueForFunctions,
|
||||
$queueForWebhooks,
|
||||
$dbForProject
|
||||
$dbForProject,
|
||||
$eventProcessor
|
||||
);
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -7,6 +7,7 @@ use Appwrite\Event\Delete;
|
||||
use Appwrite\Event\Event;
|
||||
use Appwrite\Event\StatsUsage;
|
||||
use Appwrite\Extend\Exception;
|
||||
use Appwrite\Functions\EventProcessor;
|
||||
use Appwrite\SDK\AuthType;
|
||||
use Appwrite\SDK\ContentType;
|
||||
use Appwrite\SDK\Method;
|
||||
@@ -76,6 +77,7 @@ class Update extends Action
|
||||
->inject('queueForRealtime')
|
||||
->inject('queueForFunctions')
|
||||
->inject('queueForWebhooks')
|
||||
->inject('eventProcessor')
|
||||
->callback($this->action(...));
|
||||
}
|
||||
|
||||
@@ -93,6 +95,7 @@ class Update extends Action
|
||||
* @param Event $queueForRealtime
|
||||
* @param Event $queueForFunctions
|
||||
* @param Event $queueForWebhooks
|
||||
* @param EventProcessor $eventProcessor
|
||||
* @return void
|
||||
* @throws ConflictException
|
||||
* @throws Exception
|
||||
@@ -102,7 +105,7 @@ class Update extends Action
|
||||
* @throws Structure
|
||||
* @throws \Utopia\Exception
|
||||
*/
|
||||
public function action(string $transactionId, bool $commit, bool $rollback, UtopiaResponse $response, Database $dbForProject, Document $user, TransactionState $transactionState, Delete $queueForDeletes, Event $queueForEvents, StatsUsage $queueForStatsUsage, Event $queueForRealtime, Event $queueForFunctions, Event $queueForWebhooks): void
|
||||
public function action(string $transactionId, bool $commit, bool $rollback, UtopiaResponse $response, Database $dbForProject, Document $user, TransactionState $transactionState, Delete $queueForDeletes, Event $queueForEvents, StatsUsage $queueForStatsUsage, Event $queueForRealtime, Event $queueForFunctions, Event $queueForWebhooks, EventProcessor $eventProcessor): void
|
||||
{
|
||||
if (!$commit && !$rollback) {
|
||||
throw new Exception(Exception::GENERAL_BAD_REQUEST, 'Either commit or rollback must be true');
|
||||
@@ -372,8 +375,8 @@ class Update extends Action
|
||||
|
||||
// Get project and function/webhook events (cached)
|
||||
$project = $queueForEvents->getProject();
|
||||
$functionsEvents = $this->getFunctionsEvents($project, $dbForProject);
|
||||
$webhooksEvents = $this->getWebhooksEvents($project);
|
||||
$functionsEvents = $eventProcessor->getFunctionsEvents($project, $dbForProject);
|
||||
$webhooksEvents = $eventProcessor->getWebhooksEvents($project);
|
||||
|
||||
foreach ($documentsToTrigger as $doc) {
|
||||
$payload = $doc->getArrayCopy();
|
||||
|
||||
@@ -66,6 +66,7 @@ class Delete extends DocumentsDelete
|
||||
->inject('queueForFunctions')
|
||||
->inject('queueForWebhooks')
|
||||
->inject('plan')
|
||||
->inject('eventProcessor')
|
||||
->callback($this->action(...));
|
||||
}
|
||||
}
|
||||
|
||||
@@ -68,6 +68,7 @@ class Update extends DocumentsUpdate
|
||||
->inject('queueForFunctions')
|
||||
->inject('queueForWebhooks')
|
||||
->inject('plan')
|
||||
->inject('eventProcessor')
|
||||
->callback($this->action(...));
|
||||
}
|
||||
}
|
||||
|
||||
@@ -68,6 +68,7 @@ class Upsert extends DocumentsUpsert
|
||||
->inject('queueForFunctions')
|
||||
->inject('queueForWebhooks')
|
||||
->inject('plan')
|
||||
->inject('eventProcessor')
|
||||
->callback($this->action(...));
|
||||
}
|
||||
}
|
||||
|
||||
@@ -111,6 +111,7 @@ class Create extends DocumentCreate
|
||||
->inject('queueForFunctions')
|
||||
->inject('queueForWebhooks')
|
||||
->inject('plan')
|
||||
->inject('eventProcessor')
|
||||
->callback($this->action(...));
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user