Merge pull request #2706 from appwrite/feat-add-deletes-worker
Feat add deletes worker
This commit is contained in:
commit
a84f0ebbcb
10 changed files with 294 additions and 207 deletions
|
@ -2158,9 +2158,9 @@ $collections = [
|
||||||
],
|
],
|
||||||
'indexes' => [
|
'indexes' => [
|
||||||
[
|
[
|
||||||
'$id' => '_key_status',
|
'$id' => '_key_deployment',
|
||||||
'type' => Database::INDEX_KEY,
|
'type' => Database::INDEX_KEY,
|
||||||
'attributes' => ['status'],
|
'attributes' => ['deploymentId'],
|
||||||
'lengths' => [Database::LENGTH_KEY],
|
'lengths' => [Database::LENGTH_KEY],
|
||||||
'orders' => [Database::ORDER_ASC],
|
'orders' => [Database::ORDER_ASC],
|
||||||
]
|
]
|
||||||
|
|
|
@ -423,44 +423,13 @@ App::delete('/v1/functions/:functionId')
|
||||||
->inject('response')
|
->inject('response')
|
||||||
->inject('dbForProject')
|
->inject('dbForProject')
|
||||||
->inject('deletes')
|
->inject('deletes')
|
||||||
->inject('project')
|
->action(function ($functionId, $response, $dbForProject, $deletes) {
|
||||||
->action(function ($functionId, $response, $dbForProject, $deletes, $project) {
|
|
||||||
/** @var Appwrite\Utopia\Response $response */
|
/** @var Appwrite\Utopia\Response $response */
|
||||||
/** @var Utopia\Database\Database $dbForProject */
|
/** @var Utopia\Database\Database $dbForProject */
|
||||||
/** @var Appwrite\Event\Event $deletes */
|
/** @var Appwrite\Event\Event $deletes */
|
||||||
/** @var Utopia\Database\Document $project */
|
|
||||||
|
|
||||||
$function = $dbForProject->getDocument('functions', $functionId);
|
$function = $dbForProject->getDocument('functions', $functionId);
|
||||||
|
|
||||||
// Request executor to delete deployment containers
|
|
||||||
$ch = \curl_init();
|
|
||||||
\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);
|
|
||||||
\curl_setopt($ch, CURLOPT_HTTPHEADER, [
|
|
||||||
'Content-Type: application/json',
|
|
||||||
'x-appwrite-project: '.$project->getId(),
|
|
||||||
'x-appwrite-executor-key: '. App::getEnv('_APP_EXECUTOR_SECRET', '')
|
|
||||||
]);
|
|
||||||
|
|
||||||
$executorResponse = \curl_exec($ch);
|
|
||||||
|
|
||||||
$error = \curl_error($ch);
|
|
||||||
|
|
||||||
if (!empty($error)) {
|
|
||||||
throw new Exception('Executor Cleanup Error: ' . $error, 500);
|
|
||||||
}
|
|
||||||
|
|
||||||
// Check status code
|
|
||||||
$statusCode = \curl_getinfo($ch, CURLINFO_HTTP_CODE);
|
|
||||||
if (200 !== $statusCode) {
|
|
||||||
throw new Exception('Executor error: ' . $executorResponse, $statusCode);
|
|
||||||
}
|
|
||||||
|
|
||||||
\curl_close($ch);
|
|
||||||
|
|
||||||
if ($function->isEmpty()) {
|
if ($function->isEmpty()) {
|
||||||
throw new Exception('Function not found', 404);
|
throw new Exception('Function not found', 404);
|
||||||
}
|
}
|
||||||
|
@ -713,64 +682,29 @@ App::delete('/v1/functions/:functionId/deployments/:deploymentId')
|
||||||
->inject('response')
|
->inject('response')
|
||||||
->inject('dbForProject')
|
->inject('dbForProject')
|
||||||
->inject('usage')
|
->inject('usage')
|
||||||
->inject('project')
|
->inject('deletes')
|
||||||
->action(function ($functionId, $deploymentId, $response, $dbForProject, $usage, $project) {
|
->action(function ($functionId, $deploymentId, $response, $dbForProject, $usage, $deletes) {
|
||||||
/** @var Appwrite\Utopia\Response $response */
|
/** @var Appwrite\Utopia\Response $response */
|
||||||
/** @var Utopia\Database\Database $dbForProject */
|
/** @var Utopia\Database\Database $dbForProject */
|
||||||
/** @var Appwrite\Event\Event $usage */
|
/** @var Appwrite\Event\Event $usage */
|
||||||
/** @var Utopia\Database\Document $project */
|
/** @var Appwrite\Event\Event $deletes */
|
||||||
|
|
||||||
$function = $dbForProject->getDocument('functions', $functionId);
|
$function = $dbForProject->getDocument('functions', $functionId);
|
||||||
|
|
||||||
if ($function->isEmpty()) {
|
if ($function->isEmpty()) {
|
||||||
throw new Exception('Function not found', 404);
|
throw new Exception('Function not found', 404);
|
||||||
}
|
}
|
||||||
|
|
||||||
$deployment = $dbForProject->getDocument('deployments', $deploymentId);
|
$deployment = $dbForProject->getDocument('deployments', $deploymentId);
|
||||||
|
if ($deployment->isEmpty()) {
|
||||||
|
throw new Exception('Deployment not found', 404);
|
||||||
|
}
|
||||||
|
|
||||||
if ($deployment->getAttribute('resourceId') !== $function->getId()) {
|
if ($deployment->getAttribute('resourceId') !== $function->getId()) {
|
||||||
throw new Exception('Deployment not found', 404);
|
throw new Exception('Deployment not found', 404);
|
||||||
}
|
}
|
||||||
|
|
||||||
if ($deployment->isEmpty()) {
|
if (!$dbForProject->deleteDocument('deployments', $deployment->getId())) {
|
||||||
throw new Exception('deployment not found', 404);
|
throw new Exception('Failed to remove deployment from DB', 500);
|
||||||
}
|
|
||||||
|
|
||||||
// Request executor to delete deployment containers
|
|
||||||
$ch = \curl_init();
|
|
||||||
\curl_setopt($ch, CURLOPT_CUSTOMREQUEST, 'DELETE');
|
|
||||||
\curl_setopt($ch, CURLOPT_URL, "http://appwrite-executor/v1/deployments/$deploymentId");
|
|
||||||
\curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
|
|
||||||
\curl_setopt($ch, CURLOPT_TIMEOUT, 900);
|
|
||||||
\curl_setopt($ch, CURLOPT_CONNECTTIMEOUT, 10);
|
|
||||||
\curl_setopt($ch, CURLOPT_HTTPHEADER, [
|
|
||||||
'Content-Type: application/json',
|
|
||||||
'x-appwrite-project: '.$project->getId(),
|
|
||||||
'x-appwrite-executor-key: '. App::getEnv('_APP_EXECUTOR_SECRET', '')
|
|
||||||
]);
|
|
||||||
|
|
||||||
$executorResponse = \curl_exec($ch);
|
|
||||||
|
|
||||||
$error = \curl_error($ch);
|
|
||||||
|
|
||||||
if (!empty($error)) {
|
|
||||||
throw new Exception('Executor Cleanup error: ' . $error, 500);
|
|
||||||
}
|
|
||||||
|
|
||||||
// Check status code
|
|
||||||
$statusCode = \curl_getinfo($ch, CURLINFO_HTTP_CODE);
|
|
||||||
if (200 !== $statusCode) {
|
|
||||||
throw new Exception('Executor error: ' . $executorResponse, $statusCode);
|
|
||||||
}
|
|
||||||
|
|
||||||
\curl_close($ch);
|
|
||||||
|
|
||||||
$device = Storage::getDevice('functions');
|
|
||||||
|
|
||||||
if ($device->delete($deployment->getAttribute('path', ''))) {
|
|
||||||
if (!$dbForProject->deleteDocument('deployments', $deployment->getId())) {
|
|
||||||
throw new Exception('Failed to remove deployment from DB', 500);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if($function->getAttribute('deployment') === $deployment->getId()) { // Reset function deployment
|
if($function->getAttribute('deployment') === $deployment->getId()) { // Reset function deployment
|
||||||
|
@ -783,6 +717,11 @@ App::delete('/v1/functions/:functionId/deployments/:deploymentId')
|
||||||
->setParam('storage', $deployment->getAttribute('size', 0) * -1)
|
->setParam('storage', $deployment->getAttribute('size', 0) * -1)
|
||||||
;
|
;
|
||||||
|
|
||||||
|
$deletes
|
||||||
|
->setParam('type', DELETE_TYPE_DOCUMENT)
|
||||||
|
->setParam('document', $deployment)
|
||||||
|
;
|
||||||
|
|
||||||
$response->noContent();
|
$response->noContent();
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|
166
app/executor.php
166
app/executor.php
|
@ -408,7 +408,7 @@ function execute(string $trigger, string $projectId, string $executionId, string
|
||||||
$buildId = $database->getId();
|
$buildId = $database->getId();
|
||||||
$database->createDocument('builds', new Document([
|
$database->createDocument('builds', new Document([
|
||||||
'$id' => $buildId,
|
'$id' => $buildId,
|
||||||
'$read' => ($userId !== '') ? ['user:' . $userId] : [],
|
'$read' => [],
|
||||||
'$write' => [],
|
'$write' => [],
|
||||||
'startTime' => time(),
|
'startTime' => time(),
|
||||||
'deploymentId' => $deployment->getId(),
|
'deploymentId' => $deployment->getId(),
|
||||||
|
@ -685,9 +685,7 @@ function runBuildStage(string $buildId, string $deploymentId, string $projectID)
|
||||||
|
|
||||||
// Update deployment Status
|
// Update deployment Status
|
||||||
$build->setAttribute('status', 'building');
|
$build->setAttribute('status', 'building');
|
||||||
$deployment->setAttribute('status', 'building');
|
|
||||||
$database->updateDocument('builds', $buildId, $build);
|
$database->updateDocument('builds', $buildId, $build);
|
||||||
$database->updateDocument('deployments', $deploymentId, $deployment);
|
|
||||||
|
|
||||||
// Check if runtime is active
|
// Check if runtime is active
|
||||||
$runtime = $runtimes[$build->getAttribute('runtime', '')] ?? null;
|
$runtime = $runtimes[$build->getAttribute('runtime', '')] ?? null;
|
||||||
|
@ -748,6 +746,7 @@ function runBuildStage(string $buildId, string $deploymentId, string $projectID)
|
||||||
}
|
}
|
||||||
|
|
||||||
$vars = $resource->getAttribute('vars', []);
|
$vars = $resource->getAttribute('vars', []);
|
||||||
|
$vars['ENTRYPOINT_NAME'] = $resource->getAttribute('entrypoint', '');
|
||||||
|
|
||||||
$orchestration
|
$orchestration
|
||||||
->setCpus(App::getEnv('_APP_FUNCTIONS_CPUS', 0))
|
->setCpus(App::getEnv('_APP_FUNCTIONS_CPUS', 0))
|
||||||
|
@ -903,14 +902,11 @@ function runBuildStage(string $buildId, string $deploymentId, string $projectID)
|
||||||
->setAttribute('stdout', \utf8_encode(\mb_substr($buildStdout, -4096)))
|
->setAttribute('stdout', \utf8_encode(\mb_substr($buildStdout, -4096)))
|
||||||
->setAttribute('stderr', \utf8_encode(\mb_substr($e->getMessage(), -4096)))
|
->setAttribute('stderr', \utf8_encode(\mb_substr($e->getMessage(), -4096)))
|
||||||
->setAttribute('startTime', $buildStart)
|
->setAttribute('startTime', $buildStart)
|
||||||
->setAttribute('endTime', \microtime(true))
|
->setAttribute('endTime', \time())
|
||||||
->setAttribute('duration', \microtime(true) - $buildStart);
|
->setAttribute('duration', \time() - $buildStart);
|
||||||
|
|
||||||
$build = $database->updateDocument('builds', $buildId, $build);
|
$build = $database->updateDocument('builds', $buildId, $build);
|
||||||
|
|
||||||
$deployment->setAttribute('status', 'failed');
|
|
||||||
$database->updateDocument('deployments', $deploymentId, $deployment);
|
|
||||||
|
|
||||||
// also remove the container if it exists
|
// also remove the container if it exists
|
||||||
if (isset($id)) {
|
if (isset($id)) {
|
||||||
$orchestration->remove($id, true);
|
$orchestration->remove($id, true);
|
||||||
|
@ -955,58 +951,63 @@ App::post('/v1/functions/:functionId/executions')
|
||||||
|
|
||||||
App::delete('/v1/functions/:functionId')
|
App::delete('/v1/functions/:functionId')
|
||||||
->desc('Delete a function')
|
->desc('Delete a function')
|
||||||
->param('functionId', '', new UID(), 'The FunctionID to delete')
|
->param('functionId', '', new UID())
|
||||||
|
->inject('projectId')
|
||||||
->inject('response')
|
->inject('response')
|
||||||
->inject('dbForProject')
|
->inject('dbForProject')
|
||||||
->action(
|
->action(
|
||||||
function (string $functionId, Response $response, Database $dbForProject) use ($orchestrationPool) {
|
function (string $functionId, string $projectId, Response $response, Database $dbForProject) use ($orchestrationPool) {
|
||||||
try {
|
|
||||||
/** @var Orchestration $orchestration */
|
|
||||||
$orchestration = $orchestrationPool->get();
|
|
||||||
|
|
||||||
// Get function document
|
|
||||||
$function = $dbForProject->getDocument('functions', $functionId);
|
|
||||||
|
|
||||||
// Check if function exists
|
$results = $dbForProject->find('deployments', [new Query('resourceId', Query::TYPE_EQUAL, [$functionId])], 999);
|
||||||
if ($function->isEmpty()) {
|
|
||||||
throw new Exception('Function not found', 404);
|
|
||||||
}
|
|
||||||
|
|
||||||
$results = $dbForProject->find('deployments', [new Query('functionId', Query::TYPE_EQUAL, [$functionId])], 999);
|
|
||||||
|
|
||||||
// If amount is 0 then we simply return true
|
|
||||||
if (count($results) === 0) {
|
|
||||||
$response
|
|
||||||
->setStatusCode(Response::STATUS_CODE_OK)
|
|
||||||
->send();
|
|
||||||
}
|
|
||||||
|
|
||||||
// Delete the containers of all deployments
|
|
||||||
foreach ($results as $deployment) {
|
|
||||||
// Remove any ongoing builds
|
|
||||||
if ($deployment->getAttribute('buildId')) {
|
|
||||||
$build = $dbForProject->getDocument('builds', $deployment->getAttribute('buildId'));
|
|
||||||
|
|
||||||
if ($build->getAttribute('status') === 'building') {
|
|
||||||
// Remove the build
|
|
||||||
$orchestration->remove('build-stage-' . $deployment->getAttribute('buildId'), true);
|
|
||||||
Console::info('Removed build for deployment ' . $deployment['$id']);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
$orchestration->remove('appwrite-function-' . $deployment['$id'], true);
|
|
||||||
Console::info('Removed container for deployment ' . $deployment['$id']);
|
|
||||||
}
|
|
||||||
|
|
||||||
|
// If amount is 0 then we simply return true
|
||||||
|
if (count($results) === 0) {
|
||||||
$response
|
$response
|
||||||
->setStatusCode(Response::STATUS_CODE_OK)
|
->setStatusCode(Response::STATUS_CODE_OK)
|
||||||
->send();
|
->send();
|
||||||
} catch (Throwable $th) {
|
|
||||||
$orchestrationPool->put($orchestration);
|
|
||||||
throw $th;
|
|
||||||
} finally {
|
|
||||||
$orchestrationPool->put($orchestration);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Console::info('Deleting function: ' . $functionId);
|
||||||
|
// Delete the containers of all deployments
|
||||||
|
global $register;
|
||||||
|
foreach ($results as $deployment) {
|
||||||
|
go(function () use ($orchestrationPool, $deployment, $register, $projectId) {
|
||||||
|
$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);
|
||||||
|
|
||||||
|
try {
|
||||||
|
$orchestration = $orchestrationPool->get();
|
||||||
|
// Remove the container of the deployment
|
||||||
|
$orchestration->remove('appwrite-function-' . $deployment['$id'], true);
|
||||||
|
Console::success('Removed container for deployment: ' . $deployment['$id']);
|
||||||
|
|
||||||
|
$builds = $dbForProject->find('builds', [
|
||||||
|
new Query('deploymentId', Query::TYPE_EQUAL, [$deployment['$id']]),
|
||||||
|
new Query('status', Query::TYPE_EQUAL, ['building'])
|
||||||
|
], 999);
|
||||||
|
|
||||||
|
// Remove all the build containers
|
||||||
|
foreach ($builds as $build) {
|
||||||
|
$orchestration->remove('build-stage-' . $build['$id'], true);
|
||||||
|
Console::success("Removed build contanier: $build for deployment: " . $deployment['$id']);
|
||||||
|
}
|
||||||
|
} catch (\Throwable $th) {
|
||||||
|
Console::error($th->getMessage());
|
||||||
|
} finally {
|
||||||
|
$orchestrationPool->put($orchestration);
|
||||||
|
$register->get('dbPool')->put($db);
|
||||||
|
$register->get('redisPool')->put($redis);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
$response
|
||||||
|
->setStatusCode(Response::STATUS_CODE_OK)
|
||||||
|
->send();
|
||||||
}
|
}
|
||||||
);
|
);
|
||||||
|
|
||||||
|
@ -1045,40 +1046,43 @@ App::post('/v1/functions/:functionId/deployments/:deploymentId/runtime')
|
||||||
App::delete('/v1/deployments/:deploymentId')
|
App::delete('/v1/deployments/:deploymentId')
|
||||||
->desc('Delete a deployment')
|
->desc('Delete a deployment')
|
||||||
->param('deploymentId', '', new UID(), 'Deployment unique ID.')
|
->param('deploymentId', '', new UID(), 'Deployment unique ID.')
|
||||||
|
->inject('projectId')
|
||||||
->inject('response')
|
->inject('response')
|
||||||
->inject('dbForProject')
|
->action(function (string $deploymentId, string $projectId, Response $response) use ($orchestrationPool) {
|
||||||
->action(function (string $deploymentId, Response $response, Database $dbForProject) use ($orchestrationPool) {
|
Console::info('Deleting deployment: ' . $deploymentId);
|
||||||
try {
|
global $register;
|
||||||
/** @var Orchestration $orchestration */
|
go(function () use ($projectId, $orchestrationPool, $register, $deploymentId) {
|
||||||
$orchestration = $orchestrationPool->get();
|
try {
|
||||||
|
$orchestration = $orchestrationPool->get();
|
||||||
// Get deployment document
|
// Remove the container of the deployment
|
||||||
$deployment = $dbForProject->getDocument('deployments', $deploymentId);
|
$orchestration->remove('appwrite-function-' . $deploymentId , true);
|
||||||
|
Console::success('Removed container for deployment: ' . $deploymentId);
|
||||||
|
|
||||||
// Check if deployment exists
|
$db = $register->get('dbPool')->get();
|
||||||
if ($deployment->isEmpty()) {
|
$redis = $register->get('redisPool')->get();
|
||||||
throw new Exception('Deployment not found', 404);
|
$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);
|
||||||
|
|
||||||
// Remove any ongoing builds
|
$builds = $dbForProject->find('builds', [
|
||||||
if ($deployment->getAttribute('buildId')) {
|
new Query('deploymentId', Query::TYPE_EQUAL, [$deploymentId]),
|
||||||
$build = $dbForProject->getDocument('builds', $deployment->getAttribute('buildId'));
|
new Query('status', Query::TYPE_EQUAL, ['building'])
|
||||||
|
], 999);
|
||||||
|
|
||||||
if ($build->getAttribute('status') === 'building') {
|
// Remove all the build containers
|
||||||
// Remove the build
|
foreach ($builds as $build) {
|
||||||
$orchestration->remove('build-stage-' . $deployment->getAttribute('buildId'), true);
|
$orchestration->remove('build-stage-' . $build['$id'], true);
|
||||||
Console::info('Removed build for deployment ' . $deployment['$id']);
|
Console::success("Removed build container: $build for deployment: " . $deploymentId);
|
||||||
}
|
}
|
||||||
|
} catch (\Throwable $th) {
|
||||||
|
Console::error($th->getMessage());
|
||||||
|
} finally {
|
||||||
|
$orchestrationPool->put($orchestration);
|
||||||
|
$register->get('dbPool')->put($db);
|
||||||
|
$register->get('redisPool')->put($redis);
|
||||||
}
|
}
|
||||||
|
});
|
||||||
// Remove the container of the deployment
|
|
||||||
$orchestration->remove('appwrite-function-' . $deployment['$id'], true);
|
|
||||||
Console::info('Removed container for deployment ' . $deployment['$id']);
|
|
||||||
} catch (Throwable $th) {
|
|
||||||
$orchestrationPool->put($orchestration);
|
|
||||||
throw $th;
|
|
||||||
}
|
|
||||||
$orchestrationPool->put($orchestration);
|
|
||||||
|
|
||||||
$response
|
$response
|
||||||
->setStatusCode(Response::STATUS_CODE_OK)
|
->setStatusCode(Response::STATUS_CODE_OK)
|
||||||
|
@ -1147,12 +1151,10 @@ App::post('/v1/functions/:functionId/deployments/:deploymentId/builds/:buildId')
|
||||||
|
|
||||||
// Deploy Runtime Server
|
// Deploy Runtime Server
|
||||||
try {
|
try {
|
||||||
Console::info("[ INFO ] Creating runtime server");
|
Console::info("Creating runtime server");
|
||||||
createRuntimeServer($functionId, $projectId, $deploymentId, $dbForProject);
|
createRuntimeServer($functionId, $projectId, $deploymentId, $dbForProject);
|
||||||
} catch (\Throwable $th) {
|
} catch (\Throwable $th) {
|
||||||
Console::error($th->getMessage());
|
Console::error($th->getMessage());
|
||||||
$deployment->setAttribute('status', 'failed');
|
|
||||||
$deployment = $dbForProject->updateDocument('deployments', $deploymentId, $deployment);
|
|
||||||
throw $th;
|
throw $th;
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
|
@ -100,6 +100,7 @@ const DELETE_TYPE_DOCUMENT = 'document';
|
||||||
const DELETE_TYPE_COLLECTIONS = 'collections';
|
const DELETE_TYPE_COLLECTIONS = 'collections';
|
||||||
const DELETE_TYPE_PROJECTS = 'projects';
|
const DELETE_TYPE_PROJECTS = 'projects';
|
||||||
const DELETE_TYPE_FUNCTIONS = 'functions';
|
const DELETE_TYPE_FUNCTIONS = 'functions';
|
||||||
|
const DELETE_TYPE_DEPLOYMENTS = 'deployments';
|
||||||
const DELETE_TYPE_USERS = 'users';
|
const DELETE_TYPE_USERS = 'users';
|
||||||
const DELETE_TYPE_TEAMS= 'teams';
|
const DELETE_TYPE_TEAMS= 'teams';
|
||||||
const DELETE_TYPE_EXECUTIONS = 'executions';
|
const DELETE_TYPE_EXECUTIONS = 'executions';
|
||||||
|
|
|
@ -37,7 +37,7 @@ class BuildsV1 extends Worker
|
||||||
case BUILD_TYPE_DEPLOYMENT:
|
case BUILD_TYPE_DEPLOYMENT:
|
||||||
$functionId = $this->args['functionId'] ?? '';
|
$functionId = $this->args['functionId'] ?? '';
|
||||||
$deploymentId = $this->args['deploymentId'] ?? '';
|
$deploymentId = $this->args['deploymentId'] ?? '';
|
||||||
Console::info("[ INFO ] Creating build for deployment: $deploymentId");
|
Console::info("Creating build for deployment: $deploymentId");
|
||||||
$this->buildDeployment($projectId, $functionId, $deploymentId);
|
$this->buildDeployment($projectId, $functionId, $deploymentId);
|
||||||
break;
|
break;
|
||||||
|
|
||||||
|
@ -45,7 +45,7 @@ class BuildsV1 extends Worker
|
||||||
$buildId = $this->args['buildId'] ?? '';
|
$buildId = $this->args['buildId'] ?? '';
|
||||||
$functionId = $this->args['functionId'] ?? '';
|
$functionId = $this->args['functionId'] ?? '';
|
||||||
$deploymentId = $this->args['deploymentId'] ?? '';
|
$deploymentId = $this->args['deploymentId'] ?? '';
|
||||||
Console::info("[ INFO ] Retrying build for id: $buildId");
|
Console::info("Retrying build for id: $buildId");
|
||||||
$this->createBuild($projectId, $functionId, $deploymentId, $buildId);
|
$this->createBuild($projectId, $functionId, $deploymentId, $buildId);
|
||||||
break;
|
break;
|
||||||
|
|
||||||
|
@ -113,28 +113,21 @@ class BuildsV1 extends Worker
|
||||||
if (empty($buildId)) {
|
if (empty($buildId)) {
|
||||||
try {
|
try {
|
||||||
$buildId = $dbForProject->getId();
|
$buildId = $dbForProject->getId();
|
||||||
// TODO : There is no way to associate a build with a deployment. So we need to add a deploymentId attribute to the build document
|
|
||||||
$dbForProject->createDocument('builds', new Document([
|
$dbForProject->createDocument('builds', new Document([
|
||||||
'$id' => $buildId,
|
'$id' => $buildId,
|
||||||
'$read' => [],
|
'$read' => [],
|
||||||
'$write' => [],
|
'$write' => [],
|
||||||
'dateCreated' => time(),
|
'startTime' => time(),
|
||||||
|
'deploymentId' => $deploymentId,
|
||||||
'status' => 'processing',
|
'status' => 'processing',
|
||||||
'runtime' => $function->getAttribute('runtime'),
|
|
||||||
'outputPath' => '',
|
'outputPath' => '',
|
||||||
|
'runtime' => $function->getAttribute('runtime'),
|
||||||
'source' => $deployment->getAttribute('path'),
|
'source' => $deployment->getAttribute('path'),
|
||||||
'sourceType' => Storage::DEVICE_LOCAL,
|
'sourceType' => Storage::DEVICE_LOCAL,
|
||||||
'stdout' => '',
|
'stdout' => '',
|
||||||
'stderr' => '',
|
'stderr' => '',
|
||||||
'time' => 0,
|
'endTime' => 0,
|
||||||
'vars' => [
|
'duration' => 0
|
||||||
'ENTRYPOINT_NAME' => $deployment->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,
|
|
||||||
]
|
|
||||||
]));
|
]));
|
||||||
} catch (\Throwable $th) {
|
} catch (\Throwable $th) {
|
||||||
$deployment->setAttribute('buildId', '');
|
$deployment->setAttribute('buildId', '');
|
||||||
|
@ -154,7 +147,7 @@ class BuildsV1 extends Worker
|
||||||
throw $th;
|
throw $th;
|
||||||
}
|
}
|
||||||
|
|
||||||
Console::success("[ SUCCESS ] Build id: $buildId started");
|
Console::success("Build id: $buildId started");
|
||||||
}
|
}
|
||||||
|
|
||||||
public function shutdown(): void {}
|
public function shutdown(): void {}
|
||||||
|
|
|
@ -8,11 +8,14 @@ use Appwrite\Resque\Worker;
|
||||||
use Utopia\Storage\Device\Local;
|
use Utopia\Storage\Device\Local;
|
||||||
use Utopia\Abuse\Abuse;
|
use Utopia\Abuse\Abuse;
|
||||||
use Utopia\Abuse\Adapters\TimeLimit;
|
use Utopia\Abuse\Adapters\TimeLimit;
|
||||||
|
use Utopia\App;
|
||||||
use Utopia\CLI\Console;
|
use Utopia\CLI\Console;
|
||||||
use Utopia\Audit\Audit;
|
use Utopia\Audit\Audit;
|
||||||
|
|
||||||
require_once __DIR__ . '/../init.php';
|
require_once __DIR__ . '/../init.php';
|
||||||
|
|
||||||
|
Authorization::disable();
|
||||||
|
|
||||||
Console::title('Deletes V1 Worker');
|
Console::title('Deletes V1 Worker');
|
||||||
Console::success(APP_NAME . ' deletes worker v1 has started' . "\n");
|
Console::success(APP_NAME . ' deletes worker v1 has started' . "\n");
|
||||||
|
|
||||||
|
@ -50,6 +53,9 @@ class DeletesV1 extends Worker
|
||||||
case DELETE_TYPE_FUNCTIONS:
|
case DELETE_TYPE_FUNCTIONS:
|
||||||
$this->deleteFunction($document, $projectId);
|
$this->deleteFunction($document, $projectId);
|
||||||
break;
|
break;
|
||||||
|
case DELETE_TYPE_DEPLOYMENTS:
|
||||||
|
$this->deleteDeployment($document, $projectId);
|
||||||
|
break;
|
||||||
case DELETE_TYPE_USERS:
|
case DELETE_TYPE_USERS:
|
||||||
$this->deleteUser($document, $projectId);
|
$this->deleteUser($document, $projectId);
|
||||||
break;
|
break;
|
||||||
|
@ -202,7 +208,7 @@ class DeletesV1 extends Worker
|
||||||
], $this->getProjectDB($projectId));
|
], $this->getProjectDB($projectId));
|
||||||
|
|
||||||
$user->setAttribute('sessions', []);
|
$user->setAttribute('sessions', []);
|
||||||
$updated = Authorization::skip(fn() => $this->getProjectDB($projectId)->updateDocument('users', $userId, $user));
|
$updated = $this->getProjectDB($projectId)->updateDocument('users', $userId, $user);
|
||||||
|
|
||||||
// Delete Memberships and decrement team membership counts
|
// Delete Memberships and decrement team membership counts
|
||||||
$this->deleteByGroup('memberships', [
|
$this->deleteByGroup('memberships', [
|
||||||
|
@ -307,24 +313,139 @@ class DeletesV1 extends Worker
|
||||||
protected function deleteFunction(Document $document, string $projectId): void
|
protected function deleteFunction(Document $document, string $projectId): void
|
||||||
{
|
{
|
||||||
$dbForProject = $this->getProjectDB($projectId);
|
$dbForProject = $this->getProjectDB($projectId);
|
||||||
$device = new Local(APP_STORAGE_FUNCTIONS . '/app-' . $projectId);
|
|
||||||
|
|
||||||
// Delete Deployments
|
/**
|
||||||
|
* Request executor to delete all deployment containers
|
||||||
|
*/
|
||||||
|
try {
|
||||||
|
$ch = \curl_init();
|
||||||
|
\curl_setopt($ch, CURLOPT_CUSTOMREQUEST, 'DELETE');
|
||||||
|
\curl_setopt($ch, CURLOPT_URL, "http://appwrite-executor/v1/functions/{$document->getId()}");
|
||||||
|
\curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
|
||||||
|
\curl_setopt($ch, CURLOPT_HTTPHEADER, [
|
||||||
|
'Content-Type: application/json',
|
||||||
|
'x-appwrite-project: '. $projectId,
|
||||||
|
'x-appwrite-executor-key: '. App::getEnv('_APP_EXECUTOR_SECRET', '')
|
||||||
|
]);
|
||||||
|
|
||||||
|
$executorResponse = \curl_exec($ch);
|
||||||
|
$error = \curl_error($ch);
|
||||||
|
if (!empty($error)) {
|
||||||
|
throw new Exception($error, 500);
|
||||||
|
}
|
||||||
|
|
||||||
|
$statusCode = \curl_getinfo($ch, CURLINFO_HTTP_CODE);
|
||||||
|
if ($statusCode >= 400) {
|
||||||
|
throw new Exception('Executor error: ' . $executorResponse, $statusCode);
|
||||||
|
}
|
||||||
|
|
||||||
|
\curl_close($ch);
|
||||||
|
} catch (Throwable $th) {
|
||||||
|
Console::error($th->getMessage());
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Delete Deployments
|
||||||
|
*/
|
||||||
|
$storageFunctions = new Local(APP_STORAGE_FUNCTIONS . '/app-' . $projectId);
|
||||||
|
$deploymentIds = [];
|
||||||
$this->deleteByGroup('deployments', [
|
$this->deleteByGroup('deployments', [
|
||||||
new Query('functionId', Query::TYPE_EQUAL, [$document->getId()])
|
new Query('resourceId', Query::TYPE_EQUAL, [$document->getId()])
|
||||||
], $dbForProject, function (Document $document) use ($device) {
|
], $dbForProject, function (Document $document) use ($storageFunctions, &$deploymentIds) {
|
||||||
|
$deploymentIds[] = $document->getId();
|
||||||
if ($device->delete($document->getAttribute('path', ''))) {
|
if ($storageFunctions->delete($document->getAttribute('path', ''), true)) {
|
||||||
Console::success('Delete code deployment: ' . $document->getAttribute('path', ''));
|
Console::success('Deleted deployment files: ' . $document->getAttribute('path', ''));
|
||||||
} else {
|
} else {
|
||||||
Console::error('Failed to delete code deployment: ' . $document->getAttribute('path', ''));
|
Console::error('Failed to delete deployment files: ' . $document->getAttribute('path', ''));
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Delete builds
|
||||||
|
*/
|
||||||
|
if (!empty($deploymentIds)) {
|
||||||
|
$storageBuilds = new Local(APP_STORAGE_BUILDS . '/app-' . $projectId);
|
||||||
|
$this->deleteByGroup('builds', [
|
||||||
|
new Query('deploymentId', Query::TYPE_EQUAL, $deploymentIds)
|
||||||
|
], $dbForProject, function (Document $document) use ($storageBuilds) {
|
||||||
|
if ($storageBuilds->delete($document->getAttribute('outputPath', ''), true)) {
|
||||||
|
Console::success('Deleted build files: ' . $document->getAttribute('outputPath', ''));
|
||||||
|
} else {
|
||||||
|
Console::error('Failed to delete build files: ' . $document->getAttribute('outputPath', ''));
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
// Delete Executions
|
// Delete Executions
|
||||||
$this->deleteByGroup('executions', [
|
$this->deleteByGroup('executions', [
|
||||||
new Query('functionId', Query::TYPE_EQUAL, [$document->getId()])
|
new Query('functionId', Query::TYPE_EQUAL, [$document->getId()])
|
||||||
], $dbForProject);
|
], $dbForProject);
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param Document $document deployment document
|
||||||
|
* @param string $projectId
|
||||||
|
*/
|
||||||
|
protected function deleteDeployment(Document $document, string $projectId): void
|
||||||
|
{
|
||||||
|
$dbForProject = $this->getProjectDB($projectId);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Request executor to delete the deployment containers
|
||||||
|
*/
|
||||||
|
try {
|
||||||
|
$ch = \curl_init();
|
||||||
|
\curl_setopt($ch, CURLOPT_CUSTOMREQUEST, 'DELETE');
|
||||||
|
// TODO: Implement coroutines.
|
||||||
|
\curl_setopt($ch, CURLOPT_URL, "http://appwrite-executor/v1/deployments/{$document->getId()}");
|
||||||
|
\curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
|
||||||
|
\curl_setopt($ch, CURLOPT_HTTPHEADER, [
|
||||||
|
'Content-Type: application/json',
|
||||||
|
'x-appwrite-project: '. $projectId,
|
||||||
|
'x-appwrite-executor-key: '. App::getEnv('_APP_EXECUTOR_SECRET', '')
|
||||||
|
]);
|
||||||
|
|
||||||
|
$executorResponse = \curl_exec($ch);
|
||||||
|
$error = \curl_error($ch);
|
||||||
|
if (!empty($error)) {
|
||||||
|
throw new Exception($error, 500);
|
||||||
|
}
|
||||||
|
|
||||||
|
$statusCode = \curl_getinfo($ch, CURLINFO_HTTP_CODE);
|
||||||
|
if ($statusCode >= 400) {
|
||||||
|
throw new Exception('Executor error: ' . $executorResponse, $statusCode);
|
||||||
|
}
|
||||||
|
|
||||||
|
\curl_close($ch);
|
||||||
|
} catch (Throwable $th) {
|
||||||
|
Console::error($th->getMessage());
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Delete deployment files
|
||||||
|
*/
|
||||||
|
$storageFunctions = new Local(APP_STORAGE_FUNCTIONS . '/app-' . $projectId);
|
||||||
|
if ($storageFunctions->delete($document->getAttribute('path', ''), true)) {
|
||||||
|
Console::success('Deleted deployment files: ' . $document->getAttribute('path', ''));
|
||||||
|
} else {
|
||||||
|
Console::error('Failed to delete deployment files: ' . $document->getAttribute('path', ''));
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Delete builds
|
||||||
|
*/
|
||||||
|
$storageBuilds = new Local(APP_STORAGE_BUILDS . '/app-' . $projectId);
|
||||||
|
$this->deleteByGroup('builds', [
|
||||||
|
new Query('deploymentId', Query::TYPE_EQUAL, [$document->getId()])
|
||||||
|
], $dbForProject, function (Document $document) use ($storageBuilds) {
|
||||||
|
if ($storageBuilds->delete($document->getAttribute('outputPath', ''), true)) {
|
||||||
|
Console::success('Deleted build files: ' . $document->getAttribute('outputPath', ''));
|
||||||
|
} else {
|
||||||
|
Console::error('Failed to delete build files: ' . $document->getAttribute('outputPath', ''));
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@ -337,8 +458,6 @@ class DeletesV1 extends Worker
|
||||||
*/
|
*/
|
||||||
protected function deleteById(Document $document, Database $database, callable $callback = null): bool
|
protected function deleteById(Document $document, Database $database, callable $callback = null): bool
|
||||||
{
|
{
|
||||||
Authorization::disable();
|
|
||||||
|
|
||||||
if ($database->deleteDocument($document->getCollection(), $document->getId())) {
|
if ($database->deleteDocument($document->getCollection(), $document->getId())) {
|
||||||
Console::success('Deleted document "' . $document->getId() . '" successfully');
|
Console::success('Deleted document "' . $document->getId() . '" successfully');
|
||||||
|
|
||||||
|
@ -351,8 +470,6 @@ class DeletesV1 extends Worker
|
||||||
Console::error('Failed to delete document: ' . $document->getId());
|
Console::error('Failed to delete document: ' . $document->getId());
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
Authorization::reset();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -369,9 +486,7 @@ class DeletesV1 extends Worker
|
||||||
$executionStart = \microtime(true);
|
$executionStart = \microtime(true);
|
||||||
|
|
||||||
while ($sum === $limit) {
|
while ($sum === $limit) {
|
||||||
Authorization::disable();
|
|
||||||
$projects = $this->getConsoleDB()->find('projects', [], $limit, ($chunk * $limit));
|
$projects = $this->getConsoleDB()->find('projects', [], $limit, ($chunk * $limit));
|
||||||
Authorization::reset();
|
|
||||||
|
|
||||||
$chunk++;
|
$chunk++;
|
||||||
|
|
||||||
|
@ -410,12 +525,8 @@ class DeletesV1 extends Worker
|
||||||
while ($sum === $limit) {
|
while ($sum === $limit) {
|
||||||
$chunk++;
|
$chunk++;
|
||||||
|
|
||||||
Authorization::disable();
|
|
||||||
|
|
||||||
$results = $database->find($collection, $queries, $limit, 0);
|
$results = $database->find($collection, $queries, $limit, 0);
|
||||||
|
|
||||||
Authorization::reset();
|
|
||||||
|
|
||||||
$sum = count($results);
|
$sum = count($results);
|
||||||
|
|
||||||
Console::info('Deleting chunk #' . $chunk . '. Found ' . $sum . ' documents');
|
Console::info('Deleting chunk #' . $chunk . '. Found ' . $sum . ' documents');
|
||||||
|
|
|
@ -238,6 +238,7 @@ services:
|
||||||
- appwrite-uploads:/storage/uploads:rw
|
- appwrite-uploads:/storage/uploads:rw
|
||||||
- appwrite-cache:/storage/cache:rw
|
- appwrite-cache:/storage/cache:rw
|
||||||
- appwrite-functions:/storage/functions:rw
|
- appwrite-functions:/storage/functions:rw
|
||||||
|
- appwrite-builds:/storage/builds:rw
|
||||||
- appwrite-certificates:/storage/certificates:rw
|
- appwrite-certificates:/storage/certificates:rw
|
||||||
- ./app:/usr/src/code/app
|
- ./app:/usr/src/code/app
|
||||||
- ./src:/usr/src/code/src
|
- ./src:/usr/src/code/src
|
||||||
|
@ -396,6 +397,7 @@ services:
|
||||||
volumes:
|
volumes:
|
||||||
- /var/run/docker.sock:/var/run/docker.sock
|
- /var/run/docker.sock:/var/run/docker.sock
|
||||||
- appwrite-functions:/storage/functions:rw
|
- appwrite-functions:/storage/functions:rw
|
||||||
|
- appwrite-builds:/storage/builds:rw
|
||||||
- /tmp:/tmp:rw
|
- /tmp:/tmp:rw
|
||||||
- ./app:/usr/src/code/app
|
- ./app:/usr/src/code/app
|
||||||
- ./src:/usr/src/code/src
|
- ./src:/usr/src/code/src
|
||||||
|
@ -696,6 +698,7 @@ volumes:
|
||||||
appwrite-uploads:
|
appwrite-uploads:
|
||||||
appwrite-certificates:
|
appwrite-certificates:
|
||||||
appwrite-functions:
|
appwrite-functions:
|
||||||
|
appwrite-builds:
|
||||||
appwrite-influxdb:
|
appwrite-influxdb:
|
||||||
appwrite-config:
|
appwrite-config:
|
||||||
appwrite-executor:
|
appwrite-executor:
|
||||||
|
|
|
@ -87,7 +87,7 @@ class FunctionsCustomClientTest extends Scope
|
||||||
$this->assertEquals(201, $deployment['headers']['status-code']);
|
$this->assertEquals(201, $deployment['headers']['status-code']);
|
||||||
|
|
||||||
// Wait for deployment to be built.
|
// Wait for deployment to be built.
|
||||||
sleep(5);
|
sleep(10);
|
||||||
|
|
||||||
$function = $this->client->call(Client::METHOD_PATCH, '/functions/'.$function['body']['$id'].'/deployment', [
|
$function = $this->client->call(Client::METHOD_PATCH, '/functions/'.$function['body']['$id'].'/deployment', [
|
||||||
'content-type' => 'application/json',
|
'content-type' => 'application/json',
|
||||||
|
@ -97,6 +97,8 @@ class FunctionsCustomClientTest extends Scope
|
||||||
'deployment' => $deploymentId,
|
'deployment' => $deploymentId,
|
||||||
]);
|
]);
|
||||||
|
|
||||||
|
// var_dump($function);
|
||||||
|
|
||||||
$this->assertEquals(200, $function['headers']['status-code']);
|
$this->assertEquals(200, $function['headers']['status-code']);
|
||||||
|
|
||||||
$execution = $this->client->call(Client::METHOD_POST, '/functions/'.$function['body']['$id'].'/executions', [
|
$execution = $this->client->call(Client::METHOD_POST, '/functions/'.$function['body']['$id'].'/executions', [
|
||||||
|
@ -117,14 +119,14 @@ class FunctionsCustomClientTest extends Scope
|
||||||
|
|
||||||
$this->assertEquals(201, $execution['headers']['status-code']);
|
$this->assertEquals(201, $execution['headers']['status-code']);
|
||||||
|
|
||||||
$execution = $this->client->call(Client::METHOD_POST, '/functions/'.$function['body']['$id'].'/executions', array_merge([
|
// Cleanup : Delete function
|
||||||
|
$response = $this->client->call(Client::METHOD_DELETE, '/functions/'.$function['body']['$id'], [
|
||||||
'content-type' => 'application/json',
|
'content-type' => 'application/json',
|
||||||
'x-appwrite-project' => $this->getProject()['$id'],
|
'x-appwrite-project' => $this->getProject()['$id'],
|
||||||
]), [
|
'x-appwrite-key' => $this->getProject()['apiKey'],
|
||||||
'async' => true,
|
], []);
|
||||||
]);
|
|
||||||
|
|
||||||
$this->assertEquals(401, $execution['headers']['status-code']);
|
$this->assertEquals(204, $response['headers']['status-code']);
|
||||||
|
|
||||||
return [];
|
return [];
|
||||||
}
|
}
|
||||||
|
@ -300,6 +302,16 @@ class FunctionsCustomClientTest extends Scope
|
||||||
'cursor' => $base['body']['executions'][1]['$id'],
|
'cursor' => $base['body']['executions'][1]['$id'],
|
||||||
'cursorDirection' => Database::CURSOR_BEFORE
|
'cursorDirection' => Database::CURSOR_BEFORE
|
||||||
]);
|
]);
|
||||||
|
|
||||||
|
// Cleanup : Delete function
|
||||||
|
$response = $this->client->call(Client::METHOD_DELETE, '/functions/'. $functionId, [
|
||||||
|
'content-type' => 'application/json',
|
||||||
|
'x-appwrite-project' => $this->getProject()['$id'],
|
||||||
|
'x-appwrite-key' => $this->getProject()['apiKey'],
|
||||||
|
], []);
|
||||||
|
|
||||||
|
$this->assertEquals(204, $response['headers']['status-code']);
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public function testSynchronousExecution():array
|
public function testSynchronousExecution():array
|
||||||
|
@ -346,7 +358,7 @@ class FunctionsCustomClientTest extends Scope
|
||||||
$this->assertEquals(201, $deployment['headers']['status-code']);
|
$this->assertEquals(201, $deployment['headers']['status-code']);
|
||||||
|
|
||||||
// Wait for deployment to be built.
|
// Wait for deployment to be built.
|
||||||
sleep(5);
|
sleep(10);
|
||||||
|
|
||||||
$function = $this->client->call(Client::METHOD_PATCH, '/functions/'.$functionId.'/deployment', [
|
$function = $this->client->call(Client::METHOD_PATCH, '/functions/'.$functionId.'/deployment', [
|
||||||
'content-type' => 'application/json',
|
'content-type' => 'application/json',
|
||||||
|
@ -382,6 +394,15 @@ class FunctionsCustomClientTest extends Scope
|
||||||
$this->assertNotEmpty($output['APPWRITE_FUNCTION_JWT']);
|
$this->assertNotEmpty($output['APPWRITE_FUNCTION_JWT']);
|
||||||
$this->assertEquals($projectId, $output['APPWRITE_FUNCTION_PROJECT_ID']);
|
$this->assertEquals($projectId, $output['APPWRITE_FUNCTION_PROJECT_ID']);
|
||||||
|
|
||||||
|
// Cleanup : Delete function
|
||||||
|
$response = $this->client->call(Client::METHOD_DELETE, '/functions/'. $functionId, [
|
||||||
|
'content-type' => 'application/json',
|
||||||
|
'x-appwrite-project' => $this->getProject()['$id'],
|
||||||
|
'x-appwrite-key' => $this->getProject()['apiKey'],
|
||||||
|
], []);
|
||||||
|
|
||||||
|
$this->assertEquals(204, $response['headers']['status-code']);
|
||||||
|
|
||||||
return [];
|
return [];
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -291,10 +291,9 @@ class FunctionsCustomServerTest extends Scope
|
||||||
$this->assertNotEmpty($deployment['body']['$id']);
|
$this->assertNotEmpty($deployment['body']['$id']);
|
||||||
$this->assertIsInt($deployment['body']['dateCreated']);
|
$this->assertIsInt($deployment['body']['dateCreated']);
|
||||||
$this->assertEquals('index.php', $deployment['body']['entrypoint']);
|
$this->assertEquals('index.php', $deployment['body']['entrypoint']);
|
||||||
// $this->assertGreaterThan(10000, $deployment['body']['size']);
|
|
||||||
|
|
||||||
// Wait for deployment to build.
|
// Wait for deployment to build.
|
||||||
sleep(5);
|
sleep(15);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Test for FAILURE
|
* Test for FAILURE
|
||||||
|
@ -450,7 +449,7 @@ class FunctionsCustomServerTest extends Scope
|
||||||
$this->assertEquals('', $execution['body']['stderr']);
|
$this->assertEquals('', $execution['body']['stderr']);
|
||||||
$this->assertEquals(0, $execution['body']['time']);
|
$this->assertEquals(0, $execution['body']['time']);
|
||||||
|
|
||||||
sleep(15);
|
sleep(5);
|
||||||
|
|
||||||
$execution = $this->client->call(Client::METHOD_GET, '/functions/'.$data['functionId'].'/executions/'.$executionId, array_merge([
|
$execution = $this->client->call(Client::METHOD_GET, '/functions/'.$data['functionId'].'/executions/'.$executionId, array_merge([
|
||||||
'content-type' => 'application/json',
|
'content-type' => 'application/json',
|
||||||
|
@ -628,7 +627,7 @@ class FunctionsCustomServerTest extends Scope
|
||||||
/**
|
/**
|
||||||
* Test for SUCCESS
|
* Test for SUCCESS
|
||||||
*/
|
*/
|
||||||
$function = $this->client->call(Client::METHOD_DELETE, '/functions/'.$data['functionId'], array_merge([
|
$function = $this->client->call(Client::METHOD_DELETE, '/functions/'. $data['functionId'], array_merge([
|
||||||
'content-type' => 'application/json',
|
'content-type' => 'application/json',
|
||||||
'x-appwrite-project' => $this->getProject()['$id'],
|
'x-appwrite-project' => $this->getProject()['$id'],
|
||||||
], $this->getHeaders()));
|
], $this->getHeaders()));
|
||||||
|
@ -686,7 +685,7 @@ class FunctionsCustomServerTest extends Scope
|
||||||
$this->assertEquals(201, $deployment['headers']['status-code']);
|
$this->assertEquals(201, $deployment['headers']['status-code']);
|
||||||
|
|
||||||
// Allow build step to run
|
// Allow build step to run
|
||||||
sleep(5);
|
sleep(10);
|
||||||
|
|
||||||
$deployment = $this->client->call(Client::METHOD_PATCH, '/functions/'.$functionId.'/deployment', array_merge([
|
$deployment = $this->client->call(Client::METHOD_PATCH, '/functions/'.$functionId.'/deployment', array_merge([
|
||||||
'content-type' => 'application/json',
|
'content-type' => 'application/json',
|
||||||
|
@ -728,6 +727,15 @@ class FunctionsCustomServerTest extends Scope
|
||||||
$this->assertLessThan(3, $executions['body']['executions'][0]['time']);
|
$this->assertLessThan(3, $executions['body']['executions'][0]['time']);
|
||||||
$this->assertEquals($executions['body']['executions'][0]['stdout'], '');
|
$this->assertEquals($executions['body']['executions'][0]['stdout'], '');
|
||||||
$this->assertEquals($executions['body']['executions'][0]['stderr'], 'Execution timed out.');
|
$this->assertEquals($executions['body']['executions'][0]['stderr'], 'Execution timed out.');
|
||||||
|
|
||||||
|
// Cleanup : Delete function
|
||||||
|
$response = $this->client->call(Client::METHOD_DELETE, '/functions/'. $functionId, [
|
||||||
|
'content-type' => 'application/json',
|
||||||
|
'x-appwrite-project' => $this->getProject()['$id'],
|
||||||
|
'x-appwrite-key' => $this->getProject()['apiKey'],
|
||||||
|
], []);
|
||||||
|
|
||||||
|
$this->assertEquals(204, $response['headers']['status-code']);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -769,7 +777,7 @@ class FunctionsCustomServerTest extends Scope
|
||||||
$this->assertEquals(201, $deployment['headers']['status-code']);
|
$this->assertEquals(201, $deployment['headers']['status-code']);
|
||||||
|
|
||||||
// Allow build step to run
|
// Allow build step to run
|
||||||
sleep(5);
|
sleep(10);
|
||||||
|
|
||||||
$deployment = $this->client->call(Client::METHOD_PATCH, '/functions/'.$functionId.'/deployment', array_merge([
|
$deployment = $this->client->call(Client::METHOD_PATCH, '/functions/'.$functionId.'/deployment', array_merge([
|
||||||
'content-type' => 'application/json',
|
'content-type' => 'application/json',
|
||||||
|
@ -829,6 +837,15 @@ class FunctionsCustomServerTest extends Scope
|
||||||
$this->assertEquals($executions['body']['executions'][0]['$id'], $executionId);
|
$this->assertEquals($executions['body']['executions'][0]['$id'], $executionId);
|
||||||
$this->assertEquals($executions['body']['executions'][0]['trigger'], 'http');
|
$this->assertEquals($executions['body']['executions'][0]['trigger'], 'http');
|
||||||
$this->assertStringContainsString('foobar', $executions['body']['executions'][0]['stdout']);
|
$this->assertStringContainsString('foobar', $executions['body']['executions'][0]['stdout']);
|
||||||
|
|
||||||
|
// Cleanup : Delete function
|
||||||
|
$response = $this->client->call(Client::METHOD_DELETE, '/functions/'. $functionId, [
|
||||||
|
'content-type' => 'application/json',
|
||||||
|
'x-appwrite-project' => $this->getProject()['$id'],
|
||||||
|
'x-appwrite-key' => $this->getProject()['apiKey'],
|
||||||
|
], []);
|
||||||
|
|
||||||
|
$this->assertEquals(204, $response['headers']['status-code']);
|
||||||
}
|
}
|
||||||
|
|
||||||
public function testGetRuntimes()
|
public function testGetRuntimes()
|
||||||
|
|
|
@ -36,7 +36,7 @@ class ComposeTest extends TestCase
|
||||||
|
|
||||||
public function testServices()
|
public function testServices()
|
||||||
{
|
{
|
||||||
$this->assertCount(16, $this->object->getServices());
|
$this->assertCount(17, $this->object->getServices());
|
||||||
$this->assertEquals('appwrite-telegraf', $this->object->getService('telegraf')->getContainerName());
|
$this->assertEquals('appwrite-telegraf', $this->object->getService('telegraf')->getContainerName());
|
||||||
$this->assertEquals('appwrite', $this->object->getService('appwrite')->getContainerName());
|
$this->assertEquals('appwrite', $this->object->getService('appwrite')->getContainerName());
|
||||||
$this->assertEquals('', $this->object->getService('appwrite')->getImageVersion());
|
$this->assertEquals('', $this->object->getService('appwrite')->getImageVersion());
|
||||||
|
|
Loading…
Reference in a new issue