feat: remove database dependencies from the create execution endpoint
This commit is contained in:
parent
c239240cbc
commit
7f1df839ec
|
@ -769,6 +769,16 @@ App::post('/v1/functions/:functionId/executions')
|
|||
throw new Exception('Deployment not found. Deploy deployment before trying to execute a function', 404);
|
||||
}
|
||||
|
||||
/** Check if build has completed */
|
||||
$build = Authorization::skip(fn() => $dbForProject->getDocument('builds', $deployment->getAttribute('buildId', '')));
|
||||
if ($build->isEmpty()) {
|
||||
throw new Exception('Build not found', 404);
|
||||
}
|
||||
|
||||
if ($build->getAttribute('status') !== 'ready') {
|
||||
throw new Exception('Build not completed', 400);
|
||||
}
|
||||
|
||||
$validator = new Authorization('execute');
|
||||
|
||||
if (!$validator->isValid($function->getAttribute('execute'))) { // Check if user has write access to execute function
|
||||
|
@ -817,13 +827,20 @@ App::post('/v1/functions/:functionId/executions')
|
|||
if ($async) {
|
||||
Resque::enqueue('v1-functions', 'FunctionsV1', [
|
||||
'projectId' => $project->getId(),
|
||||
'deploymentId' => $deployment->getId(),
|
||||
'buildId' => $deployment->getAttribute('buildId', ''),
|
||||
'path' => $build->getAttribute('outputPath', ''),
|
||||
'vars' => $function->getAttribute('vars', []),
|
||||
'data' => $data,
|
||||
'runtime' => $function->getAttribute('runtime', ''),
|
||||
'timeout' => $function->getAttribute('timeout', 0),
|
||||
'baseImage' => '',
|
||||
'webhooks' => $project->getAttribute('webhooks', []),
|
||||
'userId' => $user->getId(),
|
||||
'functionId' => $function->getId(),
|
||||
'executionId' => $execution->getId(),
|
||||
'trigger' => 'http',
|
||||
'data' => $data,
|
||||
'userId' => $user->getId(),
|
||||
'jwt' => $jwt
|
||||
'jwt' => $jwt,
|
||||
]);
|
||||
|
||||
$response->setStatusCode(Response::STATUS_CODE_CREATED);
|
||||
|
@ -831,18 +848,38 @@ App::post('/v1/functions/:functionId/executions')
|
|||
return $response;
|
||||
}
|
||||
|
||||
/** Send variables */
|
||||
// $vars = \array_merge($function->getAttribute('vars', []), [
|
||||
// 'ENTRYPOINT_NAME' => $deployment->getAttribute('entrypoint', ''),
|
||||
// 'APPWRITE_FUNCTION_ID' => $function->getId(),
|
||||
// 'APPWRITE_FUNCTION_NAME' => $function->getAttribute('name', ''),
|
||||
// 'APPWRITE_FUNCTION_DEPLOYMENT' => $deployment->getId(),
|
||||
// 'APPWRITE_FUNCTION_TRIGGER' => 'http',
|
||||
// 'APPWRITE_FUNCTION_RUNTIME_NAME' => $runtime['name'],
|
||||
// 'APPWRITE_FUNCTION_RUNTIME_VERSION' => $runtime['version'],
|
||||
// 'APPWRITE_FUNCTION_EVENT' => $event,
|
||||
// 'APPWRITE_FUNCTION_EVENT_DATA' => $eventData,
|
||||
// 'APPWRITE_FUNCTION_DATA' => $data,
|
||||
// 'APPWRITE_FUNCTION_USER_ID' => $userId,
|
||||
// 'APPWRITE_FUNCTION_JWT' => $jwt,
|
||||
// 'APPWRITE_FUNCTION_PROJECT_ID' => $projectId
|
||||
// ]);
|
||||
|
||||
// Directly execute function.
|
||||
$ch = \curl_init();
|
||||
\curl_setopt($ch, CURLOPT_URL, "http://appwrite-executor/v1/functions/{$function->getId()}/executions");
|
||||
\curl_setopt($ch, CURLOPT_POST, true);
|
||||
\curl_setopt($ch, CURLOPT_POSTFIELDS, json_encode([
|
||||
'trigger' => 'http',
|
||||
'projectId' => $project->getId(),
|
||||
'executionId' => $execution->getId(),
|
||||
'deploymentId' => $deployment->getId(),
|
||||
'buildId' => $deployment->getAttribute('buildId', ''),
|
||||
'path' => $build->getAttribute('outputPath', ''),
|
||||
'vars' => $function->getAttribute('vars', []),
|
||||
'data' => $data,
|
||||
'runtime' => $function->getAttribute('runtime', ''),
|
||||
'timeout' => $function->getAttribute('timeout', 0),
|
||||
'baseImage' => '',
|
||||
'webhooks' => $project->getAttribute('webhooks', []),
|
||||
'userId' => $user->getId(),
|
||||
'jwt' => $jwt,
|
||||
]));
|
||||
\curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
|
||||
\curl_setopt($ch, CURLOPT_TIMEOUT, App::getEnv('_APP_FUNCTIONS_TIMEOUT', 900) + 200); // + 200 for safety margin
|
||||
|
|
317
app/executor.php
317
app/executor.php
|
@ -7,6 +7,7 @@ use Appwrite\Stats\Stats;
|
|||
use Appwrite\Utopia\Response;
|
||||
use Appwrite\Utopia\Response\Model\Execution;
|
||||
use Cron\CronExpression;
|
||||
use LanguageServerProtocol\Range;
|
||||
use Swoole\ConnectionPool;
|
||||
use Swoole\Coroutine as Co;
|
||||
use Swoole\Http\Request as SwooleRequest;
|
||||
|
@ -34,6 +35,7 @@ use Utopia\Swoole\Request;
|
|||
use Utopia\Validator\ArrayList;
|
||||
use Utopia\Validator\Assoc;
|
||||
use Utopia\Validator\JSON;
|
||||
use Utopia\Validator\Range as ValidatorRange;
|
||||
use Utopia\Validator\Text;
|
||||
|
||||
require_once __DIR__ . '/init.php';
|
||||
|
@ -161,7 +163,6 @@ function createRuntimeServer(string $projectId, string $deploymentId, array $bui
|
|||
$orchestration = $orchestrationPool->get();
|
||||
|
||||
try {
|
||||
|
||||
$container = 'appwrite-function-' . $deploymentId;
|
||||
if ($activeFunctions->exists($container) && !(\substr($activeFunctions->get($container)['status'], 0, 2) === 'Up')) { // Remove container if not online
|
||||
// If container is online then stop and remove it
|
||||
|
@ -170,7 +171,6 @@ function createRuntimeServer(string $projectId, string $deploymentId, array $bui
|
|||
} catch (Exception $e) {
|
||||
throw new Exception('Failed to remove container: ' . $e->getMessage());
|
||||
}
|
||||
|
||||
$activeFunctions->del($container);
|
||||
}
|
||||
|
||||
|
@ -268,172 +268,38 @@ function createRuntimeServer(string $projectId, string $deploymentId, array $bui
|
|||
}
|
||||
};
|
||||
|
||||
function execute(string $trigger, string $projectId, string $executionId, string $functionId, Database $database, string $event = '', string $eventData = '', string $data = '', array $webhooks = [], string $userId = '', string $jwt = ''): array
|
||||
function execute(string $projectId, string $functionId, string $deploymentId, array $build, array $vars, string $data, string $userId, string $baseImage, string $runtime, int $timeout, array $webhooks = []): array
|
||||
{
|
||||
|
||||
Console::info('Executing function: ' . $functionId);
|
||||
|
||||
global $activeFunctions;
|
||||
global $runtimes;
|
||||
global $register;
|
||||
$container = 'appwrite-function-' . $deploymentId;
|
||||
|
||||
$function = $database->getDocument('functions', $functionId);
|
||||
$deployment = $database->getDocument('deployments', $function->getAttribute('deployment', ''));
|
||||
$build = $database->getDocument('builds', $deployment->getAttribute('buildId', ''));
|
||||
|
||||
if ($deployment->getAttribute('resourceId') !== $function->getId()) {
|
||||
throw new Exception('Deployment not found', 404);
|
||||
/** Create a new runtime server if there's none running */
|
||||
if (!$activeFunctions->exists($container)) {
|
||||
createRuntimeServer($projectId, $deploymentId, $build, $vars, $baseImage, $runtime);
|
||||
}
|
||||
|
||||
// Grab execution document if exists
|
||||
// It it doesn't exist, create a new one.
|
||||
$execution = !empty($executionId)
|
||||
? $database->getDocument('executions', $executionId)
|
||||
: $database->createDocument('executions', new Document([
|
||||
'$id' => $executionId,
|
||||
'$read' => ($userId !== '') ? ['user:' . $userId] : [],
|
||||
'$write' => ['role:all'],
|
||||
'dateCreated' => time(),
|
||||
'functionId' => $function->getId(),
|
||||
'deploymentId' => $deployment->getId(),
|
||||
'trigger' => $trigger, // http / schedule / event
|
||||
'status' => 'processing', // waiting / processing / completed / failed
|
||||
'statusCode' => 0,
|
||||
'stdout' => '',
|
||||
'stderr' => '',
|
||||
'time' => 0.0,
|
||||
'search' => implode(' ', [$functionId, $executionId]),
|
||||
]));
|
||||
|
||||
if (false === $execution || ($execution instanceof Document && $execution->isEmpty())) {
|
||||
throw new Exception('Failed to create or read execution');
|
||||
}
|
||||
|
||||
|
||||
if ($build->getAttribute('status') === 'building') {
|
||||
|
||||
$execution
|
||||
->setAttribute('status', 'failed')
|
||||
->setAttribute('statusCode', 500)
|
||||
->setAttribute('stderr', 'Deployment is still being built.')
|
||||
->setAttribute('time', 0);
|
||||
|
||||
$database->updateDocument('executions', $execution->getId(), $execution);
|
||||
|
||||
throw new Exception('Execution Failed. Reason: Deployment is still being built.');
|
||||
}
|
||||
|
||||
// Check if runtime is active
|
||||
$runtime = $runtimes[$function->getAttribute('runtime', '')] ?? null;
|
||||
|
||||
if (\is_null($runtime)) {
|
||||
throw new Exception('Runtime "' . $function->getAttribute('runtime', '') . '" is not supported');
|
||||
}
|
||||
$key = $activeFunctions->get('appwrite-function-' . $deploymentId, 'key');
|
||||
|
||||
// Process environment variables
|
||||
$vars = \array_merge($function->getAttribute('vars', []), [
|
||||
'ENTRYPOINT_NAME' => $deployment->getAttribute('entrypoint', ''),
|
||||
'APPWRITE_FUNCTION_ID' => $function->getId(),
|
||||
'APPWRITE_FUNCTION_NAME' => $function->getAttribute('name', ''),
|
||||
'APPWRITE_FUNCTION_DEPLOYMENT' => $deployment->getId(),
|
||||
'APPWRITE_FUNCTION_TRIGGER' => $trigger,
|
||||
'APPWRITE_FUNCTION_RUNTIME_NAME' => $runtime['name'],
|
||||
'APPWRITE_FUNCTION_RUNTIME_VERSION' => $runtime['version'],
|
||||
'APPWRITE_FUNCTION_EVENT' => $event,
|
||||
'APPWRITE_FUNCTION_EVENT_DATA' => $eventData,
|
||||
'APPWRITE_FUNCTION_DATA' => $data,
|
||||
'APPWRITE_FUNCTION_USER_ID' => $userId,
|
||||
'APPWRITE_FUNCTION_JWT' => $jwt,
|
||||
'APPWRITE_FUNCTION_PROJECT_ID' => $projectId,
|
||||
]);
|
||||
|
||||
$container = 'appwrite-function-' . $deployment->getId();
|
||||
|
||||
try {
|
||||
if ($build->getAttribute('status') !== 'ready') {
|
||||
// Create a new build entry
|
||||
$buildId = $database->getId();
|
||||
$database->createDocument('builds', new Document([
|
||||
'$id' => $buildId,
|
||||
'$read' => [],
|
||||
'$write' => [],
|
||||
'startTime' => time(),
|
||||
'deploymentId' => $deployment->getId(),
|
||||
'status' => 'processing',
|
||||
'outputPath' => '',
|
||||
'runtime' => $function->getAttribute('runtime', ''),
|
||||
'source' => $deployment->getAttribute('path'),
|
||||
'sourceType' => Storage::DEVICE_LOCAL,
|
||||
'stdout' => '',
|
||||
'stderr' => '',
|
||||
'endTime' => 0,
|
||||
'duration' => 0
|
||||
]));
|
||||
|
||||
$deployment->setAttribute('buildId', $buildId);
|
||||
|
||||
$database->updateDocument('deployments', $deployment->getId(), $deployment);
|
||||
|
||||
runBuildStage($buildId, $deployment->getId(), $projectId);
|
||||
}
|
||||
} catch (Exception $e) {
|
||||
$execution
|
||||
->setAttribute('status', 'failed')
|
||||
->setAttribute('statusCode', 500)
|
||||
->setAttribute('stderr', \utf8_encode(\mb_substr($e->getMessage(), -4000))) // log last 4000 chars output
|
||||
->setAttribute('time', 0);
|
||||
|
||||
$database->updateDocument('executions', $execution->getId(), $execution);
|
||||
|
||||
throw new Error('Something went wrong building the code. ' . $e->getMessage());
|
||||
}
|
||||
|
||||
try {
|
||||
if (!$activeFunctions->exists($container)) { // Create container if not ready
|
||||
createRuntimeServer($functionId, $projectId, $deployment->getId(), $database);
|
||||
} else if ($activeFunctions->get($container)['status'] === 'Down') {
|
||||
sleep(1);
|
||||
} else {
|
||||
Console::info('Container is ready to run');
|
||||
}
|
||||
} catch (Exception $e) {
|
||||
$execution->setAttribute('status', 'failed')
|
||||
->setAttribute('statusCode', 500)
|
||||
->setAttribute('stderr', \utf8_encode(\mb_substr($e->getMessage(), -4000))) // log last 4000 chars output
|
||||
->setAttribute('time', 0);
|
||||
|
||||
$execution = $database->updateDocument('executions', $execution->getId(), $execution);
|
||||
|
||||
try {
|
||||
throw new Exception('Something went wrong building the runtime server. ' . $e->getMessage());
|
||||
} catch (\Exception $error) {
|
||||
logError($error, 'execution');
|
||||
}
|
||||
|
||||
return [
|
||||
'status' => 'failed',
|
||||
'response' => \utf8_encode(\mb_substr($e->getMessage(), -4000)), // log last 4000 chars output
|
||||
'time' => 0
|
||||
];
|
||||
}
|
||||
|
||||
$key = $activeFunctions->get('appwrite-function-' . $deployment->getId(), 'key');
|
||||
|
||||
// Process environment variables
|
||||
$vars = \array_merge($function->getAttribute('vars', []), [
|
||||
'ENTRYPOINT_NAME' => $deployment->getAttribute('entrypoint', ''),
|
||||
'APPWRITE_FUNCTION_ID' => $function->getId(),
|
||||
'APPWRITE_FUNCTION_NAME' => $function->getAttribute('name', ''),
|
||||
'APPWRITE_FUNCTION_DEPLOYMENT' => $deployment->getId(),
|
||||
'APPWRITE_FUNCTION_TRIGGER' => $trigger,
|
||||
'APPWRITE_FUNCTION_RUNTIME_NAME' => $runtime['name'],
|
||||
'APPWRITE_FUNCTION_RUNTIME_VERSION' => $runtime['version'],
|
||||
'APPWRITE_FUNCTION_EVENT' => $event,
|
||||
'APPWRITE_FUNCTION_EVENT_DATA' => $eventData,
|
||||
'APPWRITE_FUNCTION_DATA' => $data,
|
||||
'APPWRITE_FUNCTION_USER_ID' => $userId,
|
||||
'APPWRITE_FUNCTION_JWT' => $jwt,
|
||||
'APPWRITE_FUNCTION_PROJECT_ID' => $projectId
|
||||
]);
|
||||
// $vars = \array_merge($function->getAttribute('vars', []), [
|
||||
// 'ENTRYPOINT_NAME' => $deployment->getAttribute('entrypoint', ''),
|
||||
// 'APPWRITE_FUNCTION_ID' => $function->getId(),
|
||||
// 'APPWRITE_FUNCTION_NAME' => $function->getAttribute('name', ''),
|
||||
// 'APPWRITE_FUNCTION_DEPLOYMENT' => $deployment->getId(),
|
||||
// 'APPWRITE_FUNCTION_TRIGGER' => $trigger,
|
||||
// 'APPWRITE_FUNCTION_RUNTIME_NAME' => $runtime['name'],
|
||||
// 'APPWRITE_FUNCTION_RUNTIME_VERSION' => $runtime['version'],
|
||||
// 'APPWRITE_FUNCTION_EVENT' => $event,
|
||||
// 'APPWRITE_FUNCTION_EVENT_DATA' => $eventData,
|
||||
// 'APPWRITE_FUNCTION_DATA' => $data,
|
||||
// 'APPWRITE_FUNCTION_USER_ID' => $userId,
|
||||
// 'APPWRITE_FUNCTION_JWT' => $jwt,
|
||||
// 'APPWRITE_FUNCTION_PROJECT_ID' => $projectId
|
||||
// ]);
|
||||
|
||||
$stdout = '';
|
||||
$stderr = '';
|
||||
|
@ -458,7 +324,7 @@ function execute(string $trigger, string $projectId, string $executionId, string
|
|||
'file' => $vars['ENTRYPOINT_NAME'],
|
||||
'env' => $vars,
|
||||
'payload' => $data,
|
||||
'timeout' => $function->getAttribute('timeout', (int) App::getEnv('_APP_FUNCTIONS_TIMEOUT', 900))
|
||||
'timeout' => $timeout ?? (int) App::getEnv('_APP_FUNCTIONS_TIMEOUT', 900)
|
||||
]);
|
||||
|
||||
\curl_setopt($ch, CURLOPT_URL, "http://" . $container . ":3000/");
|
||||
|
@ -466,7 +332,7 @@ function execute(string $trigger, string $projectId, string $executionId, string
|
|||
\curl_setopt($ch, CURLOPT_POSTFIELDS, $body);
|
||||
|
||||
\curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
|
||||
\curl_setopt($ch, CURLOPT_TIMEOUT, $function->getAttribute('timeout', (int) App::getEnv('_APP_FUNCTIONS_TIMEOUT', 900)));
|
||||
\curl_setopt($ch, CURLOPT_TIMEOUT, $timeout ?? (int) App::getEnv('_APP_FUNCTIONS_TIMEOUT', 900));
|
||||
\curl_setopt($ch, CURLOPT_CONNECTTIMEOUT, 10);
|
||||
|
||||
\curl_setopt($ch, CURLOPT_HTTPHEADER, [
|
||||
|
@ -537,34 +403,32 @@ function execute(string $trigger, string $projectId, string $executionId, string
|
|||
$executionTime = ($executionEnd - $executionStart);
|
||||
$functionStatus = ($statusCode >= 200 && $statusCode < 300) ? 'completed' : 'failed';
|
||||
|
||||
Console::success('Function executed in ' . ($executionEnd - $executionStart) . ' seconds, status: ' . $functionStatus);
|
||||
Console::success('Function executed in ' . $executionTime . ' seconds, status: ' . $functionStatus);
|
||||
|
||||
$execution->setAttribute('deploymentId', $deployment->getId())
|
||||
->setAttribute('status', $functionStatus)
|
||||
->setAttribute('statusCode', $statusCode)
|
||||
->setAttribute('stdout', \utf8_encode(\mb_substr($stdout, -8000)))
|
||||
->setAttribute('stderr', \utf8_encode(\mb_substr($stderr, -8000)))
|
||||
->setAttribute('time', $executionTime);
|
||||
|
||||
$execution = $database->updateDocument('executions', $execution->getId(), $execution);
|
||||
$execution = [
|
||||
'status' => $functionStatus,
|
||||
'statusCode' => $statusCode,
|
||||
'stdout' => \utf8_encode(\mb_substr($stdout, -8000)),
|
||||
'stderr' => \utf8_encode(\mb_substr($stderr, -8000)),
|
||||
'time' => $executionTime,
|
||||
];
|
||||
|
||||
/** Trigger event */
|
||||
$executionModel = new Execution();
|
||||
$executionUpdate = new Event('v1-webhooks', 'WebhooksV1');
|
||||
|
||||
$executionUpdate
|
||||
->setParam('projectId', $projectId)
|
||||
->setParam('userId', $userId)
|
||||
->setParam('webhooks', $webhooks)
|
||||
->setParam('event', 'functions.executions.update')
|
||||
->setParam('eventData', $execution->getArrayCopy(array_keys($executionModel->getRules())));
|
||||
|
||||
->setParam('eventData', (new Document($execution))->getArrayCopy(array_keys($executionModel->getRules())));
|
||||
$executionUpdate->trigger();
|
||||
|
||||
$target = Realtime::fromPayload('functions.executions.update', $execution);
|
||||
|
||||
/** Trigger realtime event */
|
||||
$target = Realtime::fromPayload('functions.executions.update', new Document($execution));
|
||||
Realtime::send(
|
||||
projectId: $projectId,
|
||||
payload: $execution->getArrayCopy(),
|
||||
payload: $execution,
|
||||
event: 'functions.executions.update',
|
||||
channels: $target['channels'],
|
||||
roles: $target['roles']
|
||||
|
@ -572,27 +436,21 @@ function execute(string $trigger, string $projectId, string $executionId, string
|
|||
|
||||
if (App::getEnv('_APP_USAGE_STATS', 'enabled') === 'enabled') {
|
||||
$statsd = $register->get('statsd');
|
||||
|
||||
$usage = new Stats($statsd);
|
||||
|
||||
$usage
|
||||
->setParam('projectId', $projectId)
|
||||
->setParam('functionId', $function->getId())
|
||||
->setParam('functionId', $functionId)
|
||||
->setParam('functionExecution', 1)
|
||||
->setParam('functionStatus', $functionStatus)
|
||||
->setParam('functionExecutionTime', $executionTime * 1000) // ms
|
||||
->setParam('networkRequestSize', 0)
|
||||
->setParam('networkResponseSize', 0)
|
||||
->submit();
|
||||
|
||||
$usage->submit();
|
||||
}
|
||||
|
||||
return [
|
||||
'status' => $functionStatus,
|
||||
'response' => ($functionStatus !== 'completed') ? $stderr : $stdout,
|
||||
'time' => $executionTime
|
||||
];
|
||||
return $execution;
|
||||
|
||||
};
|
||||
|
||||
function runBuildStage(string $buildId, string $projectID, string $path, array $vars, string $baseImage, string $runtime): array
|
||||
|
@ -809,59 +667,36 @@ function runBuildStage(string $buildId, string $projectID, string $path, array $
|
|||
|
||||
App::post('/v1/functions/:functionId/executions')
|
||||
->desc('Execute a function')
|
||||
->param('trigger', '', new Text(1024), 'What triggered this execution, can be http / schedule / event')
|
||||
->param('projectId', '', new Text(1024), 'The ProjectID this execution belongs to')
|
||||
->param('executionId', '', new Text(1024), 'An optional execution ID, If not specified a new execution document is created.', true)
|
||||
->param('functionId', '', new Text(1024), 'The FunctionID to execute')
|
||||
->param('event', '', new Text(1024), 'The event that triggered this execution', true)
|
||||
->param('eventData', '', new Text(0), 'Extra Data for the event', true)
|
||||
->param('data', '', new Text(1024), 'Data to be forwarded to the function, this is user specified.', true)
|
||||
->param('deploymentId', '', new Text(1024), 'The deployment ID to execute')
|
||||
->param('buildId', '', new Text(1024), 'The build ID of the function')
|
||||
->param('path', '', new Text(0), 'Path to built files.', false)
|
||||
->param('vars', '', new Assoc(), 'Environment Variables required for the build', false)
|
||||
->param('data', '', new Text(8192), 'Data to be forwarded to the function, this is user specified.', true)
|
||||
->param('runtime', '', new Text(128), 'Runtime for the cloud function', false)
|
||||
->param('timeout', 15, new ValidatorRange(1, 900), 'Function maximum execution time in seconds.', true)
|
||||
->param('baseImage', '', new Text(128), 'Base image name of the runtime', false)
|
||||
->param('webhooks', [], new ArrayList(new JSON()), 'Any webhooks that need to be triggered after this execution', true)
|
||||
->param('userId', '', new Text(1024), 'The UserID of the user who triggered the execution if it was called from a client SDK', true)
|
||||
->param('jwt', '', new Text(1024), 'A JWT of the user who triggered the execution if it was called from a client SDK', true)
|
||||
->inject('projectId')
|
||||
->inject('response')
|
||||
->inject('dbForProject')
|
||||
->action(
|
||||
function (string $trigger, string $projectId, string $executionId, string $functionId, string $event, string $eventData, string $data, array $webhooks, string $userId, string $jwt, Response $response, Database $dbForProject) {
|
||||
$data = execute($trigger, $projectId, $executionId, $functionId, $dbForProject, $event, $eventData, $data, $webhooks, $userId, $jwt);
|
||||
function (string $functionId, string $deploymentId, string $buildId, string $path, array $vars, string $data, string $runtime, $timeout, string $baseImage, array $webhooks, string $userId, string $projectId, Response $response) {
|
||||
|
||||
$build = [
|
||||
'$id' => $buildId,
|
||||
'outputPath' => $path,
|
||||
];
|
||||
|
||||
// Send both data and vars from the caller
|
||||
$execution = execute($projectId, $functionId, $deploymentId, $build, $vars, $data, $userId, $baseImage, $runtime, $timeout, $webhooks);
|
||||
|
||||
$response
|
||||
->setStatusCode(Response::STATUS_CODE_OK)
|
||||
->json($data);
|
||||
->json($execution);
|
||||
}
|
||||
);
|
||||
|
||||
App::post('/v1/functions/:functionId/deployments/:deploymentId/runtime')
|
||||
->desc('Create a new runtime server for a deployment')
|
||||
->param('functionId', '', new UID(), 'Function unique ID.')
|
||||
->param('deploymentId', '', new UID(), 'Deployment unique ID.')
|
||||
->inject('response')
|
||||
->inject('dbForProject')
|
||||
->inject('projectId')
|
||||
->action(function (string $functionId, string $deploymentId, Response $response, Database $dbForProject, string $projectID) use ($runtimes) {
|
||||
// Get function document
|
||||
$function = $dbForProject->getDocument('functions', $functionId);
|
||||
if ($function->isEmpty()) {
|
||||
throw new Exception('Function not found', 404);
|
||||
}
|
||||
|
||||
// Get deployment document
|
||||
$deployment = $dbForProject->getDocument('deployments', $deploymentId);
|
||||
if ($deployment->isEmpty()) {
|
||||
throw new Exception('Deployment not found', 404);
|
||||
}
|
||||
|
||||
$runtime = $runtimes[$function->getAttribute('runtime')] ?? null;
|
||||
if (\is_null($runtime)) {
|
||||
throw new Exception('Runtime "' . $function->getAttribute('runtime', '') . '" not found.', 404);
|
||||
}
|
||||
|
||||
createRuntimeServer($functionId, $projectID, $deploymentId, $dbForProject);
|
||||
|
||||
$response
|
||||
->setStatusCode(201)
|
||||
->send();
|
||||
});
|
||||
|
||||
App::delete('/v1/deployments/:deploymentId')
|
||||
->desc('Delete a deployment')
|
||||
->param('deploymentId', '', new UID(), 'Deployment unique ID.', false)
|
||||
|
@ -906,10 +741,9 @@ App::post('/v1/functions/:functionId/deployments/:deploymentId/builds/:buildId')
|
|||
->param('vars', '', new Assoc(), 'Environment Variables required for the build', false)
|
||||
->param('runtime', '', new Text(128), 'Runtime for the cloud function', false)
|
||||
->param('baseImage', '', new Text(128), 'Base image name of the runtime', false)
|
||||
->inject('response')
|
||||
->inject('dbForProject')
|
||||
->inject('projectId')
|
||||
->action(function (string $functionId, string $deploymentId, string $buildId, string $path, array $vars, string $runtime, string $baseImage, Response $response, Database $dbForProject, string $projectId) {
|
||||
->inject('response')
|
||||
->action(function (string $functionId, string $deploymentId, string $buildId, string $path, array $vars, string $runtime, string $baseImage, string $projectId, Response $response) {
|
||||
|
||||
$build = runBuildStage($buildId, $projectId, $path, $vars, $baseImage, $runtime);
|
||||
|
||||
|
@ -1007,12 +841,6 @@ $http->on('request', function (SwooleRequest $swooleRequest, SwooleResponse $swo
|
|||
$response = new Response($swooleResponse);
|
||||
$app = new App('UTC');
|
||||
|
||||
$db = $register->get('dbPool')->get();
|
||||
$redis = $register->get('redisPool')->get();
|
||||
|
||||
App::setResource('db', fn () => $db);
|
||||
App::setResource('cache', fn () => $redis);
|
||||
|
||||
$projectId = $request->getHeader('x-appwrite-project', '');
|
||||
|
||||
Storage::setDevice('functions', new Local(APP_STORAGE_FUNCTIONS . '/app-' . $projectId));
|
||||
|
@ -1031,16 +859,6 @@ $http->on('request', function (SwooleRequest $swooleRequest, SwooleResponse $swo
|
|||
return $swooleResponse->end('401: Authentication Error');
|
||||
}
|
||||
|
||||
App::setResource('dbForProject', function ($db, $cache) use ($projectId) {
|
||||
$cache = new Cache(new RedisCache($cache));
|
||||
|
||||
$database = new Database(new MariaDB($db), $cache);
|
||||
$database->setDefaultDatabase(App::getEnv('_APP_DB_SCHEMA', 'appwrite'));
|
||||
$database->setNamespace('_project_' . $projectId);
|
||||
|
||||
return $database;
|
||||
}, ['db', 'cache']);
|
||||
|
||||
App::error(function ($error, $utopia, $request, $response) {
|
||||
/** @var Exception $error */
|
||||
/** @var Utopia\App $utopia */
|
||||
|
@ -1094,13 +912,6 @@ $http->on('request', function (SwooleRequest $swooleRequest, SwooleResponse $swo
|
|||
logError($e, "serverError");
|
||||
$swooleResponse->end('500: Server Error');
|
||||
} finally {
|
||||
/** @var PDOPool $dbPool */
|
||||
$dbPool = $register->get('dbPool');
|
||||
$dbPool->put($db);
|
||||
|
||||
/** @var RedisPool $redisPool */
|
||||
$redisPool = $register->get('redisPool');
|
||||
$redisPool->put($redis);
|
||||
}
|
||||
});
|
||||
|
||||
|
|
|
@ -189,10 +189,18 @@ class FunctionsV1 extends Worker
|
|||
throw new Exception('Function not found ('.$functionId.')');
|
||||
}
|
||||
|
||||
$deployment = Authorization::skip(fn() => $database->getDocument('deployments', $function->getAttribute('deployment')));
|
||||
|
||||
$build = Authorization::skip(fn() => $database->getDocument('builds', $deployment->getAttribute('build')));
|
||||
$path = $build->getAttribute('path', '');
|
||||
|
||||
$this->execute(
|
||||
trigger: $trigger,
|
||||
projectId: $projectId,
|
||||
executionId: $executionId,
|
||||
path: $path,
|
||||
buildId: $deployment->getAttribute('buildId', ''),
|
||||
deploymentId: $deployment->getId(),
|
||||
database: $database,
|
||||
function: $function,
|
||||
data: $data,
|
||||
|
@ -221,21 +229,22 @@ class FunctionsV1 extends Worker
|
|||
*
|
||||
* @return void
|
||||
*/
|
||||
public function execute(string $trigger, string $projectId, string $executionId, Database $database, Document $function, string $event = '', string $eventData = '', string $data = '', array $webhooks = [], string $userId = '', string $jwt = ''): void
|
||||
public function execute(string $trigger, string $path, string $projectId, string $deploymentId, string $buildId, string $executionId, Database $database, Document $function, string $event = '', string $eventData = '', string $data = '', array $webhooks = [], string $userId = '', string $jwt = ''): void
|
||||
{
|
||||
$ch = \curl_init();
|
||||
\curl_setopt($ch, CURLOPT_URL, "http://appwrite-executor/v1/functions/{$function->getId()}/executions");
|
||||
\curl_setopt($ch, CURLOPT_POST, true);
|
||||
\curl_setopt($ch, CURLOPT_POSTFIELDS, json_encode([
|
||||
'trigger' => $trigger,
|
||||
'projectId' => $projectId,
|
||||
'executionId' => $executionId,
|
||||
'event' => $event,
|
||||
'eventData' => $eventData,
|
||||
'deploymentId' => $deploymentId,
|
||||
'buildId' => $buildId,
|
||||
'path' => $path,
|
||||
'vars' => $function->getAttribute('vars', []),
|
||||
'data' => $data,
|
||||
'runtime' => $function->getAttribute('runtime', ''),
|
||||
'timeout' => $function->getAttribute('timeout', 0),
|
||||
'baseImage' => '',
|
||||
'webhooks' => $webhooks,
|
||||
'userId' => $userId,
|
||||
'jwt' => $jwt,
|
||||
]));
|
||||
\curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
|
||||
\curl_setopt($ch, CURLOPT_TIMEOUT, App::getEnv('_APP_FUNCTIONS_TIMEOUT', 900) + 200); // + 200 for safety margin
|
||||
|
|
Loading…
Reference in a new issue