2023-06-05 16:13:00 +00:00
< ? php
namespace Appwrite\Platform\Workers ;
use Appwrite\Event\Event ;
use Appwrite\Event\Func ;
2023-10-25 07:39:59 +00:00
use Appwrite\Event\Usage ;
2023-06-05 16:13:00 +00:00
use Appwrite\Messaging\Adapter\Realtime ;
use Appwrite\Utopia\Response\Model\Execution ;
use Exception ;
use Executor\Executor ;
use Utopia\CLI\Console ;
use Utopia\Config\Config ;
use Utopia\Database\Database ;
use Utopia\Database\Document ;
use Utopia\Database\Exception\Authorization ;
2023-10-15 17:41:09 +00:00
use Utopia\Database\Exception\Conflict ;
2023-06-05 16:13:00 +00:00
use Utopia\Database\Exception\Structure ;
use Utopia\Database\Helpers\ID ;
use Utopia\Database\Helpers\Permission ;
use Utopia\Database\Helpers\Role ;
use Utopia\Database\Query ;
2023-09-28 17:37:07 +00:00
use Utopia\Logger\Log ;
2023-06-05 16:13:00 +00:00
use Utopia\Platform\Action ;
use Utopia\Queue\Message ;
2024-04-01 11:02:47 +00:00
use Utopia\System\System ;
2023-06-05 16:13:00 +00:00
class Functions extends Action
{
public static function getName () : string
{
return 'functions' ;
}
/**
* @ throws Exception
*/
public function __construct ()
{
$this
-> desc ( 'Functions worker' )
2023-12-12 20:33:02 +00:00
-> groups ([ 'functions' ])
2023-06-05 16:13:00 +00:00
-> inject ( 'message' )
-> inject ( 'dbForProject' )
-> inject ( 'queueForFunctions' )
2023-06-11 10:29:04 +00:00
-> inject ( 'queueForEvents' )
2023-10-25 07:39:59 +00:00
-> inject ( 'queueForUsage' )
2023-09-28 17:37:07 +00:00
-> inject ( 'log' )
2024-03-06 17:34:21 +00:00
-> callback ( fn ( Message $message , Database $dbForProject , Func $queueForFunctions , Event $queueForEvents , Usage $queueForUsage , Log $log ) => $this -> action ( $message , $dbForProject , $queueForFunctions , $queueForEvents , $queueForUsage , $log ));
2023-06-05 16:13:00 +00:00
}
/**
2023-10-01 17:39:26 +00:00
* @ param Message $message
* @ param Database $dbForProject
* @ param Func $queueForFunctions
* @ param Event $queueForEvents
2023-10-25 07:39:59 +00:00
* @ param Usage $queueForUsage
2023-10-01 17:39:26 +00:00
* @ param Log $log
* @ return void
2023-10-15 17:41:09 +00:00
* @ throws Authorization
* @ throws Structure
* @ throws \Utopia\Database\Exception
* @ throws Conflict
2023-06-05 16:13:00 +00:00
*/
2023-10-25 07:39:59 +00:00
public function action ( Message $message , Database $dbForProject , Func $queueForFunctions , Event $queueForEvents , Usage $queueForUsage , Log $log ) : void
2023-06-05 16:13:00 +00:00
{
$payload = $message -> getPayload () ? ? [];
if ( empty ( $payload )) {
throw new Exception ( 'Missing payload' );
}
$payload = $message -> getPayload () ? ? [];
if ( empty ( $payload )) {
throw new Exception ( 'Missing payload' );
}
$type = $payload [ 'type' ] ? ? '' ;
$events = $payload [ 'events' ] ? ? [];
2023-10-23 13:33:26 +00:00
$data = $payload [ 'body' ] ? ? '' ;
2023-06-05 16:13:00 +00:00
$eventData = $payload [ 'payload' ] ? ? '' ;
$project = new Document ( $payload [ 'project' ] ? ? []);
$function = new Document ( $payload [ 'function' ] ? ? []);
$user = new Document ( $payload [ 'user' ] ? ? []);
2023-09-28 17:37:07 +00:00
$method = $payload [ 'method' ] ? ? 'POST' ;
$headers = $payload [ 'headers' ] ? ? [];
$path = $payload [ 'path' ] ? ? '/' ;
2023-06-05 16:13:00 +00:00
if ( $project -> getId () === 'console' ) {
return ;
}
2023-11-22 13:50:57 +00:00
$log -> addTag ( 'functionId' , $function -> getId ());
$log -> addTag ( 'projectId' , $project -> getId ());
$log -> addTag ( 'type' , $type );
2023-06-05 16:13:00 +00:00
if ( ! empty ( $events )) {
$limit = 30 ;
$sum = 30 ;
$offset = 0 ;
/** @var Document[] $functions */
while ( $sum >= $limit ) {
$functions = $dbForProject -> find ( 'functions' , [
Query :: limit ( $limit ),
Query :: offset ( $offset ),
Query :: orderAsc ( 'name' ),
]);
$sum = \count ( $functions );
$offset = $offset + $limit ;
Console :: log ( 'Fetched ' . $sum . ' functions...' );
foreach ( $functions as $function ) {
if ( ! array_intersect ( $events , $function -> getAttribute ( 'events' , []))) {
continue ;
}
Console :: success ( 'Iterating function: ' . $function -> getAttribute ( 'name' ));
$this -> execute (
2023-09-28 17:37:07 +00:00
log : $log ,
2023-06-05 16:13:00 +00:00
dbForProject : $dbForProject ,
queueForFunctions : $queueForFunctions ,
2023-10-25 07:39:59 +00:00
queueForUsage : $queueForUsage ,
2023-09-28 17:37:07 +00:00
queueForEvents : $queueForEvents ,
2023-06-05 16:13:00 +00:00
project : $project ,
function : $function ,
trigger : 'event' ,
2023-09-28 17:37:07 +00:00
path : '/' ,
method : 'POST' ,
headers : [
2023-10-17 16:23:10 +00:00
'user-agent' => 'Appwrite/' . APP_VERSION_STABLE ,
'content-type' => 'application/json'
2023-09-28 17:37:07 +00:00
],
data : null ,
2023-06-05 16:13:00 +00:00
user : $user ,
2023-09-28 17:37:07 +00:00
jwt : null ,
2023-06-05 16:13:00 +00:00
event : $events [ 0 ],
eventData : \is_string ( $eventData ) ? $eventData : \json_encode ( $eventData ),
2023-09-28 17:37:07 +00:00
executionId : null ,
2023-06-05 16:13:00 +00:00
);
Console :: success ( 'Triggered function: ' . $events [ 0 ]);
}
}
return ;
}
/**
* Handle Schedule and HTTP execution .
*/
switch ( $type ) {
case 'http' :
$jwt = $payload [ 'jwt' ] ? ? '' ;
$execution = new Document ( $payload [ 'execution' ] ? ? []);
$user = new Document ( $payload [ 'user' ] ? ? []);
$this -> execute (
2023-09-28 17:37:07 +00:00
log : $log ,
2023-06-05 16:13:00 +00:00
dbForProject : $dbForProject ,
queueForFunctions : $queueForFunctions ,
2023-10-25 07:39:59 +00:00
queueForUsage : $queueForUsage ,
2023-09-28 17:37:07 +00:00
queueForEvents : $queueForEvents ,
2023-06-05 16:13:00 +00:00
project : $project ,
function : $function ,
trigger : 'http' ,
2023-09-28 17:37:07 +00:00
path : $path ,
method : $method ,
headers : $headers ,
2023-06-05 16:13:00 +00:00
data : $data ,
user : $user ,
jwt : $jwt ,
2023-09-28 17:37:07 +00:00
event : null ,
eventData : null ,
executionId : $execution -> getId ()
2023-06-05 16:13:00 +00:00
);
break ;
case 'schedule' :
$this -> execute (
2023-09-28 17:37:07 +00:00
log : $log ,
2023-06-05 16:13:00 +00:00
dbForProject : $dbForProject ,
queueForFunctions : $queueForFunctions ,
2023-10-25 07:39:59 +00:00
queueForUsage : $queueForUsage ,
2023-09-28 17:37:07 +00:00
queueForEvents : $queueForEvents ,
2023-06-05 16:13:00 +00:00
project : $project ,
function : $function ,
trigger : 'schedule' ,
2023-09-28 17:37:07 +00:00
path : $path ,
method : $method ,
headers : $headers ,
data : null ,
user : null ,
jwt : null ,
event : null ,
eventData : null ,
executionId : null ,
2023-06-05 16:13:00 +00:00
);
break ;
}
}
2024-04-01 11:34:36 +00:00
/**
2024-04-01 13:37:17 +00:00
* @ param string $message
2024-04-01 11:34:36 +00:00
* @ param Document $function
* @ param string $trigger
* @ param string $path
* @ param string $method
* @ param Document $user
2024-04-01 11:48:42 +00:00
* @ param string | null $jwt
* @ param string | null $event
2024-04-01 11:34:36 +00:00
* @ throws Exception
*/
private function fail (
2024-04-01 13:37:17 +00:00
string $message ,
2024-04-01 11:34:36 +00:00
Database $dbForProject ,
Document $function ,
string $trigger ,
string $path ,
string $method ,
Document $user ,
2024-04-01 11:48:42 +00:00
string $jwt = null ,
string $event = null ,
2024-04-01 11:34:36 +00:00
) : void {
2024-04-01 11:48:42 +00:00
$headers [ 'x-appwrite-trigger' ] = $trigger ;
$headers [ 'x-appwrite-event' ] = $event ? ? '' ;
$headers [ 'x-appwrite-user-id' ] = $user -> getId () ? ? '' ;
$headers [ 'x-appwrite-user-jwt' ] = $jwt ? ? '' ;
$headersFiltered = [];
foreach ( $headers as $key => $value ) {
if ( \in_array ( \strtolower ( $key ), FUNCTION_ALLOWLIST_HEADERS_REQUEST )) {
$headersFiltered [] = [ 'name' => $key , 'value' => $value ];
}
}
2024-04-01 11:34:36 +00:00
$executionId = ID :: unique ();
$execution = new Document ([
'$id' => $executionId ,
'$permissions' => $user -> isEmpty () ? [] : [ Permission :: read ( Role :: user ( $user -> getId ()))],
'functionInternalId' => $function -> getInternalId (),
'functionId' => $function -> getId (),
'deploymentInternalId' => '' ,
'deploymentId' => '' ,
'trigger' => $trigger ,
'status' => 'failed' ,
2024-04-01 14:07:51 +00:00
'responseStatusCode' => 0 ,
2024-04-01 11:34:36 +00:00
'responseHeaders' => [],
'requestPath' => $path ,
'requestMethod' => $method ,
2024-04-01 11:48:42 +00:00
'requestHeaders' => $headersFiltered ,
2024-04-01 13:37:17 +00:00
'errors' => $message ,
2024-04-01 11:34:36 +00:00
'logs' => '' ,
'duration' => 0.0 ,
'search' => implode ( ' ' , [ $function -> getId (), $executionId ]),
]);
if ( $function -> getAttribute ( 'logging' )) {
$execution = $dbForProject -> createDocument ( 'executions' , $execution );
}
if ( $execution -> isEmpty ()) {
throw new Exception ( 'Failed to create execution' );
}
}
2023-06-05 16:13:00 +00:00
/**
2023-10-01 17:39:26 +00:00
* @ param Log $log
* @ param Database $dbForProject
* @ param Func $queueForFunctions
2023-10-25 07:39:59 +00:00
* @ param Usage $queueForUsage
2023-10-01 17:39:26 +00:00
* @ param Event $queueForEvents
* @ param Document $project
* @ param Document $function
* @ param string $trigger
* @ param string $path
* @ param string $method
* @ param array $headers
* @ param string | null $data
* @ param Document | null $user
* @ param string | null $jwt
* @ param string | null $event
* @ param string | null $eventData
* @ param string | null $executionId
* @ return void
2023-06-05 16:13:00 +00:00
* @ throws Authorization
* @ throws Structure
2023-10-01 17:39:26 +00:00
* @ throws \Utopia\Database\Exception
2023-10-15 17:41:09 +00:00
* @ throws Conflict
2023-06-05 16:13:00 +00:00
*/
private function execute (
2023-09-28 17:37:07 +00:00
Log $log ,
2023-06-05 16:13:00 +00:00
Database $dbForProject ,
Func $queueForFunctions ,
2023-10-25 07:39:59 +00:00
Usage $queueForUsage ,
2023-09-28 17:37:07 +00:00
Event $queueForEvents ,
2023-06-05 16:13:00 +00:00
Document $project ,
Document $function ,
string $trigger ,
2023-09-28 17:37:07 +00:00
string $path ,
string $method ,
array $headers ,
2023-06-05 16:13:00 +00:00
string $data = null ,
? Document $user = null ,
string $jwt = null ,
string $event = null ,
string $eventData = null ,
string $executionId = null ,
) : void {
2023-11-22 13:50:57 +00:00
$user ? ? = new Document ();
$functionId = $function -> getId ();
$deploymentId = $function -> getAttribute ( 'deployment' , '' );
2023-06-05 16:13:00 +00:00
2023-11-22 13:50:57 +00:00
$log -> addTag ( 'deploymentId' , $deploymentId );
2023-09-28 17:37:07 +00:00
2023-11-22 13:50:57 +00:00
/** Check if deployment exists */
$deployment = $dbForProject -> getDocument ( 'deployments' , $deploymentId );
2023-06-05 16:13:00 +00:00
if ( $deployment -> getAttribute ( 'resourceId' ) !== $functionId ) {
2024-04-01 13:37:17 +00:00
$errorMessage = 'The execution could not be completed because a corresponding deployment was not found. A function deployment needs to be created before it can be executed. Please create a deployment for your function and try again.' ;
$this -> fail ( $errorMessage , $dbForProject , $function , $trigger , $path , $method , $user , $jwt , $event );
2024-04-01 11:34:36 +00:00
return ;
2023-06-05 16:13:00 +00:00
}
if ( $deployment -> isEmpty ()) {
2024-04-01 13:37:17 +00:00
$errorMessage = 'The execution could not be completed because a corresponding deployment was not found. A function deployment needs to be created before it can be executed. Please create a deployment for your function and try again.' ;
$this -> fail ( $errorMessage , $dbForProject , $function , $trigger , $path , $method , $user , $jwt , $event );
2024-04-01 11:34:36 +00:00
return ;
2023-06-05 16:13:00 +00:00
}
2023-11-22 13:50:57 +00:00
$buildId = $deployment -> getAttribute ( 'buildId' , '' );
$log -> addTag ( 'buildId' , $buildId );
/** Check if build has exists */
$build = $dbForProject -> getDocument ( 'builds' , $buildId );
2023-06-05 16:13:00 +00:00
if ( $build -> isEmpty ()) {
2024-04-01 14:07:51 +00:00
$errorMessage = 'The execution could not be completed because a corresponding deployment was not found. A function deployment needs to be created before it can be executed. Please create a deployment for your function and try again.' ;
2024-04-01 13:37:17 +00:00
$this -> fail ( $errorMessage , $dbForProject , $function , $trigger , $path , $method , $user , $jwt , $event );
return ;
2023-06-05 16:13:00 +00:00
}
if ( $build -> getAttribute ( 'status' ) !== 'ready' ) {
2024-04-01 13:37:17 +00:00
$errorMessage = 'The execution could not be completed because the build is not ready. Please wait for the build to complete and try again.' ;
$this -> fail ( $errorMessage , $dbForProject , $function , $trigger , $path , $method , $user , $jwt , $event );
return ;
2023-06-05 16:13:00 +00:00
}
2023-11-22 13:50:57 +00:00
/** Check if runtime is supported */
2023-09-28 17:37:07 +00:00
$version = $function -> getAttribute ( 'version' , 'v2' );
$runtimes = Config :: getParam ( $version === 'v2' ? 'runtimes-v2' : 'runtimes' , []);
2023-06-05 16:13:00 +00:00
if ( ! \array_key_exists ( $function -> getAttribute ( 'runtime' ), $runtimes )) {
throw new Exception ( 'Runtime "' . $function -> getAttribute ( 'runtime' , '' ) . '" is not supported' );
}
2023-09-28 17:37:07 +00:00
$runtime = $runtimes [ $function -> getAttribute ( 'runtime' )];
2023-06-05 16:13:00 +00:00
2023-09-28 17:37:07 +00:00
$headers [ 'x-appwrite-trigger' ] = $trigger ;
$headers [ 'x-appwrite-event' ] = $event ? ? '' ;
$headers [ 'x-appwrite-user-id' ] = $user -> getId () ? ? '' ;
$headers [ 'x-appwrite-user-jwt' ] = $jwt ? ? '' ;
/** Create execution or update execution status */
$execution = $dbForProject -> getDocument ( 'executions' , $executionId ? ? '' );
2023-06-05 16:13:00 +00:00
if ( $execution -> isEmpty ()) {
2023-09-28 17:37:07 +00:00
$headersFiltered = [];
foreach ( $headers as $key => $value ) {
if ( \in_array ( \strtolower ( $key ), FUNCTION_ALLOWLIST_HEADERS_REQUEST )) {
$headersFiltered [] = [ 'name' => $key , 'value' => $value ];
}
}
2023-06-05 16:13:00 +00:00
$executionId = ID :: unique ();
2023-09-28 17:37:07 +00:00
$execution = new Document ([
2023-06-05 16:13:00 +00:00
'$id' => $executionId ,
'$permissions' => $user -> isEmpty () ? [] : [ Permission :: read ( Role :: user ( $user -> getId ()))],
2023-09-28 17:37:07 +00:00
'functionInternalId' => $function -> getInternalId (),
'functionId' => $function -> getId (),
'deploymentInternalId' => $deployment -> getInternalId (),
'deploymentId' => $deployment -> getId (),
2023-06-05 16:13:00 +00:00
'trigger' => $trigger ,
2023-09-28 17:37:07 +00:00
'status' => 'processing' ,
'responseStatusCode' => 0 ,
'responseHeaders' => [],
'requestPath' => $path ,
'requestMethod' => $method ,
'requestHeaders' => $headersFiltered ,
'errors' => '' ,
'logs' => '' ,
2023-06-05 16:13:00 +00:00
'duration' => 0.0 ,
2023-09-28 17:37:07 +00:00
'search' => implode ( ' ' , [ $functionId , $executionId ]),
]);
if ( $function -> getAttribute ( 'logging' )) {
$execution = $dbForProject -> createDocument ( 'executions' , $execution );
}
2023-06-05 16:13:00 +00:00
// TODO: @Meldiron Trigger executions.create event here
if ( $execution -> isEmpty ()) {
throw new Exception ( 'Failed to create or read execution' );
}
}
2023-09-28 17:37:07 +00:00
if ( $execution -> getAttribute ( 'status' ) !== 'processing' ) {
2023-06-05 16:13:00 +00:00
$execution -> setAttribute ( 'status' , 'processing' );
2023-09-28 17:37:07 +00:00
if ( $function -> getAttribute ( 'logging' )) {
$execution = $dbForProject -> updateDocument ( 'executions' , $executionId , $execution );
}
}
$durationStart = \microtime ( true );
2023-06-05 16:13:00 +00:00
2023-09-28 17:37:07 +00:00
$body = $eventData ? ? '' ;
if ( empty ( $body )) {
$body = $data ? ? '' ;
}
$vars = [];
// V2 vars
if ( $version === 'v2' ) {
2023-06-05 16:13:00 +00:00
$vars = \array_merge ( $vars , [
2023-09-28 17:37:07 +00:00
'APPWRITE_FUNCTION_TRIGGER' => $headers [ 'x-appwrite-trigger' ] ? ? '' ,
'APPWRITE_FUNCTION_DATA' => $body ? ? '' ,
'APPWRITE_FUNCTION_EVENT_DATA' => $body ? ? '' ,
'APPWRITE_FUNCTION_EVENT' => $headers [ 'x-appwrite-event' ] ? ? '' ,
'APPWRITE_FUNCTION_USER_ID' => $headers [ 'x-appwrite-user-id' ] ? ? '' ,
'APPWRITE_FUNCTION_JWT' => $headers [ 'x-appwrite-user-jwt' ] ? ? ''
2023-06-05 16:13:00 +00:00
]);
2023-09-28 17:37:07 +00:00
}
// Shared vars
foreach ( $function -> getAttribute ( 'varsProject' , []) as $var ) {
$vars [ $var -> getAttribute ( 'key' )] = $var -> getAttribute ( 'value' , '' );
}
2023-06-05 16:13:00 +00:00
2023-09-28 17:37:07 +00:00
// Function vars
foreach ( $function -> getAttribute ( 'vars' , []) as $var ) {
$vars [ $var -> getAttribute ( 'key' )] = $var -> getAttribute ( 'value' , '' );
}
// Appwrite vars
$vars = \array_merge ( $vars , [
'APPWRITE_FUNCTION_ID' => $functionId ,
'APPWRITE_FUNCTION_NAME' => $function -> getAttribute ( 'name' ),
'APPWRITE_FUNCTION_DEPLOYMENT' => $deploymentId ,
'APPWRITE_FUNCTION_PROJECT_ID' => $project -> getId (),
'APPWRITE_FUNCTION_RUNTIME_NAME' => $runtime [ 'name' ] ? ? '' ,
'APPWRITE_FUNCTION_RUNTIME_VERSION' => $runtime [ 'version' ] ? ? '' ,
]);
/** Execute function */
2023-06-05 16:13:00 +00:00
try {
2023-09-28 17:37:07 +00:00
$version = $function -> getAttribute ( 'version' , 'v2' );
$command = $runtime [ 'startCommand' ];
2024-04-01 11:02:47 +00:00
$executor = new Executor ( System :: getEnv ( '_APP_EXECUTOR_HOST' ));
2023-09-28 17:37:07 +00:00
$command = $version === 'v2' ? '' : 'cp /tmp/code.tar.gz /mnt/code/code.tar.gz && nohup helpers/start.sh "' . $command . '"' ;
$executionResponse = $executor -> createExecution (
2023-06-05 16:13:00 +00:00
projectId : $project -> getId (),
deploymentId : $deploymentId ,
2023-09-28 17:37:07 +00:00
body : \strlen ( $body ) > 0 ? $body : null ,
2023-06-05 16:13:00 +00:00
variables : $vars ,
timeout : $function -> getAttribute ( 'timeout' , 0 ),
image : $runtime [ 'image' ],
2023-09-28 17:37:07 +00:00
source : $build -> getAttribute ( 'path' , '' ),
2023-06-05 16:13:00 +00:00
entrypoint : $deployment -> getAttribute ( 'entrypoint' , '' ),
2023-09-28 17:37:07 +00:00
version : $version ,
path : $path ,
method : $method ,
headers : $headers ,
runtimeEntrypoint : $command
2023-06-05 16:13:00 +00:00
);
2023-09-28 17:37:07 +00:00
$status = $executionResponse [ 'statusCode' ] >= 400 ? 'failed' : 'completed' ;
$headersFiltered = [];
foreach ( $executionResponse [ 'headers' ] as $key => $value ) {
if ( \in_array ( \strtolower ( $key ), FUNCTION_ALLOWLIST_HEADERS_RESPONSE )) {
$headersFiltered [] = [ 'name' => $key , 'value' => $value ];
}
}
2023-06-05 16:13:00 +00:00
/** Update execution status */
$execution
2023-09-28 17:37:07 +00:00
-> setAttribute ( 'status' , $status )
-> setAttribute ( 'responseStatusCode' , $executionResponse [ 'statusCode' ])
-> setAttribute ( 'responseHeaders' , $headersFiltered )
-> setAttribute ( 'logs' , $executionResponse [ 'logs' ])
-> setAttribute ( 'errors' , $executionResponse [ 'errors' ])
2023-06-05 16:13:00 +00:00
-> setAttribute ( 'duration' , $executionResponse [ 'duration' ]);
} catch ( \Throwable $th ) {
2023-09-28 17:37:07 +00:00
$durationEnd = \microtime ( true );
2023-06-05 16:13:00 +00:00
$execution
2023-09-28 17:37:07 +00:00
-> setAttribute ( 'duration' , $durationEnd - $durationStart )
2023-06-05 16:13:00 +00:00
-> setAttribute ( 'status' , 'failed' )
2023-09-28 17:37:07 +00:00
-> setAttribute ( 'responseStatusCode' , 500 )
-> setAttribute ( 'errors' , $th -> getMessage () . '\nError Code: ' . $th -> getCode ());
2023-06-05 16:13:00 +00:00
2023-09-28 17:37:07 +00:00
$error = $th -> getMessage ();
$errorCode = $th -> getCode ();
2023-12-14 04:49:16 +00:00
} finally {
2023-12-12 19:21:47 +00:00
/** Trigger usage queue */
$queueForUsage
-> setProject ( $project )
-> addMetric ( METRIC_EXECUTIONS , 1 )
-> addMetric ( str_replace ( '{functionInternalId}' , $function -> getInternalId (), METRIC_FUNCTION_ID_EXECUTIONS ), 1 )
2023-12-12 19:55:01 +00:00
-> addMetric ( METRIC_EXECUTIONS_COMPUTE , ( int )( $execution -> getAttribute ( 'duration' ) * 1000 )) // per project
-> addMetric ( str_replace ( '{functionInternalId}' , $function -> getInternalId (), METRIC_FUNCTION_ID_EXECUTIONS_COMPUTE ), ( int )( $execution -> getAttribute ( 'duration' ) * 1000 ))
2023-12-12 19:21:47 +00:00
-> trigger ()
;
2023-06-05 16:13:00 +00:00
}
2023-09-28 17:37:07 +00:00
if ( $function -> getAttribute ( 'logging' )) {
2023-06-05 16:13:00 +00:00
$execution = $dbForProject -> updateDocument ( 'executions' , $executionId , $execution );
2023-09-28 17:37:07 +00:00
}
/** Trigger Webhook */
$executionModel = new Execution ();
$queueForEvents
-> setQueue ( Event :: WEBHOOK_QUEUE_NAME )
-> setClass ( Event :: WEBHOOK_CLASS_NAME )
-> setProject ( $project )
-> setUser ( $user )
-> setEvent ( 'functions.[functionId].executions.[executionId].update' )
-> setParam ( 'functionId' , $function -> getId ())
-> setParam ( 'executionId' , $execution -> getId ())
-> setPayload ( $execution -> getArrayCopy ( array_keys ( $executionModel -> getRules ())))
-> trigger ();
/** Trigger Functions */
$queueForFunctions
-> from ( $queueForEvents )
-> trigger ();
/** Trigger realtime event */
$allEvents = Event :: generateEvents ( 'functions.[functionId].executions.[executionId].update' , [
'functionId' => $function -> getId (),
'executionId' => $execution -> getId ()
]);
$target = Realtime :: fromPayload (
2024-03-06 17:34:21 +00:00
// Pass first, most verbose event pattern
2023-09-28 17:37:07 +00:00
event : $allEvents [ 0 ],
payload : $execution
);
Realtime :: send (
projectId : 'console' ,
payload : $execution -> getArrayCopy (),
events : $allEvents ,
channels : $target [ 'channels' ],
roles : $target [ 'roles' ]
);
Realtime :: send (
projectId : $project -> getId (),
payload : $execution -> getArrayCopy (),
events : $allEvents ,
channels : $target [ 'channels' ],
roles : $target [ 'roles' ]
);
if ( ! empty ( $error )) {
throw new Exception ( $error , $errorCode );
}
2023-06-05 16:13:00 +00:00
}
}