1
0
Fork 0
mirror of synced 2024-05-20 12:42:39 +12:00

Worker now run real functions

This commit is contained in:
Eldad Fux 2020-07-16 15:04:06 +03:00
parent 58cbc4ce3a
commit 2af2484afa
4 changed files with 80 additions and 23 deletions

View file

@ -403,7 +403,7 @@ App::post('/v1/functions/:functionId/executions')
->label('sdk.description', '/docs/references/functions/create-execution.md')
->param('functionId', '', function () { return new UID(); }, 'Function unique ID.')
->param('async', 1, function () { return new Range(0, 1); }, 'Execute code asynchronously. Pass 1 for true, 0 for false. Default value is 1.', true)
->action(function ($functionId, $async, $response, $projectDB) {
->action(function ($functionId, $async, $response, $project, $projectDB) {
$function = $projectDB->getDocument($functionId);
if (empty($function->getId()) || Database::SYSTEM_COLLECTION_FUNCTIONS != $function->getCollection()) {
@ -442,10 +442,9 @@ App::post('/v1/functions/:functionId/executions')
if((bool)$async) {
// Issue a TLS certificate when domain is verified
Resque::enqueue('v1-functions', 'FunctionsV1', [
'projectId' => $project->getId(),
'functionId' => $function->getId(),
'functionTag' => $tag->getId(),
'functionEnv' => $function->getAttribute('env', ''),
'functionCommand' => $tag->getAttribute('command', ''),
]);
}
@ -453,7 +452,7 @@ App::post('/v1/functions/:functionId/executions')
->setStatusCode(Response::STATUS_CODE_CREATED)
->json($execution->getArrayCopy())
;
}, ['response', 'projectDB']);
}, ['response', 'project', 'projectDB']);
App::get('/v1/functions/:functionId/executions')
->groups(['api', 'functions'])

View file

@ -7,7 +7,7 @@ $events = array_keys($this->getParam('events', []));
<div
data-service="functions.get"
data-name="project-function"
data-event="load,functions.update"
data-event="load,functions.update,functions.updateTag"
data-param-function-id="{{router.params.id}}"
data-success="trigger"
data-success-param-trigger-events="functions.get">
@ -73,9 +73,10 @@ $events = array_keys($this->getParam('events', []));
<div class="margin-bottom"
data-service="functions.listTags"
data-scope="sdk"
data-event="load,functions.createTag,functions.deleteTag"
data-event="load,functions.createTag,functions.deleteTag,functions.updateTag"
data-name="project-function-tags"
data-param-function-id="{{router.params.id}}"
data-param-order-type="DESC"
data-success="trigger"
data-success-param-trigger-events="functions.listTags">
@ -89,20 +90,20 @@ $events = array_keys($this->getParam('events', []));
<div class="box margin-bottom">
<ul data-ls-loop="project-function-tags.tags" data-ls-as="tag" class="list">
<li class="clear">
<form name="functions.updateTag" class="pull-end"
<form data-ls-if="{{tag.$id}} !== {{project-function.tag}}" name="functions.updateTag" class="pull-end"
data-analytics-event="submit"
data-analytics-category="console"
data-analytics-label="Create Function Execution"
data-service="functions.updateTag"
data-event="submit"
data-param-function-id="{{router.params.id}}"
data-param-tag="{{tag.$id}}"
data-success="alert,trigger"
data-success-param-alert-text="Tag updated successfully"
data-success-param-trigger-events="functions.updateTag"
data-failure="alert"
data-failure-param-alert-text="Failed to update tag"
data-failure-param-alert-classname="error">
<input type="hidden" name="tag" data-ls-bind="{{tag.$id}}">
<button class="margin-bottom-small">Activate</button>
</form>

View file

@ -1,5 +1,12 @@
<?php
ini_set('display_errors', 1);
ini_set('display_startup_errors', 1);
error_reporting(E_ALL);
use Appwrite\Database\Database;
use Appwrite\Database\Adapter\MySQL as MySQLAdapter;
use Appwrite\Database\Adapter\Redis as RedisAdapter;
use Appwrite\Database\Validator\Authorization;
use Utopia\CLI\Console;
use Utopia\Config\Config;
@ -49,17 +56,39 @@ class FunctionsV1
public function perform()
{
global $environments;
global $environments, $register;
$projectId = $this->args['projectId'];
$functionId = $this->args['functionId'];
$functionTag = $this->args['functionTag'];
$functionCommand = $this->args['functionCommand'];
$functionEnv = $this->args['functionEnv'];
$environment = (isset($environments[$functionEnv])) ? $environments[$functionEnv] : null;
$projectDB = new Database();
$projectDB->setAdapter(new RedisAdapter(new MySQLAdapter($register), $register));
$projectDB->setNamespace('app_'.$projectId);
$projectDB->setMocks(Config::getParam('collections', []));
Authorization::disable();
$function = $projectDB->getDocument($functionId);
Authorization::reset();
if (empty($function->getId()) || Database::SYSTEM_COLLECTION_FUNCTIONS != $function->getCollection()) {
throw new Exception('Function not found', 404);
}
Authorization::disable();
$tag = $projectDB->getDocument($functionTag);
Authorization::reset();
if($tag->getAttribute('functionId') !== $function->getId()) {
throw new Exception('Tag not found', 404);
}
$environment = (isset($environments[$function->getAttribute('env', '')]))
? $environments[$function->getAttribute('env', '')]
: null;
if(is_null($environment)) {
throw new Exception('Environment "'.$functionEnv.' is not supported');
if(\is_null($environment)) {
throw new Exception('Environment "'.$function->getAttribute('env', '').' is not supported');
}
/*
@ -75,7 +104,6 @@ class FunctionsV1
* If error count bigger than allowed change status to pause
*/
/**
* 1. Get event args
* 2. Unpackage code in the isolated container
@ -92,7 +120,7 @@ class FunctionsV1
$stderr = '';
$timeout = 15;
$start = microtime(true);
$start = \microtime(true);
//TODO aviod scheduled execution if delay is bigger than X offest
@ -104,6 +132,28 @@ class FunctionsV1
* Make sure no access to NFS server / storage volumes
* Access Appwrite REST from internal network for improved performance
*/
$tagPath = $tag->getAttribute('codePath', '');
$tagDir = \pathinfo($tag->getAttribute('codePath', ''), PATHINFO_DIRNAME);
$tagFile = \pathinfo($tag->getAttribute('codePath', ''), PATHINFO_BASENAME);
$tagPathTarget = '/tmp/project-'.$projectId.'/'.$tag->getId().'/code.tar.gz';
$tagPathTargetDir = \pathinfo($tagPathTarget, PATHINFO_DIRNAME);
if(!\is_readable($tagPath)) {
throw new Exception('Code is not readable: '.$tag->getAttribute('codePath', ''));
}
if (!\file_exists($tagPathTargetDir)) {
if (!\mkdir($tagPathTargetDir, 0755, true)) {
throw new Exception('Can\'t create directory '.$tagPathTargetDir);
}
}
if (!\file_exists($tagPathTarget)) {
if(!\copy($tagPath, $tagPathTarget)) {
throw new Exception('Can\'t create temporary code file '.$tagPathTarget);
}
}
//--storage-opt size=120m \
$exitCode = Console::execute("docker run \
@ -112,23 +162,24 @@ class FunctionsV1
--memory-swap=50m \
--rm \
--name=appwrite-function-{$functionId} \
--volume $(pwd):/app \
--workdir /app \
--volume {$tagPathTargetDir}:/tmp:rw \
--workdir /usr/local/src \
--env APPWRITE_FUNCTION_ID={$functionId} \
--env APPWRITE_FUNCTION_TAG={$functionTag} \
--env APPWRITE_FUNCTION_ENV_NAME={$environment['name']} \
--env APPWRITE_FUNCTION_ENV_VERSION={$environment['version']} \
{$environment['image']} \
{$functionCommand}", null, $stdout, $stderr, $timeout);
sh -c 'mv /tmp/code.tar.gz /usr/local/src/code.tar.gz && tar -zxf /usr/local/src/code.tar.gz --strip 1 && rm /usr/local/src/code.tar.gz && {$tag->getAttribute('command', '')}'"
, null, $stdout, $stderr, $timeout);
$end = microtime(true);
$end = \microtime(true);
var_dump('stdout', $stdout);
var_dump('stderr', $stderr);
Console::info("Code executed in " . ($end - $start) . " seconds with exit code {$exitCode}");
// Double-check Cleanup
var_dump($stdout);
var_dump($stderr);
}
public function tearDown()

View file

@ -223,11 +223,17 @@ services:
- mariadb
volumes:
- /var/run/docker.sock:/var/run/docker.sock
- /tmp:/tmp:rw
- appwrite-functions:/storage/functions:rw
environment:
- _APP_ENV
- _APP_REDIS_HOST
- _APP_REDIS_PORT
- _APP_DB_HOST
- _APP_DB_PORT
- _APP_DB_SCHEMA
- _APP_DB_USER
- _APP_DB_PASS
appwrite-worker-mails:
entrypoint: worker-mails