1
0
Fork 0
mirror of synced 2024-06-14 00:34:51 +12:00

feat: refactor

This commit is contained in:
Christy Jacob 2022-01-26 03:45:41 +04:00
parent 92706045ad
commit ebc55e7e8e
5 changed files with 63 additions and 178 deletions

View file

@ -367,7 +367,7 @@ App::patch('/v1/functions/:functionId/tag')
$function = $dbForProject->getDocument('functions', $functionId);
$tag = $dbForProject->getDocument('tags', $tag);
$build = $dbForProject->getDocument('builds', $tag->getAttribute('buildId'));
$build = $dbForProject->getDocument('builds', $tag->getAttribute('buildId', ''));
if ($function->isEmpty()) {
throw new Exception('Function not found', 404);
@ -433,11 +433,8 @@ App::delete('/v1/functions/:functionId')
// Request executor to delete tag containers
$ch = \curl_init();
\curl_setopt($ch, CURLOPT_URL, "http://appwrite-executor/v1/cleanup/function");
\curl_setopt($ch, CURLOPT_POST, true);
\curl_setopt($ch, CURLOPT_POSTFIELDS, json_encode([
'functionId' => $functionId
]));
\curl_setopt($ch, CURLOPT_CUSTOMREQUEST, 'DELETE');
\curl_setopt($ch, CURLOPT_URL, "http://appwrite-executor/v1/functions/$functionId");
\curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
\curl_setopt($ch, CURLOPT_TIMEOUT, 900);
\curl_setopt($ch, CURLOPT_CONNECTTIMEOUT, 10);
@ -743,11 +740,8 @@ App::delete('/v1/functions/:functionId/tags/:tagId')
// Request executor to delete tag containers
$ch = \curl_init();
\curl_setopt($ch, CURLOPT_URL, "http://appwrite-executor/v1/cleanup/tag");
\curl_setopt($ch, CURLOPT_POST, true);
\curl_setopt($ch, CURLOPT_POSTFIELDS, json_encode([
'tagId' => $tagId
]));
\curl_setopt($ch, CURLOPT_CUSTOMREQUEST, 'DELETE');
\curl_setopt($ch, CURLOPT_URL, "http://appwrite-executor/v1/tags/$tagId");
\curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
\curl_setopt($ch, CURLOPT_TIMEOUT, 900);
\curl_setopt($ch, CURLOPT_CONNECTTIMEOUT, 10);
@ -901,13 +895,12 @@ App::post('/v1/functions/:functionId/executions')
// Directly execute function.
$ch = \curl_init();
\curl_setopt($ch, CURLOPT_URL, "http://appwrite-executor/v1/execute");
\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(),
'functionId' => $function->getId(),
'data' => $data,
'webhooks' => $project->getAttribute('webhooks', []),
'userId' => $user->getId(),

View file

@ -312,7 +312,7 @@ function createRuntimeServer(string $functionId, string $projectId, string $tagI
'key' => $secret,
]);
Console::info('Runtime Server created in ' . ($executionEnd - $executionStart) . ' seconds');
Console::success('Runtime Server created in ' . ($executionEnd - $executionStart) . ' seconds');
} else {
Console::info('Runtime server is ready to run');
}
@ -601,7 +601,7 @@ function execute(string $trigger, string $projectId, string $executionId, string
$executionTime = ($executionEnd - $executionStart);
$functionStatus = ($statusCode >= 200 && $statusCode < 300) ? 'completed' : 'failed';
Console::info('Function executed in ' . ($executionEnd - $executionStart) . ' seconds, status: ' . $functionStatus);
Console::success('Function executed in ' . ($executionEnd - $executionStart) . ' seconds, status: ' . $functionStatus);
$execution->setAttribute('tagId', $tag->getId())
->setAttribute('status', $functionStatus)
@ -914,7 +914,7 @@ function runBuildStage(string $buildId, string $projectID): Document
return $build;
}
App::post('/v1/execute') // Define Route
App::post('/v1/functions/:functionId/executions')
->desc('Execute a function')
->param('trigger', '', new Text(1024))
->param('projectId', '', new Text(1024))
@ -932,21 +932,17 @@ App::post('/v1/execute') // Define Route
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) {
try {
$data = execute($trigger, $projectId, $executionId, $functionId, $dbForProject, $event, $eventData, $data, $webhooks, $userId, $jwt);
$response->json($data);
$response
->setStatusCode(Response::STATUS_CODE_OK)
->send();
} catch (Exception $e) {
logError($e, 'executeEndpoint');
$response
->addHeader('Cache-Control', 'no-cache, no-store, must-revalidate')
->addHeader('Expires', '0')
->addHeader('Pragma', 'no-cache')
->json(['error' => $e->getMessage()]);
throw $e;
}
}
);
// Cleanup Endpoints used internally by appwrite when a function or tag gets deleted to also clean up their containers
App::post('/v1/cleanup/function')
App::delete('/v1/functions/:functionId')
->param('functionId', '', new UID())
->inject('response')
->inject('dbForProject')
@ -1003,7 +999,39 @@ App::post('/v1/cleanup/function')
}
);
App::post('/v1/cleanup/tag')
App::post('/v1/functions/:functionId/tags/:tagId/runtime')
->desc('Create a new runtime server for a tag')
->param('functionId', '', new UID(), 'Function unique ID.')
->param('tagId', '', new UID(), 'Tag unique ID.')
->inject('response')
->inject('dbForProject')
->inject('projectID')
->action(function (string $functionId, string $tagId, 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 tag document
$tag = $dbForProject->getDocument('tags', $tagId);
if ($tag->isEmpty()) {
throw new Exception('Tag 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, $tagId, $dbForProject);
$response
->setStatusCode(201)
->send();
});
App::delete('/v1/tags/:tagId')
->param('tagId', '', new UID(), 'Tag unique ID.')
->inject('response')
->inject('dbForProject')
@ -1049,130 +1077,7 @@ App::post('/v1/cleanup/tag')
return $response->json(['success' => true]);
});
App::post('/v1/tag')
->desc('Create a new build')
->param('functionId', '', new UID(), 'Function unique ID.')
->param('tagId', '', new UID(), 'Tag unique ID.')
->param('userId', '', new UID(), 'User unique ID.', true)
->inject('response')
->inject('dbForProject')
->inject('projectID')
->inject('register')
->action(function (string $functionId, string $tagId, string $userId, Response $response, Database $dbForProject, string $projectID, Registry $register) use ($runtimes) {
// Get function document
$function = $dbForProject->getDocument('functions', $functionId);
// Get tag document
$tag = $dbForProject->getDocument('tags', $tagId);
// Check if both documents exist
if ($function->isEmpty()) {
throw new Exception('Function not found', 404);
}
if ($tag->isEmpty()) {
throw new Exception('Tag not found', 404);
}
$runtime = $runtimes[$function->getAttribute('runtime')] ?? null;
if (\is_null($runtime)) {
throw new Exception('Runtime "' . $function->getAttribute('runtime', '') . '" is not supported');
}
// Create a new build entry
$buildId = $dbForProject->getId();
if ($tag->getAttribute('buildId')) {
$buildId = $tag->getAttribute('buildId');
} else {
try {
$dbForProject->createDocument('builds', new Document([
'$id' => $buildId,
'$read' => (!empty($userId)) ? ['user:' . $userId] : [],
'$write' => ['role:all'],
'dateCreated' => time(),
'status' => 'processing',
'runtime' => $function->getAttribute('runtime'),
'outputPath' => '',
'source' => $tag->getAttribute('path'),
'sourceType' => Storage::DEVICE_LOCAL,
'stdout' => '',
'stderr' => '',
'time' => 0,
'vars' => [
'ENTRYPOINT_NAME' => $tag->getAttribute('entrypoint'),
'APPWRITE_FUNCTION_ID' => $function->getId(),
'APPWRITE_FUNCTION_NAME' => $function->getAttribute('name', ''),
'APPWRITE_FUNCTION_RUNTIME_NAME' => $runtime['name'],
'APPWRITE_FUNCTION_RUNTIME_VERSION' => $runtime['version'],
'APPWRITE_FUNCTION_PROJECT_ID' => $projectID,
]
]));
$tag->setAttribute('buildId', $buildId);
$dbForProject->updateDocument('tags', $tag->getId(), $tag);
} catch (\Throwable $th) {
var_dump($tag->getArrayCopy());
throw $th;
}
}
// Build Code
go(function () use ($projectID, $tagId, $buildId, $functionId, $function, $register) {
try {
$db = $register->get('dbPool')->get();
$redis = $register->get('redisPool')->get();
$cache = new Cache(new RedisCache($redis));
$dbForProject = new Database(new MariaDB($db), $cache);
$dbForProject->setDefaultDatabase(App::getEnv('_APP_DB_SCHEMA', 'appwrite'));
$dbForProject->setNamespace('_project_' . $projectID);
// Build Code
runBuildStage($buildId, $projectID);
// Update the schedule
$schedule = $function->getAttribute('schedule', '');
$cron = (empty($function->getAttribute('tag')) && !empty($schedule)) ? new CronExpression($schedule) : null;
$next = (empty($function->getAttribute('tag')) && !empty($schedule)) ? $cron->getNextRunDate()->format('U') : 0;
// Grab tag
$tag = $dbForProject->getDocument('tags', $tagId);
// Grab build
$build = $dbForProject->getDocument('builds', $buildId);
// If the build failed, it won't be possible to deploy
if ($build->getAttribute('status') !== 'ready') {
return;
}
if ($tag->getAttribute('automaticDeploy') === true) {
// Update the function document setting the tag as the active one
$function
->setAttribute('tag', $tag->getId())
->setAttribute('scheduleNext', (int)$next);
$function = $dbForProject->updateDocument('functions', $function->getId(), $function);
}
// Deploy Runtime Server
createRuntimeServer($functionId, $projectID, $tagId, $dbForProject);
} catch (\Throwable $th) {
} finally {
$register->get('dbPool')->put($db);
$register->get('redisPool')->put($redis);
}
});
if (false === $function) {
throw new Exception('Failed saving function to DB', 500);
}
$response->dynamic($function, Response::MODEL_FUNCTION);
});
// Build Endpoints
App::post('/v1/build/:buildId') // Start a Build
App::post('/v1/builds/:buildId')
->desc('Start a build')
->param('buildId', '', new UID(), 'Build unique ID.', false)
->inject('response')
@ -1197,11 +1102,8 @@ App::post('/v1/build/:buildId') // Start a Build
if ($build->getAttribute('status') === 'finished') {
throw new Exception('Build is already finished', 409);
}
go(function () use ($buildId, $dbForProject, $projectID) {
// Build Code
runBuildStage($buildId, $projectID, $dbForProject);
});
runBuildStage($buildId, $projectID, $dbForProject);
$response
->setStatusCode(Response::STATUS_CODE_CREATED)

