Merge branch 'feat-functions-refactor' of github.com:appwrite/appwrite into feat-cleanup-executor
This commit is contained in:
commit
4a405323cb
24 changed files with 450 additions and 272 deletions
3
.env
3
.env
|
@ -39,7 +39,8 @@ _APP_FUNCTIONS_CONTAINERS=10
|
|||
_APP_FUNCTIONS_CPUS=4
|
||||
_APP_FUNCTIONS_MEMORY=2000
|
||||
_APP_FUNCTIONS_MEMORY_SWAP=2000
|
||||
_APP_EXECUTOR_SECRET=a-randomly-generated-key
|
||||
_APP_EXECUTOR_RUNTIME_NETWORK=appwrite_runtimes
|
||||
_APP_EXECUTOR_SECRET=a-random-secret
|
||||
_APP_MAINTENANCE_INTERVAL=86400
|
||||
_APP_MAINTENANCE_RETENTION_EXECUTION=1209600
|
||||
_APP_MAINTENANCE_RETENTION_ABUSE=86400
|
||||
|
|
|
@ -3,7 +3,7 @@
|
|||
- Introduced new execution model for functions
|
||||
- Improved functions execution times
|
||||
- Improved functions execution times
|
||||
- Improved functions execution times
|
||||
- Create a new builds worker to handle building of deployments
|
||||
- **[ Breaking ]** **Tags** have been renamed to **Deployments**
|
||||
- Rename `tagId` to `deplyomentId` in collections
|
||||
- Rename tags to deployments in the docs
|
||||
|
|
|
@ -174,6 +174,7 @@ ENV _APP_SERVER=swoole \
|
|||
_APP_FUNCTIONS_MEMORY=128 \
|
||||
_APP_FUNCTIONS_MEMORY_SWAP=128 \
|
||||
_APP_EXECUTOR_SECRET=a-random-secret \
|
||||
_APP_EXECUTOR_RUNTIME_NETWORK=appwrite_runtimes \
|
||||
_APP_SETUP=self-hosted \
|
||||
_APP_VERSION=$VERSION \
|
||||
_APP_USAGE_STATS=enabled \
|
||||
|
@ -269,6 +270,7 @@ RUN chmod +x /usr/local/bin/doctor && \
|
|||
chmod +x /usr/local/bin/worker-database && \
|
||||
chmod +x /usr/local/bin/worker-deletes && \
|
||||
chmod +x /usr/local/bin/worker-functions && \
|
||||
chmod +x /usr/local/bin/worker-builds && \
|
||||
chmod +x /usr/local/bin/worker-mails && \
|
||||
chmod +x /usr/local/bin/worker-webhooks && \
|
||||
chmod +x /usr/local/bin/executor
|
||||
|
|
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
|
@ -498,6 +498,15 @@ return [
|
|||
'question' => '',
|
||||
'filter' => ''
|
||||
],
|
||||
[
|
||||
'name' => '_APP_EXECUTOR_RUNTIME_NETWORK',
|
||||
'description' => 'The docker network used for communication between the executor and runtimes. Change this if you have altered the default network names.',
|
||||
'introduction' => '0.13.0',
|
||||
'default' => 'appwrite_runtimes',
|
||||
'required' => false,
|
||||
'question' => '',
|
||||
'filter' => ''
|
||||
],
|
||||
[
|
||||
'name' => '_APP_FUNCTIONS_ENVS',
|
||||
'description' => 'Deprecated with 0.8.0, use \'_APP_FUNCTIONS_RUNTIMES\' instead!',
|
||||
|
|
|
@ -3,6 +3,7 @@
|
|||
use Ahc\Jwt\JWT;
|
||||
use Appwrite\Auth\Auth;
|
||||
use Appwrite\Database\Validator\CustomId;
|
||||
use Appwrite\Event\Event;
|
||||
use Utopia\Database\Validator\UID;
|
||||
use Utopia\Storage\Storage;
|
||||
use Utopia\Storage\Validator\File;
|
||||
|
@ -367,7 +368,7 @@ App::patch('/v1/functions/:functionId/deployment')
|
|||
|
||||
$function = $dbForProject->getDocument('functions', $functionId);
|
||||
$deployment = $dbForProject->getDocument('deployments', $deployment);
|
||||
$build = $dbForProject->getDocument('builds', $deployment->getAttribute('buildId'));
|
||||
$build = $dbForProject->getDocument('builds', $deployment->getAttribute('buildId', ''));
|
||||
|
||||
if ($function->isEmpty()) {
|
||||
throw new Exception('Function not found', 404);
|
||||
|
@ -433,11 +434,8 @@ App::delete('/v1/functions/:functionId')
|
|||
|
||||
// Request executor to delete deployment 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);
|
||||
|
@ -582,45 +580,18 @@ App::post('/v1/functions/:functionId/deployments')
|
|||
'deploy' => ($deploy === 'true'),
|
||||
]));
|
||||
|
||||
// Enqueue a message to start the build
|
||||
Resque::enqueue(Event::BUILDS_QUEUE_NAME, Event::BUILDS_CLASS_NAME, [
|
||||
'projectId' => $project->getId(),
|
||||
'functionId' => $function->getId(),
|
||||
'deploymentId' => $deploymentId,
|
||||
'type' => BUILD_TYPE_DEPLOYMENT
|
||||
]);
|
||||
|
||||
$usage
|
||||
->setParam('storage', $deployment->getAttribute('size', 0))
|
||||
;
|
||||
|
||||
// Send start build reqeust to executor using /v1/deployment
|
||||
$function = $dbForProject->getDocument('functions', $functionId);
|
||||
|
||||
$ch = \curl_init();
|
||||
\curl_setopt($ch, CURLOPT_URL, "http://appwrite-executor/v1/deployment");
|
||||
\curl_setopt($ch, CURLOPT_POST, true);
|
||||
\curl_setopt($ch, CURLOPT_POSTFIELDS, json_encode([
|
||||
'functionId' => $function->getId(),
|
||||
'deploymentId' => $deployment->getId(),
|
||||
'userId' => $user->getId(),
|
||||
]));
|
||||
\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 Communication 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);
|
||||
|
||||
$response->setStatusCode(Response::STATUS_CODE_CREATED);
|
||||
$response->dynamic($deployment, Response::MODEL_DEPLOYMENT);
|
||||
|
@ -769,11 +740,8 @@ App::delete('/v1/functions/:functionId/deployments/:deploymentId')
|
|||
|
||||
// Request executor to delete deployment containers
|
||||
$ch = \curl_init();
|
||||
\curl_setopt($ch, CURLOPT_URL, "http://appwrite-executor/v1/cleanup/deployment");
|
||||
\curl_setopt($ch, CURLOPT_POST, true);
|
||||
\curl_setopt($ch, CURLOPT_POSTFIELDS, json_encode([
|
||||
'deploymentId' => $deploymentId
|
||||
]));
|
||||
\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);
|
||||
|
@ -927,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(),
|
||||
|
@ -958,8 +925,8 @@ App::post('/v1/functions/:functionId/executions')
|
|||
\curl_close($ch);
|
||||
|
||||
$response
|
||||
->setStatusCode(Response::STATUS_CODE_CREATED)
|
||||
->dynamic(new Document(json_decode($responseExecute, true)), Response::MODEL_SYNC_EXECUTION);
|
||||
->setStatusCode(Response::STATUS_CODE_CREATED)
|
||||
->dynamic(new Document(json_decode($responseExecute, true)), Response::MODEL_SYNC_EXECUTION);
|
||||
});
|
||||
|
||||
App::get('/v1/functions/:functionId/executions')
|
||||
|
@ -1115,9 +1082,7 @@ App::get('/v1/builds/:buildId')
|
|||
/** @var Appwrite\Utopia\Response $response */
|
||||
/** @var Utopia\Database\Database $dbForProject */
|
||||
|
||||
$build = Authorization::skip(function () use ($dbForProject, $buildId) {
|
||||
return $dbForProject->getDocument('builds', $buildId);
|
||||
});
|
||||
$build = Authorization::skip(fn() => $dbForProject->getDocument('builds', $buildId));
|
||||
|
||||
if ($build->isEmpty()) {
|
||||
throw new Exception('Build not found', 404);
|
||||
|
@ -1125,6 +1090,7 @@ App::get('/v1/builds/:buildId')
|
|||
|
||||
$response->dynamic($build, Response::MODEL_BUILD);
|
||||
});
|
||||
|
||||
App::post('/v1/builds/:buildId')
|
||||
->groups(['api', 'functions'])
|
||||
->desc('Retry Build')
|
||||
|
@ -1145,9 +1111,7 @@ App::post('/v1/builds/:buildId')
|
|||
/** @var Utopia\Database\Database $dbForProject */
|
||||
/** @var Utopia\Database\Document $project */
|
||||
|
||||
$build = Authorization::skip(function () use ($dbForProject, $buildId) {
|
||||
return $dbForProject->getDocument('builds', $buildId);
|
||||
});
|
||||
$build = Authorization::skip(fn() => $dbForProject->getDocument('builds', $buildId));
|
||||
|
||||
if ($build->isEmpty()) {
|
||||
throw new Exception('Build not found', 404);
|
||||
|
@ -1157,34 +1121,12 @@ App::post('/v1/builds/:buildId')
|
|||
throw new Exception('Build not failed', 400);
|
||||
}
|
||||
|
||||
// Retry build
|
||||
$ch = \curl_init();
|
||||
\curl_setopt($ch, CURLOPT_URL, "http://appwrite-executor/v1/build/{$buildId}");
|
||||
\curl_setopt($ch, CURLOPT_POST, true);
|
||||
\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', '')
|
||||
// Enqueue a message to start the build
|
||||
Resque::enqueue(Event::BUILDS_QUEUE_NAME, Event::BUILDS_CLASS_NAME, [
|
||||
'projectId' => $project->getId(),
|
||||
'buildId' => $buildId,
|
||||
'type' => BUILD_TYPE_RETRY
|
||||
]);
|
||||
|
||||
$executorResponse = \curl_exec($ch);
|
||||
|
||||
$error = \curl_error($ch);
|
||||
|
||||
if (!empty($error)) {
|
||||
throw new Exception('Executor Communication 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);
|
||||
|
||||
$response->noContent();
|
||||
});
|
271
app/executor.php
271
app/executor.php
|
@ -300,7 +300,7 @@ function createRuntimeServer(string $functionId, string $projectId, string $depl
|
|||
}
|
||||
|
||||
// Add to network
|
||||
$orchestration->networkConnect($container, 'appwrite_runtimes');
|
||||
$orchestration->networkConnect($container, App::getEnv('_APP_EXECUTOR_RUNTIME_NETWORK', 'appwrite_runtimes'));
|
||||
|
||||
$executionEnd = \microtime(true);
|
||||
|
||||
|
@ -311,12 +311,13 @@ function createRuntimeServer(string $functionId, string $projectId, string $depl
|
|||
'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');
|
||||
Console::success('Runtime server is ready to run');
|
||||
}
|
||||
} catch (\Throwable $th) {
|
||||
$orchestrationPool->put($orchestration);
|
||||
Console::error($th->getMessage());
|
||||
$orchestrationPool->put($orchestration ?? null);
|
||||
throw $th;
|
||||
}
|
||||
$orchestrationPool->put($orchestration);
|
||||
|
@ -434,7 +435,7 @@ function execute(string $trigger, string $projectId, string $executionId, string
|
|||
|
||||
$database->updateDocument('deployments', $deployment->getId(), $deployment);
|
||||
|
||||
runBuildStage($buildId, $projectId);
|
||||
runBuildStage($buildId, $deployment->getId(), $projectId);
|
||||
}
|
||||
} catch (Exception $e) {
|
||||
$execution
|
||||
|
@ -599,7 +600,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('deploymentId', $deployment->getId())
|
||||
->setAttribute('status', $functionStatus)
|
||||
|
@ -657,7 +658,7 @@ function execute(string $trigger, string $projectId, string $executionId, string
|
|||
];
|
||||
};
|
||||
|
||||
function runBuildStage(string $buildId, string $projectID): Document
|
||||
function runBuildStage(string $buildId, string $deploymentId, string $projectID): Document
|
||||
{
|
||||
global $runtimes;
|
||||
global $orchestrationPool;
|
||||
|
@ -679,6 +680,7 @@ function runBuildStage(string $buildId, string $projectID): Document
|
|||
|
||||
// Check if build has already been run
|
||||
$build = $database->getDocument('builds', $buildId);
|
||||
$deployment = $database->getDocument('deployments', $deploymentId);
|
||||
|
||||
try {
|
||||
// If we already have a built package ready there is no need to rebuild.
|
||||
|
@ -686,10 +688,11 @@ function runBuildStage(string $buildId, string $projectID): Document
|
|||
return $build;
|
||||
}
|
||||
|
||||
// Update Tag Status
|
||||
// Update deployment Status
|
||||
$build->setAttribute('status', 'building');
|
||||
|
||||
$database->updateDocument('builds', $build->getId(), $build);
|
||||
$deployment->setAttribute('status', 'building');
|
||||
$database->updateDocument('builds', $buildId, $build);
|
||||
$database->updateDocument('deployments', $deploymentId, $deployment);
|
||||
|
||||
// Check if runtime is active
|
||||
$runtime = $runtimes[$build->getAttribute('runtime', '')] ?? null;
|
||||
|
@ -698,16 +701,14 @@ function runBuildStage(string $buildId, string $projectID): Document
|
|||
throw new Exception('Runtime "' . $build->getAttribute('runtime', '') . '" is not supported');
|
||||
}
|
||||
|
||||
// Grab Tag Files
|
||||
// Grab Deployment Files
|
||||
$deploymentPath = $build->getAttribute('source', '');
|
||||
$sourceType = $build->getAttribute('sourceType', '');
|
||||
|
||||
$device = Storage::getDevice('builds');
|
||||
|
||||
$deploymentPathTarget = '/tmp/project-' . $projectID . '/' . $build->getId() . '/code.tar.gz';
|
||||
$deploymentPathTarget = '/tmp/project-' . $projectID . '/' . $buildId . '/code.tar.gz';
|
||||
$deploymentPathTargetDir = \pathinfo($deploymentPathTarget, PATHINFO_DIRNAME);
|
||||
|
||||
$container = 'build-stage-' . $build->getId();
|
||||
$container = 'build-stage-' . $buildId;
|
||||
|
||||
// Perform various checks
|
||||
if (!\file_exists($deploymentPathTargetDir)) {
|
||||
|
@ -745,13 +746,13 @@ function runBuildStage(string $buildId, string $projectID): Document
|
|||
->setSwap(App::getEnv('_APP_FUNCTIONS_MEMORY_SWAP', 256));
|
||||
|
||||
$vars = array_map(fn ($v) => strval($v), $vars);
|
||||
$path = '/tmp/project-' . $projectID . '/' . $build->getId() . '/builtCode';
|
||||
$path = '/tmp/project-' . $projectID . '/' . $buildId . '/builtCode';
|
||||
|
||||
if (!\file_exists($path)) {
|
||||
if (@\mkdir($path, 0777, true)) {
|
||||
\chmod($path, 0777);
|
||||
} else {
|
||||
throw new Exception('Can\'t create directory /tmp/project-' . $projectID . '/' . $build->getId() . '/builtCode');
|
||||
throw new Exception('Can\'t create directory /tmp/project-' . $projectID . '/' . $buildId . '/builtCode');
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -766,7 +767,7 @@ function runBuildStage(string $buildId, string $projectID): Document
|
|||
'appwrite-created' => strval($time),
|
||||
'appwrite-runtime' => $build->getAttribute('runtime', ''),
|
||||
'appwrite-project' => $projectID,
|
||||
'appwrite-build' => $build->getId(),
|
||||
'appwrite-build' => $buildId,
|
||||
],
|
||||
command: [
|
||||
'tail',
|
||||
|
@ -776,7 +777,7 @@ function runBuildStage(string $buildId, string $projectID): Document
|
|||
hostname: $container,
|
||||
mountFolder: $deploymentPathTargetDir,
|
||||
volumes: [
|
||||
'/tmp/project-' . $projectID . '/' . $build->getId() . '/builtCode' . ':/usr/builtCode:rw'
|
||||
'/tmp/project-' . $projectID . '/' . $buildId . '/builtCode' . ':/usr/builtCode:rw'
|
||||
]
|
||||
);
|
||||
|
||||
|
@ -882,6 +883,9 @@ function runBuildStage(string $buildId, string $projectID): Document
|
|||
// Update build with built code attribute
|
||||
$build = $database->updateDocument('builds', $buildId, $build);
|
||||
|
||||
$deployment->setAttribute('status', 'ready');
|
||||
$database->updateDocument('deployments', $deploymentId, $deployment);
|
||||
|
||||
$buildEnd = \microtime(true);
|
||||
|
||||
Console::info('Build Stage Ran in ' . ($buildEnd - $buildStart) . ' seconds');
|
||||
|
@ -893,6 +897,9 @@ function runBuildStage(string $buildId, string $projectID): Document
|
|||
|
||||
$build = $database->updateDocument('builds', $buildId, $build);
|
||||
|
||||
$deployment->setAttribute('status', 'failed');
|
||||
$database->updateDocument('deployments', $deploymentId, $deployment);
|
||||
|
||||
// also remove the container if it exists
|
||||
if (isset($id)) {
|
||||
$orchestration->remove($id, true);
|
||||
|
@ -912,7 +919,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), 'What triggered this execution, can be http / schedule / event')
|
||||
->param('projectId', '', new Text(1024), 'The ProjectID this execution belongs to')
|
||||
|
@ -930,15 +937,15 @@ 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) {
|
||||
$data = execute($trigger, $projectId, $executionId, $functionId, $dbForProject, $event, $eventData, $data, $webhooks, $userId, $jwt);
|
||||
|
||||
return $response
|
||||
$response
|
||||
->setStatusCode(Response::STATUS_CODE_OK)
|
||||
->json($data);
|
||||
}
|
||||
);
|
||||
|
||||
// Cleanup Endpoints used internally by appwrite when a function or deployment gets deleted to also clean up their containers
|
||||
App::post('/v1/cleanup/function')
|
||||
->param('functionId', '', new UID(), 'The FunctionID to cleanup')
|
||||
App::delete('/v1/functions/:functionId')
|
||||
->desc('Delete a function')
|
||||
->param('functionId', '', new UID(), 'The FunctionID to delete')
|
||||
->inject('response')
|
||||
->inject('dbForProject')
|
||||
->action(
|
||||
|
@ -992,7 +999,40 @@ App::post('/v1/cleanup/function')
|
|||
}
|
||||
);
|
||||
|
||||
App::post('/v1/cleanup/deployment')
|
||||
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.')
|
||||
->inject('response')
|
||||
->inject('dbForProject')
|
||||
|
@ -1033,160 +1073,81 @@ App::post('/v1/cleanup/deployment')
|
|||
->json(['success' => true]);
|
||||
});
|
||||
|
||||
App::post('/v1/deployment')
|
||||
->param('functionId', '', new UID(), 'Function unique ID.')
|
||||
->param('deploymentId', '', new UID(), 'Deployment unique ID.')
|
||||
->param('userId', '', new UID(), 'User unique ID.', true)
|
||||
App::post('/v1/functions/:functionId/deployments/:deploymentId/builds/:buildId')
|
||||
->desc("Create a new build")
|
||||
->param('functionId', '', new UID(), 'Function unique ID.', false)
|
||||
->param('deploymentId', '', new UID(), 'Deployment unique ID.', false)
|
||||
->param('buildId', '', new UID(), 'Build unique ID.', false)
|
||||
->inject('response')
|
||||
->inject('dbForProject')
|
||||
->inject('projectID')
|
||||
->inject('register')
|
||||
->action(function (string $functionId, string $deploymentId, string $userId, Response $response, Database $dbForProject, string $projectID, Registry $register) use ($runtimes) {
|
||||
// Get function document
|
||||
->inject('projectId')
|
||||
->action(function (string $functionId, string $deploymentId, string $buildId, Response $response, Database $dbForProject, string $projectId) {
|
||||
|
||||
$function = $dbForProject->getDocument('functions', $functionId);
|
||||
// Get deployment document
|
||||
$deployment = $dbForProject->getDocument('deployments', $deploymentId);
|
||||
|
||||
// Check if both documents exist
|
||||
if ($function->isEmpty()) {
|
||||
throw new Exception('Function not found', 404);
|
||||
}
|
||||
|
||||
$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', '') . '" is not supported', 404);
|
||||
}
|
||||
|
||||
// Create a new build entry
|
||||
$buildId = $dbForProject->getId();
|
||||
|
||||
if ($deployment->getAttribute('buildId')) {
|
||||
$buildId = $deployment->getAttribute('buildId');
|
||||
} else {
|
||||
$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' => $deployment->getAttribute('path'),
|
||||
'sourceType' => Storage::DEVICE_LOCAL,
|
||||
'stdout' => '',
|
||||
'stderr' => '',
|
||||
'time' => 0,
|
||||
'vars' => [
|
||||
'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,
|
||||
]
|
||||
]));
|
||||
|
||||
$deployment->setAttribute('buildId', $buildId);
|
||||
|
||||
$dbForProject->updateDocument('deployments', $deployment->getId(), $deployment);
|
||||
}
|
||||
|
||||
// Build Code
|
||||
go(function () use ($projectID, $deploymentId, $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('deployment')) && !empty($schedule)) ? new CronExpression($schedule) : null;
|
||||
$next = (empty($function->getAttribute('deployment')) && !empty($schedule)) ? $cron->getNextRunDate()->format('U') : 0;
|
||||
|
||||
// Grab deployment
|
||||
$deployment = $dbForProject->getDocument('deployments', $deploymentId);
|
||||
|
||||
// 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 ($deployment->getAttribute('automaticDeploy') === true) {
|
||||
// Update the function document setting the deployment as the active one
|
||||
$function
|
||||
->setAttribute('deployment', $deployment->getId())
|
||||
->setAttribute('scheduleNext', (int)$next);
|
||||
$function = $dbForProject->updateDocument('functions', $function->getId(), $function);
|
||||
}
|
||||
|
||||
// Deploy Runtime Server
|
||||
createRuntimeServer($functionId, $projectID, $deploymentId, $dbForProject);
|
||||
} catch (\Throwable $th) {
|
||||
$register->get('dbPool')->put($db);
|
||||
$register->get('redisPool')->put($redis);
|
||||
throw $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
|
||||
->param('buildId', '', new UID(), 'Build unique ID.', false)
|
||||
->inject('response')
|
||||
->inject('dbForProject')
|
||||
->inject('projectID')
|
||||
->action(function (string $buildId, Response $response, Database $dbForProject, string $projectID) {
|
||||
// Get build document
|
||||
$build = $dbForProject->getDocument('builds', $buildId);
|
||||
|
||||
// Check if build exists
|
||||
if ($build->isEmpty()) {
|
||||
throw new Exception('Build not found', 404);
|
||||
}
|
||||
|
||||
// Check if build is already running
|
||||
if ($build->getAttribute('status') === 'running') {
|
||||
if ($build->getAttribute('status') === 'building') {
|
||||
throw new Exception('Build is already running', 409);
|
||||
}
|
||||
|
||||
// Check if build is already finished
|
||||
if ($build->getAttribute('status') === 'finished') {
|
||||
if ($build->getAttribute('status') === 'ready') {
|
||||
throw new Exception('Build is already finished', 409);
|
||||
}
|
||||
|
||||
go(function () use ($buildId, $dbForProject, $projectID) {
|
||||
// Build Code
|
||||
runBuildStage($buildId, $projectID, $dbForProject);
|
||||
go(function() use ($functionId, $deploymentId, $buildId, $projectId, $dbForProject, $function, $deployment) {
|
||||
Console::info('Starting build for deployment ' . $deployment['$id']);
|
||||
runBuildStage($buildId, $deploymentId, $projectId);
|
||||
|
||||
// Update the schedule
|
||||
$schedule = $function->getAttribute('schedule', '');
|
||||
$cron = (empty($function->getAttribute('deployment')) && !empty($schedule)) ? new CronExpression($schedule) : null;
|
||||
$next = (empty($function->getAttribute('deployment')) && !empty($schedule)) ? $cron->getNextRunDate()->format('U') : 0;
|
||||
|
||||
// Grab build
|
||||
$build = $dbForProject->getDocument('builds', $buildId);
|
||||
|
||||
// If the build failed, it won't be possible to deploy
|
||||
if ($build->getAttribute('status') !== 'ready') {
|
||||
throw new Exception('Build failed', 500);
|
||||
}
|
||||
|
||||
if ($deployment->getAttribute('deploy') === true) {
|
||||
// Update the function document setting the deployment as the active one
|
||||
$function
|
||||
->setAttribute('deployment', $deployment->getId())
|
||||
->setAttribute('scheduleNext', (int)$next);
|
||||
|
||||
$function = $dbForProject->updateDocument('functions', $functionId, $function);
|
||||
}
|
||||
|
||||
// Deploy Runtime Server
|
||||
try {
|
||||
Console::info("[ INFO ] Creating runtime server");
|
||||
createRuntimeServer($functionId, $projectId, $deploymentId, $dbForProject);
|
||||
} catch (\Throwable $th) {
|
||||
Console::error($th->getMessage());
|
||||
$deployment->setAttribute('status', 'failed');
|
||||
$deployment = $dbForProject->updateDocument('deployments', $deploymentId, $deployment);
|
||||
throw $th;
|
||||
}
|
||||
});
|
||||
|
||||
// return success
|
||||
return $response
|
||||
->setStatusCode(Response::STATUS_CODE_OK)
|
||||
->json(['success' => true]);
|
||||
$response
|
||||
->setStatusCode(Response::STATUS_CODE_CREATED)
|
||||
->send();
|
||||
});
|
||||
|
||||
App::setMode(App::MODE_TYPE_PRODUCTION); // Define Mode
|
||||
|
@ -1351,7 +1312,7 @@ $http->on('request', function (SwooleRequest $swooleRequest, SwooleResponse $swo
|
|||
);
|
||||
}, ['error', 'utopia', 'request', 'response']);
|
||||
|
||||
App::setResource('projectID', function () use ($projectId) {
|
||||
App::setResource('projectId', function () use ($projectId) {
|
||||
return $projectId;
|
||||
});
|
||||
|
||||
|
|
|
@ -92,6 +92,9 @@ const DATABASE_TYPE_CREATE_ATTRIBUTE = 'createAttribute';
|
|||
const DATABASE_TYPE_CREATE_INDEX = 'createIndex';
|
||||
const DATABASE_TYPE_DELETE_ATTRIBUTE = 'deleteAttribute';
|
||||
const DATABASE_TYPE_DELETE_INDEX = 'deleteIndex';
|
||||
// Build Worker Types
|
||||
const BUILD_TYPE_DEPLOYMENT = 'deployment';
|
||||
const BUILD_TYPE_RETRY = 'retry';
|
||||
// Deletion Types
|
||||
const DELETE_TYPE_DOCUMENT = 'document';
|
||||
const DELETE_TYPE_COLLECTIONS = 'collections';
|
||||
|
|
|
@ -191,6 +191,7 @@ services:
|
|||
- _APP_FUNCTIONS_MEMORY
|
||||
- _APP_FUNCTIONS_MEMORY_SWAP
|
||||
- _APP_EXECUTOR_SECRET
|
||||
- _APP_EXECUTOR_RUNTIME_NETWORK
|
||||
- _APP_USAGE_STATS
|
||||
- _APP_STATSD_HOST
|
||||
- _APP_STATSD_PORT
|
||||
|
@ -221,6 +222,31 @@ services:
|
|||
- _APP_DB_USER
|
||||
- _APP_DB_PASS
|
||||
|
||||
appwrite-worker-builds:
|
||||
image: <?php echo $organization; ?>/<?php echo $image; ?>:<?php echo $version."\n"; ?>
|
||||
entrypoint: worker-builds
|
||||
container_name: appwrite-worker-builds
|
||||
restart: unless-stopped
|
||||
networks:
|
||||
- appwrite
|
||||
depends_on:
|
||||
- redis
|
||||
- mariadb
|
||||
environment:
|
||||
- _APP_ENV
|
||||
- _APP_REDIS_HOST
|
||||
- _APP_REDIS_PORT
|
||||
- _APP_REDIS_USER
|
||||
- _APP_REDIS_PASS
|
||||
- _APP_DB_HOST
|
||||
- _APP_DB_PORT
|
||||
- _APP_DB_SCHEMA
|
||||
- _APP_DB_USER
|
||||
- _APP_DB_PASS
|
||||
- _APP_LOGGING_PROVIDER
|
||||
- _APP_LOGGING_CONFIG
|
||||
- _APP_EXECUTOR_SECRET
|
||||
|
||||
appwrite-worker-audits:
|
||||
image: <?php echo $organization; ?>/<?php echo $image; ?>:<?php echo $version."\n"; ?>
|
||||
entrypoint: worker-audits
|
||||
|
|
164
app/workers/builds.php
Normal file
164
app/workers/builds.php
Normal file
|
@ -0,0 +1,164 @@
|
|||
<?php
|
||||
|
||||
use Appwrite\Resque\Worker;
|
||||
use Cron\CronExpression;
|
||||
use Utopia\Database\Validator\Authorization;
|
||||
use Utopia\App;
|
||||
use Utopia\CLI\Console;
|
||||
use Utopia\Storage\Storage;
|
||||
use Utopia\Database\Document;
|
||||
use Utopia\Config\Config;
|
||||
|
||||
require_once __DIR__.'/../init.php';
|
||||
|
||||
// Disable Auth since we already validate it in the API
|
||||
Authorization::disable();
|
||||
|
||||
Console::title('Builds V1 Worker');
|
||||
Console::success(APP_NAME.' build worker v1 has started');
|
||||
|
||||
// TODO: Executor should return appropriate response codes.
|
||||
class BuildsV1 extends Worker
|
||||
{
|
||||
|
||||
public function getName(): string
|
||||
{
|
||||
return "builds";
|
||||
}
|
||||
|
||||
public function init(): void {}
|
||||
|
||||
public function run(): void
|
||||
{
|
||||
$type = $this->args['type'] ?? '';
|
||||
$projectId = $this->args['projectId'] ?? '';
|
||||
|
||||
switch ($type) {
|
||||
case BUILD_TYPE_DEPLOYMENT:
|
||||
$functionId = $this->args['functionId'] ?? '';
|
||||
$deploymentId = $this->args['deploymentId'] ?? '';
|
||||
Console::info("[ INFO ] Creating build for deployment: $deploymentId");
|
||||
$this->buildDeployment($projectId, $functionId, $deploymentId);
|
||||
break;
|
||||
|
||||
case BUILD_TYPE_RETRY:
|
||||
$buildId = $this->args['buildId'] ?? '';
|
||||
$functionId = $this->args['functionId'] ?? '';
|
||||
$deploymentId = $this->args['deploymentId'] ?? '';
|
||||
Console::info("[ INFO ] Retrying build for id: $buildId");
|
||||
$this->createBuild($projectId, $functionId, $deploymentId, $buildId);
|
||||
break;
|
||||
|
||||
default:
|
||||
throw new \Exception('Invalid build type');
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
protected function createBuild(string $projectId, string $functionId, string $deploymentId, string $buildId)
|
||||
{
|
||||
// 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/functions/$functionId/deployments/$deploymentId/builds/$buildId");
|
||||
\curl_setopt($ch, CURLOPT_POST, true);
|
||||
\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: '.$projectId,
|
||||
'x-appwrite-executor-key: '. App::getEnv('_APP_EXECUTOR_SECRET', '')
|
||||
]);
|
||||
|
||||
$response = \curl_exec($ch);
|
||||
$responseStatus = curl_getinfo($ch, CURLINFO_HTTP_CODE);
|
||||
|
||||
$error = \curl_error($ch);
|
||||
if (!empty($error)) {
|
||||
throw new \Exception($error);
|
||||
}
|
||||
|
||||
\curl_close($ch);
|
||||
|
||||
if ($responseStatus >= 400) {
|
||||
throw new \Exception("Build failed with status code: $responseStatus");
|
||||
}
|
||||
}
|
||||
|
||||
protected function buildDeployment(string $projectId, string $functionId, string $deploymentId)
|
||||
{
|
||||
$dbForProject = $this->getProjectDB($projectId);
|
||||
|
||||
$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);
|
||||
}
|
||||
|
||||
$runtimes = Config::getParam('runtimes', []);
|
||||
$key = $function->getAttribute('runtime');
|
||||
$runtime = isset($runtimes[$key]) ? $runtimes[$key] : null;
|
||||
if (\is_null($runtime)) {
|
||||
throw new Exception('Runtime "' . $function->getAttribute('runtime', '') . '" is not supported');
|
||||
}
|
||||
|
||||
$buildId = $deployment->getAttribute('buildId', '');
|
||||
|
||||
// If build ID is empty, create a new build
|
||||
if (empty($buildId)) {
|
||||
try {
|
||||
$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([
|
||||
'$id' => $buildId,
|
||||
'$read' => [],
|
||||
'$write' => [],
|
||||
'dateCreated' => time(),
|
||||
'status' => 'processing',
|
||||
'runtime' => $function->getAttribute('runtime'),
|
||||
'outputPath' => '',
|
||||
'source' => $deployment->getAttribute('path'),
|
||||
'sourceType' => Storage::DEVICE_LOCAL,
|
||||
'stdout' => '',
|
||||
'stderr' => '',
|
||||
'time' => 0,
|
||||
'vars' => [
|
||||
'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) {
|
||||
$deployment->setAttribute('status', 'failed');
|
||||
$deployment->setAttribute('buildId', '');
|
||||
$deployment = $dbForProject->updateDocument('deployments', $deploymentId, $deployment);
|
||||
Console::error($th->getMessage());
|
||||
throw $th;
|
||||
}
|
||||
}
|
||||
|
||||
// Build the Code
|
||||
try {
|
||||
$deployment->setAttribute('buildId', $buildId);
|
||||
$deployment = $dbForProject->updateDocument('deployments', $deploymentId, $deployment);
|
||||
$this->createBuild($projectId, $functionId, $deploymentId, $buildId);
|
||||
} catch (\Throwable $th) {
|
||||
$deployment->setAttribute('status', 'failed');
|
||||
$deployment = $dbForProject->updateDocument('deployments', $deploymentId, $deployment);
|
||||
Console::error($th->getMessage());
|
||||
throw $th;
|
||||
}
|
||||
|
||||
Console::success("[ SUCCESS ] Build id: $buildId started");
|
||||
}
|
||||
|
||||
public function shutdown(): void {}
|
||||
}
|
|
@ -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,
|
||||
|
|
10
bin/worker-builds
Normal file
10
bin/worker-builds
Normal file
|
@ -0,0 +1,10 @@
|
|||
#!/bin/sh
|
||||
|
||||
if [ -z "$_APP_REDIS_USER" ] && [ -z "$_APP_REDIS_PASS" ]
|
||||
then
|
||||
REDIS_BACKEND="${_APP_REDIS_HOST}:${_APP_REDIS_PORT}"
|
||||
else
|
||||
REDIS_BACKEND="redis://${_APP_REDIS_USER}:${_APP_REDIS_PASS}@${_APP_REDIS_HOST}:${_APP_REDIS_PORT}"
|
||||
fi
|
||||
|
||||
INTERVAL=0.1 QUEUE='v1-builds' APP_INCLUDE='/usr/src/code/app/workers/builds.php' php /usr/src/code/vendor/bin/resque -dopcache.preload=opcache.preload=/usr/src/code/app/preload.php
|
|
@ -50,7 +50,7 @@
|
|||
"utopia-php/cache": "0.4.*",
|
||||
"utopia-php/cli": "0.11.*",
|
||||
"utopia-php/config": "0.2.*",
|
||||
"utopia-php/database": "0.13.*",
|
||||
"utopia-php/database": "0.14.*",
|
||||
"utopia-php/locale": "0.4.*",
|
||||
"utopia-php/registry": "0.5.*",
|
||||
"utopia-php/preloader": "0.2.*",
|
||||
|
|
33
composer.lock
generated
33
composer.lock
generated
|
@ -4,7 +4,7 @@
|
|||
"Read more about it at https://getcomposer.org/doc/01-basic-usage.md#installing-dependencies",
|
||||
"This file is @generated automatically"
|
||||
],
|
||||
"content-hash": "cba39f50398d5ae2b121db34c9e4c529",
|
||||
"content-hash": "1a5d84f96eb76e59f7ad0ff7bcd4a8d8",
|
||||
"packages": [
|
||||
{
|
||||
"name": "adhocore/jwt",
|
||||
|
@ -2135,16 +2135,16 @@
|
|||
},
|
||||
{
|
||||
"name": "utopia-php/database",
|
||||
"version": "0.13.2",
|
||||
"version": "0.14.0",
|
||||
"source": {
|
||||
"type": "git",
|
||||
"url": "https://github.com/utopia-php/database.git",
|
||||
"reference": "bf92279b707b3a10ee5ec5df5c065023b2221357"
|
||||
"reference": "2f2527bb080cf578fba327ea2ec637064561d403"
|
||||
},
|
||||
"dist": {
|
||||
"type": "zip",
|
||||
"url": "https://api.github.com/repos/utopia-php/database/zipball/bf92279b707b3a10ee5ec5df5c065023b2221357",
|
||||
"reference": "bf92279b707b3a10ee5ec5df5c065023b2221357",
|
||||
"url": "https://api.github.com/repos/utopia-php/database/zipball/2f2527bb080cf578fba327ea2ec637064561d403",
|
||||
"reference": "2f2527bb080cf578fba327ea2ec637064561d403",
|
||||
"shasum": ""
|
||||
},
|
||||
"require": {
|
||||
|
@ -2192,9 +2192,9 @@
|
|||
],
|
||||
"support": {
|
||||
"issues": "https://github.com/utopia-php/database/issues",
|
||||
"source": "https://github.com/utopia-php/database/tree/0.13.2"
|
||||
"source": "https://github.com/utopia-php/database/tree/0.14.0"
|
||||
},
|
||||
"time": "2022-01-04T10:51:22+00:00"
|
||||
"time": "2022-01-21T16:34:34+00:00"
|
||||
},
|
||||
{
|
||||
"name": "utopia-php/domains",
|
||||
|
@ -3126,23 +3126,23 @@
|
|||
},
|
||||
{
|
||||
"name": "composer/pcre",
|
||||
"version": "1.0.0",
|
||||
"version": "1.0.1",
|
||||
"source": {
|
||||
"type": "git",
|
||||
"url": "https://github.com/composer/pcre.git",
|
||||
"reference": "3d322d715c43a1ac36c7fe215fa59336265500f2"
|
||||
"reference": "67a32d7d6f9f560b726ab25a061b38ff3a80c560"
|
||||
},
|
||||
"dist": {
|
||||
"type": "zip",
|
||||
"url": "https://api.github.com/repos/composer/pcre/zipball/3d322d715c43a1ac36c7fe215fa59336265500f2",
|
||||
"reference": "3d322d715c43a1ac36c7fe215fa59336265500f2",
|
||||
"url": "https://api.github.com/repos/composer/pcre/zipball/67a32d7d6f9f560b726ab25a061b38ff3a80c560",
|
||||
"reference": "67a32d7d6f9f560b726ab25a061b38ff3a80c560",
|
||||
"shasum": ""
|
||||
},
|
||||
"require": {
|
||||
"php": "^5.3.2 || ^7.0 || ^8.0"
|
||||
},
|
||||
"require-dev": {
|
||||
"phpstan/phpstan": "^1",
|
||||
"phpstan/phpstan": "^1.3",
|
||||
"phpstan/phpstan-strict-rules": "^1.1",
|
||||
"symfony/phpunit-bridge": "^4.2 || ^5"
|
||||
},
|
||||
|
@ -3177,7 +3177,7 @@
|
|||
],
|
||||
"support": {
|
||||
"issues": "https://github.com/composer/pcre/issues",
|
||||
"source": "https://github.com/composer/pcre/tree/1.0.0"
|
||||
"source": "https://github.com/composer/pcre/tree/1.0.1"
|
||||
},
|
||||
"funding": [
|
||||
{
|
||||
|
@ -3193,7 +3193,7 @@
|
|||
"type": "tidelift"
|
||||
}
|
||||
],
|
||||
"time": "2021-12-06T15:17:27+00:00"
|
||||
"time": "2022-01-21T20:24:37+00:00"
|
||||
},
|
||||
{
|
||||
"name": "composer/semver",
|
||||
|
@ -3697,9 +3697,6 @@
|
|||
"require": {
|
||||
"php": "^7.1 || ^8.0"
|
||||
},
|
||||
"replace": {
|
||||
"myclabs/deep-copy": "self.version"
|
||||
},
|
||||
"require-dev": {
|
||||
"doctrine/collections": "^1.0",
|
||||
"doctrine/common": "^2.6",
|
||||
|
@ -6665,5 +6662,5 @@
|
|||
"platform-overrides": {
|
||||
"php": "8.0"
|
||||
},
|
||||
"plugin-api-version": "2.1.0"
|
||||
"plugin-api-version": "2.2.0"
|
||||
}
|
||||
|
|
|
@ -285,6 +285,34 @@ services:
|
|||
- _APP_DB_PASS
|
||||
- _APP_LOGGING_PROVIDER
|
||||
- _APP_LOGGING_CONFIG
|
||||
|
||||
appwrite-worker-builds:
|
||||
entrypoint: worker-builds
|
||||
container_name: appwrite-worker-builds
|
||||
build:
|
||||
context: .
|
||||
networks:
|
||||
- appwrite
|
||||
volumes:
|
||||
- ./app:/usr/src/code/app
|
||||
- ./src:/usr/src/code/src
|
||||
depends_on:
|
||||
- redis
|
||||
- mariadb
|
||||
environment:
|
||||
- _APP_ENV
|
||||
- _APP_REDIS_HOST
|
||||
- _APP_REDIS_PORT
|
||||
- _APP_REDIS_USER
|
||||
- _APP_REDIS_PASS
|
||||
- _APP_DB_HOST
|
||||
- _APP_DB_PORT
|
||||
- _APP_DB_SCHEMA
|
||||
- _APP_DB_USER
|
||||
- _APP_DB_PASS
|
||||
- _APP_LOGGING_PROVIDER
|
||||
- _APP_LOGGING_CONFIG
|
||||
- _APP_EXECUTOR_SECRET
|
||||
|
||||
appwrite-worker-certificates:
|
||||
entrypoint: worker-certificates
|
||||
|
@ -350,7 +378,11 @@ services:
|
|||
|
||||
appwrite-executor:
|
||||
container_name: appwrite-executor
|
||||
entrypoint: executor
|
||||
entrypoint:
|
||||
- php
|
||||
- -e
|
||||
- /usr/src/code/app/executor.php
|
||||
- -dopcache.preload=opcache.preload=/usr/src/code/app/preload.php
|
||||
stop_signal: SIGINT
|
||||
build:
|
||||
context: .
|
||||
|
@ -391,6 +423,7 @@ services:
|
|||
- _APP_FUNCTIONS_MEMORY
|
||||
- _APP_FUNCTIONS_MEMORY_SWAP
|
||||
- _APP_EXECUTOR_SECRET
|
||||
- _APP_EXECUTOR_RUNTIME_NETWORK
|
||||
- _APP_USAGE_STATS
|
||||
- _APP_STATSD_HOST
|
||||
- _APP_STATSD_PORT
|
||||
|
|
|
@ -30,6 +30,9 @@ class Event
|
|||
|
||||
const CERTIFICATES_QUEUE_NAME = 'v1-certificates';
|
||||
const CERTIFICATES_CLASS_NAME = 'CertificatesV1';
|
||||
|
||||
const BUILDS_QUEUE_NAME = 'v1-builds';
|
||||
const BUILDS_CLASS_NAME = 'BuildsV1';
|
||||
|
||||
/**
|
||||
* @var string
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -242,7 +242,7 @@ class FunctionsCustomClientTest extends Scope
|
|||
'content-type' => 'application/json',
|
||||
'x-appwrite-project' => $this->getProject()['$id'],
|
||||
], [
|
||||
'async' => 1,
|
||||
'async' => true,
|
||||
]);
|
||||
|
||||
$this->assertEquals(401, $execution['headers']['status-code']);
|
||||
|
|
|
@ -266,6 +266,34 @@ services:
|
|||
- _APP_REDIS_PORT
|
||||
- _APP_SMTP_HOST
|
||||
- _APP_SMTP_PORT
|
||||
|
||||
appwrite-worker-builds:
|
||||
entrypoint: worker-builds
|
||||
container_name: appwrite-worker-builds
|
||||
build:
|
||||
context: .
|
||||
networks:
|
||||
- appwrite
|
||||
volumes:
|
||||
- ./app:/usr/src/code/app
|
||||
- ./src:/usr/src/code/src
|
||||
depends_on:
|
||||
- redis
|
||||
- mariadb
|
||||
environment:
|
||||
- _APP_ENV
|
||||
- _APP_REDIS_HOST
|
||||
- _APP_REDIS_PORT
|
||||
- _APP_REDIS_USER
|
||||
- _APP_REDIS_PASS
|
||||
- _APP_DB_HOST
|
||||
- _APP_DB_PORT
|
||||
- _APP_DB_SCHEMA
|
||||
- _APP_DB_USER
|
||||
- _APP_DB_PASS
|
||||
- _APP_LOGGING_PROVIDER
|
||||
- _APP_LOGGING_CONFIG
|
||||
- _APP_EXECUTOR_SECRET
|
||||
|
||||
appwrite-schedule:
|
||||
entrypoint: schedule
|
||||
|
|
Loading…
Reference in a new issue