View file

@ -21,14 +21,12 @@ Console::success(APP_NAME.' build worker v1 has started');
class BuildsV1 extends Worker
{
public function getName(): string {
public function getName(): string
{
return "builds";
}
public function init(): void
{
Console::success("Initializing...");
}
public function init(): void {}
public function run(): void
{
@ -59,7 +57,7 @@ class BuildsV1 extends Worker
{
// TODO: What is a reasonable time to wait for a build to complete?
$ch = \curl_init();
\curl_setopt($ch, CURLOPT_URL, "http://appwrite-executor/v1/build/$buildId");
\curl_setopt($ch, CURLOPT_URL, "http://appwrite-executor/v1/builds/$buildId");
\curl_setopt($ch, CURLOPT_POST, true);
\curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
\curl_setopt($ch, CURLOPT_TIMEOUT, 900);
@ -88,7 +86,7 @@ class BuildsV1 extends Worker
protected function triggerCreateRuntimeServer(string $projectId, string $functionId, string $tagId)
{
$ch = \curl_init();
\curl_setopt($ch, CURLOPT_URL, "http://appwrite-executor/v1/executor/runtime");
\curl_setopt($ch, CURLOPT_URL, "http://appwrite-executor/v1/functions/$functionId/tags/$tagId/runtime");
\curl_setopt($ch, CURLOPT_POST, true);
\curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
\curl_setopt($ch, CURLOPT_TIMEOUT, 900);
@ -98,10 +96,6 @@ class BuildsV1 extends Worker
'x-appwrite-project: '.$projectId,
'x-appwrite-executor-key: '. App::getEnv('_APP_EXECUTOR_SECRET', '')
]);
\curl_setopt($ch, CURLOPT_POSTFIELDS, json_encode([
'functionId' => $functionId,
'tagId' => $tagId
]));
$response = \curl_exec($ch);
$responseStatus = curl_getinfo($ch, CURLINFO_HTTP_CODE);
@ -161,8 +155,8 @@ class BuildsV1 extends Worker
'sourceType' => Storage::DEVICE_LOCAL,
'stdout' => '',
'stderr' => '',
'buildTime' => 0,
'envVars' => [
'time' => 0,
'vars' => [
'ENTRYPOINT_NAME' => $tag->getAttribute('entrypoint'),
'APPWRITE_FUNCTION_ID' => $function->getId(),
'APPWRITE_FUNCTION_NAME' => $function->getAttribute('name', ''),
@ -232,11 +226,8 @@ class BuildsV1 extends Worker
return;
}
Console::success("Runtime Server created");
Console::success("[ SUCCESS ] Runtime Server created");
}
public function shutdown(): void
{
Console::success("Shutting Down...");
}
public function shutdown(): void {}
}

View file

@ -224,13 +224,12 @@ class FunctionsV1 extends Worker
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
{
$ch = \curl_init();
\curl_setopt($ch, CURLOPT_URL, "http://appwrite-executor/v1/execute");
\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,
'functionId' => $function->getId(),
'event' => $event,
'eventData' => $eventData,
'data' => $data,

View file

@ -45,7 +45,7 @@ abstract class Worker
* @throws \Exception|\Throwable
*/
public function init() {
throw new Exception("Please implement getName method in worker");
throw new Exception("Please implement init method in worker");
}
/**
@ -56,7 +56,7 @@ abstract class Worker
* @throws \Exception|\Throwable
*/
public function run() {
throw new Exception("Please implement getName method in worker");
throw new Exception("Please implement run method in worker");
}
/**
@ -67,7 +67,7 @@ abstract class Worker
* @throws \Exception|\Throwable
*/
public function shutdown() {
throw new Exception("Please implement getName method in worker");
throw new Exception("Please implement shutdown method in worker");
}
const MAX_ATTEMPTS = 10;