aaaaa
This commit is contained in:
parent
5bbbbd5a3e
commit
48d57aa38e
2
.env
2
.env
|
@ -42,4 +42,4 @@ _APP_MAINTENANCE_INTERVAL=86400
|
|||
_APP_MAINTENANCE_RETENTION_EXECUTION=1209600
|
||||
_APP_MAINTENANCE_RETENTION_ABUSE=86400
|
||||
_APP_MAINTENANCE_RETENTION_AUDIT=1209600
|
||||
_APP_USAGE_STATS=enabled
|
||||
_APP_USAGE_STATS=enabled
|
|
@ -2,6 +2,8 @@
|
|||
|
||||
use Utopia\App;
|
||||
use Appwrite\Runtimes\Runtimes;
|
||||
use Appwrite\Runtimes\Runtime;
|
||||
use Utopia\System\System;
|
||||
|
||||
/**
|
||||
* List of Appwrite Cloud Functions supported runtimes
|
||||
|
@ -10,6 +12,11 @@ $runtimes = new Runtimes();
|
|||
|
||||
$allowList = empty(App::getEnv('_APP_FUNCTIONS_RUNTIMES')) ? [] : \explode(',', App::getEnv('_APP_FUNCTIONS_RUNTIMES'));
|
||||
|
||||
$node = new Runtime('node', 'Node.js');
|
||||
$node->addVersion('NG-Latest', 'node:16-alpine-nx', 'node-runtime', [System::X86, System::PPC, System::ARM]);
|
||||
|
||||
$runtimes->add($node);
|
||||
|
||||
$runtimes = $runtimes->getAll(true, $allowList);
|
||||
|
||||
return $runtimes;
|
373
app/executor.php
373
app/executor.php
|
@ -25,6 +25,8 @@ use Utopia\Validator\ArrayList;
|
|||
use Utopia\Validator\JSON;
|
||||
use Utopia\Validator\Text;
|
||||
|
||||
use function PHPUnit\Framework\isEmpty;
|
||||
|
||||
require_once __DIR__ . '/workers.php';
|
||||
|
||||
$dockerUser = App::getEnv('DOCKERHUB_PULL_USERNAME', null);
|
||||
|
@ -34,43 +36,41 @@ $orchestration = new Orchestration(new DockerAPI($dockerUser, $dockerPass, $dock
|
|||
|
||||
$runtimes = Config::getParam('runtimes');
|
||||
|
||||
// NOTE: Triggers wierd cURL and Swoole bug, Need to look into.
|
||||
// Co\run(function() use ($runtimes, $orchestration) { // Warmup: make sure images are ready to run fast 🚀
|
||||
// foreach($runtimes as $runtime) {
|
||||
// go(function() use ($runtime, $orchestration) {
|
||||
// Console::info('Warming up '.$runtime['name'].' '.$runtime['version'].' environment...');
|
||||
|
||||
// $response = $orchestration->pull($runtime['image']);
|
||||
Swoole\Runtime::enableCoroutine(true, SWOOLE_HOOK_ALL ^ SWOOLE_HOOK_CURL);
|
||||
|
||||
// if ($response) {
|
||||
// Console::success("Successfully Warmed up {$runtime['name']} {$runtime['version']}!");
|
||||
// } else {
|
||||
// Console::error("Failed to Warmup {$runtime['name']} {$runtime['version']}!");
|
||||
// }
|
||||
// });
|
||||
// }
|
||||
// });
|
||||
// Warmup: make sure images are ready to run fast 🚀
|
||||
Co\run(function() use ($runtimes, $orchestration) {
|
||||
foreach($runtimes as $runtime) {
|
||||
go(function() use ($runtime, $orchestration) {
|
||||
Console::info('Warming up '.$runtime['name'].' '.$runtime['version'].' environment...');
|
||||
|
||||
$response = $orchestration->pull($runtime['image']);
|
||||
|
||||
if ($response) {
|
||||
Console::success("Successfully Warmed up {$runtime['name']} {$runtime['version']}!");
|
||||
} else {
|
||||
Console::error("Failed to Warmup {$runtime['name']} {$runtime['version']}!");
|
||||
}
|
||||
});
|
||||
}
|
||||
});
|
||||
|
||||
/**
|
||||
* List function servers
|
||||
*/
|
||||
|
||||
$stdout = '';
|
||||
$stderr = '';
|
||||
|
||||
$executionStart = \microtime(true);
|
||||
|
||||
$response = $orchestration->list(['label' => 'appwrite-type=function']);
|
||||
|
||||
$list = [];
|
||||
$activeFunctions = [];
|
||||
|
||||
foreach ($response as $value) {
|
||||
$list[$value->getName()] = $value;
|
||||
$activeFunctions[$value->getName()] = $value;
|
||||
}
|
||||
|
||||
$executionEnd = \microtime(true);
|
||||
|
||||
Console::info(count($list).' functions listed in ' . ($executionEnd - $executionStart) . ' seconds');
|
||||
Console::info(count($activeFunctions).' functions listed in ' . ($executionEnd - $executionStart) . ' seconds');
|
||||
|
||||
App::post('/v1/execute') // Define Route
|
||||
->inject('request')
|
||||
|
@ -107,14 +107,6 @@ App::post('/v1/tag')
|
|||
->inject('projectDB')
|
||||
->inject('projectID')
|
||||
->action(function ($functionId, $tagId, $response, $projectDB, $projectID) {
|
||||
global $register;
|
||||
|
||||
// Create new Database Instance
|
||||
// $projectDB = new Database();
|
||||
// $projectDB->setAdapter(new RedisAdapter(new MySQLAdapter($db, $cache), $cache));
|
||||
// $projectDB->setNamespace('app_' . $projectId);
|
||||
// $projectDB->setMocks(Config::getParam('collections', []));
|
||||
|
||||
Authorization::disable();
|
||||
$project = $projectDB->getDocument($projectID);
|
||||
$function = $projectDB->getDocument($functionId);
|
||||
|
@ -140,6 +132,9 @@ App::post('/v1/tag')
|
|||
]));
|
||||
Authorization::reset();
|
||||
|
||||
// Deploy Runtime Server
|
||||
createRuntimeServer($functionId, $projectID, $tag);
|
||||
|
||||
if ($next) { // Init first schedule
|
||||
ResqueScheduler::enqueueAt($next, 'v1-functions', 'FunctionsV1', [
|
||||
'projectId' => $projectID,
|
||||
|
@ -147,7 +142,7 @@ App::post('/v1/tag')
|
|||
'functionId' => $function->getId(),
|
||||
'executionId' => null,
|
||||
'trigger' => 'schedule',
|
||||
]); // Async task rescheduale
|
||||
]); // Async task reschedule
|
||||
}
|
||||
|
||||
if (false === $function) {
|
||||
|
@ -170,10 +165,162 @@ App::get('/v1/healthz')
|
|||
}
|
||||
);
|
||||
|
||||
function createRuntimeServer(string $functionId, string $projectId, Document $tag) {
|
||||
global $register;
|
||||
global $orchestration;
|
||||
global $runtimes;
|
||||
global $activeFunctions;
|
||||
|
||||
$db = $register->get('db');
|
||||
$cache = $register->get('cache');
|
||||
|
||||
// Create new Database Instance
|
||||
$database = new Database();
|
||||
$database->setAdapter(new RedisAdapter(new MySQLAdapter($db, $cache), $cache));
|
||||
$database->setNamespace('app_' . $projectId);
|
||||
$database->setMocks(Config::getParam('collections', []));
|
||||
|
||||
// Grab Tag Document
|
||||
Authorization::disable();
|
||||
$function = $database->getDocument($functionId);
|
||||
$tag = $database->getDocument($function->getAttribute('tag', ''));
|
||||
Authorization::reset();
|
||||
|
||||
// Check if runtime is active
|
||||
$runtime = (isset($runtimes[$function->getAttribute('runtime', '')]))
|
||||
? $runtimes[$function->getAttribute('runtime', '')]
|
||||
: null;
|
||||
|
||||
if ($tag->getAttribute('functionId') !== $function->getId()) {
|
||||
throw new Exception('Tag not found', 404);
|
||||
}
|
||||
|
||||
if (\is_null($runtime)) {
|
||||
throw new Exception('Runtime "' . $function->getAttribute('runtime', '') . '" is not supported');
|
||||
}
|
||||
|
||||
// Process environment variables
|
||||
$vars = \array_merge($function->getAttribute('vars', []), [
|
||||
'APPWRITE_FUNCTION_ID' => $function->getId(),
|
||||
'APPWRITE_FUNCTION_NAME' => $function->getAttribute('name', ''),
|
||||
'APPWRITE_FUNCTION_TAG' => $tag->getId(),
|
||||
'APPWRITE_FUNCTION_RUNTIME_NAME' => $runtime['name'],
|
||||
'APPWRITE_FUNCTION_RUNTIME_VERSION' => $runtime['version'],
|
||||
'APPWRITE_FUNCTION_PROJECT_ID' => $projectId,
|
||||
]);
|
||||
|
||||
$container = 'appwrite-function-' . $tag->getId();
|
||||
|
||||
if (isset($activeFunctions[$container]) && !(\substr($activeFunctions[$container]->getStatus(), 0, 2) === 'Up')) { // Remove conatiner if not online
|
||||
// If container is online then stop and remove it
|
||||
try {
|
||||
$orchestration->remove($container);
|
||||
} catch (Exception $e) {
|
||||
Console::warning('Failed to remove container: ' . $e->getMessage());
|
||||
}
|
||||
|
||||
unset($activeFunctions[$container]);
|
||||
}
|
||||
|
||||
// Grab Tag Files
|
||||
$tagPath = $tag->getAttribute('path', '');
|
||||
$tagPathTarget = '/tmp/project-' . $projectId . '/' . $tag->getId() . '/code.tar.gz';
|
||||
$tagPathTargetDir = \pathinfo($tagPathTarget, PATHINFO_DIRNAME);
|
||||
$container = 'appwrite-function-' . $tag->getId();
|
||||
|
||||
if (!\is_readable($tagPath)) {
|
||||
throw new Exception('Code is not readable: ' . $tag->getAttribute('path', ''));
|
||||
}
|
||||
|
||||
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);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Limit CPU Usage - DONE
|
||||
* Limit Memory Usage - DONE
|
||||
* Limit Network Usage
|
||||
* Limit Storage Usage (//--storage-opt size=120m \)
|
||||
* Make sure no access to redis, mariadb, influxdb or other system services
|
||||
* Make sure no access to NFS server / storage volumes
|
||||
* Access Appwrite REST from internal network for improved performance
|
||||
*/
|
||||
if (!isset($activeFunctions[$container])) { // Create contianer if not ready
|
||||
$executionStart = \microtime(true);
|
||||
$executionTime = \time();
|
||||
|
||||
$orchestration->setCpus(App::getEnv('_APP_FUNCTIONS_CPUS', '1'));
|
||||
$orchestration->setMemory(App::getEnv('_APP_FUNCTIONS_MEMORY', '256'));
|
||||
$orchestration->setSwap(App::getEnv('_APP_FUNCTIONS_MEMORY_SWAP', '256'));
|
||||
foreach ($vars as &$value) {
|
||||
$value = strval($value);
|
||||
}
|
||||
|
||||
$id = $orchestration->run(
|
||||
image: $runtime['image'],
|
||||
name: $container,
|
||||
vars: $vars,
|
||||
labels: [
|
||||
'appwrite-type' => 'function',
|
||||
'appwrite-created' => strval($executionTime),
|
||||
'appwrite-runtime' => $function->getAttribute('runtime', ''),
|
||||
],
|
||||
hostname: $container,
|
||||
mountFolder: $tagPathTargetDir,
|
||||
);
|
||||
|
||||
// Add to network
|
||||
$orchestration->networkConnect($container, 'appwrite_runtimes');
|
||||
|
||||
$untarStdout = '';
|
||||
$untarStderr = '';
|
||||
|
||||
$untarSuccess = $orchestration->execute(
|
||||
name: $container,
|
||||
command: [
|
||||
'sh',
|
||||
'-c',
|
||||
'mkdir /usr/code -p && cp /tmp/code.tar.gz /usr/code/code.tar.gz && cd /usr/code && tar -zxf /usr/code/code.tar.gz --strip 1 && rm /usr/code/code.tar.gz'
|
||||
],
|
||||
stdout: $untarStdout,
|
||||
stderr: $untarStderr,
|
||||
timeout: 60
|
||||
);
|
||||
|
||||
if (!$untarSuccess) {
|
||||
throw new Exception('Failed to extract tar: ' . $untarStderr);
|
||||
}
|
||||
|
||||
$executionEnd = \microtime(true);
|
||||
|
||||
$activeFunctions[$container] = new Container(
|
||||
$container,
|
||||
$id,
|
||||
'Up',
|
||||
[
|
||||
'appwrite-type' => 'function',
|
||||
'appwrite-created' => strval($executionTime),
|
||||
'appwrite-runtime' => $function->getAttribute('runtime', ''),
|
||||
]
|
||||
);
|
||||
|
||||
Console::info('Runtime Server created in ' . ($executionEnd - $executionStart) . ' seconds');
|
||||
} else {
|
||||
Console::info('Runtime server is ready to run');
|
||||
}
|
||||
};
|
||||
|
||||
function execute(string $trigger, string $projectId, string $executionId, string $functionId, string $event = '', string $eventData = '', string $data = '', array $webhooks = [], string $userId = '', string $jwt = ''): array
|
||||
{
|
||||
global $list;
|
||||
global $orchestration;
|
||||
global $activeFunctions;
|
||||
global $runtimes;
|
||||
|
||||
global $register;
|
||||
|
@ -247,118 +394,10 @@ function execute(string $trigger, string $projectId, string $executionId, string
|
|||
'APPWRITE_FUNCTION_PROJECT_ID' => $projectId,
|
||||
]);
|
||||
|
||||
$tagPath = $tag->getAttribute('path', '');
|
||||
$tagPathTarget = '/tmp/project-' . $projectId . '/' . $tag->getId() . '/code.tar.gz';
|
||||
$tagPathTargetDir = \pathinfo($tagPathTarget, PATHINFO_DIRNAME);
|
||||
$container = 'appwrite-function-' . $tag->getId();
|
||||
$command = \escapeshellcmd($tag->getAttribute('command', ''));
|
||||
|
||||
if (!\is_readable($tagPath)) {
|
||||
throw new Exception('Code is not readable: ' . $tag->getAttribute('path', ''));
|
||||
}
|
||||
|
||||
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);
|
||||
}
|
||||
}
|
||||
|
||||
// Check if container is already online
|
||||
if (isset($list[$container]) && !(\substr($list[$container]->getStatus(), 0, 2) === 'Up')) { // Remove conatiner if not online
|
||||
$stdout = '';
|
||||
$stderr = '';
|
||||
|
||||
// If container is online then stop and remove it
|
||||
try {
|
||||
$orchestration->remove($container);
|
||||
} catch (Exception $e) {
|
||||
Console::warning('Failed to remove container: ' . $e->getMessage());
|
||||
}
|
||||
|
||||
unset($list[$container]);
|
||||
}
|
||||
|
||||
/**
|
||||
* Limit CPU Usage - DONE
|
||||
* Limit Memory Usage - DONE
|
||||
* Limit Network Usage
|
||||
* Limit Storage Usage (//--storage-opt size=120m \)
|
||||
* Make sure no access to redis, mariadb, influxdb or other system services
|
||||
* Make sure no access to NFS server / storage volumes
|
||||
* Access Appwrite REST from internal network for improved performance
|
||||
*/
|
||||
if (!isset($list[$container])) { // Create contianer if not ready
|
||||
$stdout = '';
|
||||
$stderr = '';
|
||||
|
||||
$executionStart = \microtime(true);
|
||||
$executionTime = \time();
|
||||
|
||||
$orchestration->setCpus(App::getEnv('_APP_FUNCTIONS_CPUS', '1'));
|
||||
$orchestration->setMemory(App::getEnv('_APP_FUNCTIONS_MEMORY', '256'));
|
||||
$orchestration->setSwap(App::getEnv('_APP_FUNCTIONS_MEMORY_SWAP', '256'));
|
||||
foreach ($vars as &$value) {
|
||||
$value = strval($value);
|
||||
}
|
||||
|
||||
$id = $orchestration->run(
|
||||
image: $runtime['image'],
|
||||
name: $container,
|
||||
command: [
|
||||
'tail',
|
||||
'-f',
|
||||
'/dev/null'
|
||||
],
|
||||
entrypoint: '',
|
||||
workdir: '/usr/local/src',
|
||||
volumes: [],
|
||||
vars: $vars,
|
||||
mountFolder: $tagPathTargetDir,
|
||||
labels: [
|
||||
'appwrite-type' => 'function',
|
||||
'appwrite-created' => strval($executionTime)
|
||||
]
|
||||
);
|
||||
|
||||
$untarStdout = '';
|
||||
$untarStderr = '';
|
||||
|
||||
$untarSuccess = $orchestration->execute(
|
||||
name: $container,
|
||||
command: [
|
||||
'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'
|
||||
],
|
||||
stdout: $untarStdout,
|
||||
stderr: $untarStderr,
|
||||
vars: $vars,
|
||||
timeout: 60
|
||||
);
|
||||
|
||||
if (!$untarSuccess) {
|
||||
throw new Exception('Failed to extract tar: ' . $untarStderr);
|
||||
}
|
||||
|
||||
$executionEnd = \microtime(true);
|
||||
|
||||
$list[$container] = new Container(
|
||||
$container,
|
||||
$id,
|
||||
'Up',
|
||||
[
|
||||
'appwrite-type' => 'function',
|
||||
'appwrite-created' => strval($executionTime),
|
||||
]
|
||||
);
|
||||
|
||||
Console::info('Function created in ' . ($executionEnd - $executionStart) . ' seconds');
|
||||
if (!isset($activeFunctions[$container])) { // Create contianer if not ready
|
||||
createRuntimeServer($functionId, $projectId, $tag);
|
||||
} else {
|
||||
Console::info('Container is ready to run');
|
||||
}
|
||||
|
@ -370,18 +409,41 @@ function execute(string $trigger, string $projectId, string $executionId, string
|
|||
|
||||
$exitCode = 0;
|
||||
|
||||
// Execute function
|
||||
try {
|
||||
$exitCode = (int)!$orchestration->execute(
|
||||
name: $container,
|
||||
command: $orchestration->parseCommandString($command),
|
||||
stdout: $stdout,
|
||||
stderr: $stderr,
|
||||
vars: $vars,
|
||||
timeout: $function->getAttribute('timeout', (int) App::getEnv('_APP_FUNCTIONS_TIMEOUT', 900))
|
||||
);
|
||||
} catch (TimeoutException $e) {
|
||||
$exitCode = 124;
|
||||
// cURL request to runtime
|
||||
$ch = \curl_init();
|
||||
\curl_setopt($ch, CURLOPT_URL, "http://".$container.":3000/");
|
||||
\curl_setopt($ch, CURLOPT_POST, true);
|
||||
\curl_setopt($ch, CURLOPT_POSTFIELDS, json_encode([
|
||||
'path' => '/usr/code',
|
||||
'file' => 'index.js',
|
||||
'env' => $vars,
|
||||
'payload' => $data
|
||||
]));
|
||||
\curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
|
||||
\curl_setopt($ch, CURLOPT_TIMEOUT, $function->getAttribute('timeout', (int) App::getEnv('_APP_FUNCTIONS_TIMEOUT', 900)));
|
||||
\curl_setopt($ch, CURLOPT_CONNECTTIMEOUT, 10);
|
||||
|
||||
$executorResponse = \curl_exec($ch);
|
||||
|
||||
$error = \curl_error($ch);
|
||||
if (!empty($error)) {
|
||||
throw new Exception('Curl error: ' . $error, 500);
|
||||
}
|
||||
|
||||
\curl_close($ch);
|
||||
|
||||
$executionData = json_decode($executorResponse, true);
|
||||
if (\is_null($executionData)) {
|
||||
throw new Exception('Failed to decode JSON response', 500);
|
||||
}
|
||||
if (isset($executionData['code'])) {
|
||||
$exitCode = $executionData['code'];
|
||||
}
|
||||
|
||||
if ($exitCode === 500) {
|
||||
$stderr = $executionData['message'];
|
||||
} else {
|
||||
$stdout = $executorResponse;
|
||||
}
|
||||
|
||||
$executionEnd = \microtime(true);
|
||||
|
@ -492,7 +554,6 @@ $http->on('request', function (SwooleRequest $swooleRequest, SwooleResponse $swo
|
|||
|
||||
if($route) {
|
||||
Console::error('[Error] Method: '.$route->getMethod());
|
||||
Console::error('[Error] URL: '.$route->getURL());
|
||||
}
|
||||
|
||||
Console::error('[Error] Type: '.get_class($error));
|
||||
|
|
|
@ -318,7 +318,7 @@ class FunctionsV1 extends Worker
|
|||
'Content-Type: application/json',
|
||||
]);
|
||||
|
||||
$response = \curl_exec($ch);
|
||||
\curl_exec($ch);
|
||||
|
||||
$error = \curl_error($ch);
|
||||
if (!empty($error)) {
|
||||
|
|
|
@ -20,6 +20,12 @@
|
|||
"Appwrite\\Tests\\": "tests/extensions"
|
||||
}
|
||||
},
|
||||
"repositories": [
|
||||
{
|
||||
"url": "https://github.com/PineappleIOnic/orchestration.git",
|
||||
"type": "git"
|
||||
}
|
||||
],
|
||||
"require": {
|
||||
"php": ">=8.0.0",
|
||||
"ext-curl": "*",
|
||||
|
@ -52,7 +58,7 @@
|
|||
"utopia-php/swoole": "0.2.*",
|
||||
"utopia-php/storage": "0.5.*",
|
||||
"utopia-php/image": "0.5.*",
|
||||
"utopia-php/orchestration": "0.2.*",
|
||||
"utopia-php/orchestration": "dev-exp1",
|
||||
"resque/php-resque": "1.3.6",
|
||||
"matomo/device-detector": "4.2.3",
|
||||
"dragonmantank/cron-expression": "3.1.0",
|
||||
|
|
67
composer.lock
generated
67
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": "45963af754680568d89330a4f37c40d1",
|
||||
"content-hash": "9d5d3107489a374a84612765ee3ae4c5",
|
||||
"packages": [
|
||||
{
|
||||
"name": "adhocore/jwt",
|
||||
|
@ -1907,6 +1907,55 @@
|
|||
},
|
||||
"time": "2021-07-24T11:35:55+00:00"
|
||||
},
|
||||
{
|
||||
"name": "utopia-php/orchestration",
|
||||
"version": "dev-exp1",
|
||||
"source": {
|
||||
"type": "git",
|
||||
"url": "https://github.com/PineappleIOnic/orchestration.git",
|
||||
"reference": "26b4d08fd72a00a1e2b41e11876e97566036db48"
|
||||
},
|
||||
"require": {
|
||||
"php": ">=8.0",
|
||||
"utopia-php/cli": "0.11.*"
|
||||
},
|
||||
"require-dev": {
|
||||
"phpunit/phpunit": "^9.3",
|
||||
"vimeo/psalm": "4.0.1"
|
||||
},
|
||||
"type": "library",
|
||||
"autoload": {
|
||||
"psr-4": {
|
||||
"Utopia\\Orchestration\\": "src/Orchestration"
|
||||
}
|
||||
},
|
||||
"autoload-dev": {
|
||||
"psr-4": {
|
||||
"Utopia\\Tests\\": "tests/Orchestration"
|
||||
}
|
||||
},
|
||||
"license": [
|
||||
"MIT"
|
||||
],
|
||||
"authors": [
|
||||
{
|
||||
"name": "Eldad Fux",
|
||||
"email": "eldad@appwrite.io"
|
||||
}
|
||||
],
|
||||
"description": "Lite & fast micro PHP abstraction library for container orchestration",
|
||||
"keywords": [
|
||||
"docker",
|
||||
"framework",
|
||||
"kubernetes",
|
||||
"orchestration",
|
||||
"php",
|
||||
"swarm",
|
||||
"upf",
|
||||
"utopia"
|
||||
],
|
||||
"time": "2021-08-27T09:04:09+00:00"
|
||||
},
|
||||
{
|
||||
"name": "utopia-php/preloader",
|
||||
"version": "0.2.4",
|
||||
|
@ -2452,16 +2501,16 @@
|
|||
},
|
||||
{
|
||||
"name": "composer/package-versions-deprecated",
|
||||
"version": "1.11.99.2",
|
||||
"version": "1.11.99.3",
|
||||
"source": {
|
||||
"type": "git",
|
||||
"url": "https://github.com/composer/package-versions-deprecated.git",
|
||||
"reference": "c6522afe5540d5fc46675043d3ed5a45a740b27c"
|
||||
"reference": "fff576ac850c045158a250e7e27666e146e78d18"
|
||||
},
|
||||
"dist": {
|
||||
"type": "zip",
|
||||
"url": "https://api.github.com/repos/composer/package-versions-deprecated/zipball/c6522afe5540d5fc46675043d3ed5a45a740b27c",
|
||||
"reference": "c6522afe5540d5fc46675043d3ed5a45a740b27c",
|
||||
"url": "https://api.github.com/repos/composer/package-versions-deprecated/zipball/fff576ac850c045158a250e7e27666e146e78d18",
|
||||
"reference": "fff576ac850c045158a250e7e27666e146e78d18",
|
||||
"shasum": ""
|
||||
},
|
||||
"require": {
|
||||
|
@ -2505,7 +2554,7 @@
|
|||
"description": "Composer plugin that provides efficient querying for installed package versions (no runtime IO)",
|
||||
"support": {
|
||||
"issues": "https://github.com/composer/package-versions-deprecated/issues",
|
||||
"source": "https://github.com/composer/package-versions-deprecated/tree/1.11.99.2"
|
||||
"source": "https://github.com/composer/package-versions-deprecated/tree/1.11.99.3"
|
||||
},
|
||||
"funding": [
|
||||
{
|
||||
|
@ -2521,7 +2570,7 @@
|
|||
"type": "tidelift"
|
||||
}
|
||||
],
|
||||
"time": "2021-05-24T07:46:03+00:00"
|
||||
"time": "2021-08-17T13:49:14+00:00"
|
||||
},
|
||||
{
|
||||
"name": "composer/semver",
|
||||
|
@ -6067,7 +6116,9 @@
|
|||
],
|
||||
"aliases": [],
|
||||
"minimum-stability": "stable",
|
||||
"stability-flags": [],
|
||||
"stability-flags": {
|
||||
"utopia-php/orchestration": 20
|
||||
},
|
||||
"prefer-stable": false,
|
||||
"prefer-lowest": false,
|
||||
"platform": {
|
||||
|
|
|
@ -332,6 +332,7 @@ services:
|
|||
appwrite:
|
||||
aliases:
|
||||
- executor
|
||||
runtimes:
|
||||
volumes:
|
||||
- /var/run/docker.sock:/var/run/docker.sock
|
||||
- appwrite-functions:/storage/functions:rw
|
||||
|
@ -588,6 +589,7 @@ services:
|
|||
networks:
|
||||
gateway:
|
||||
appwrite:
|
||||
runtimes:
|
||||
|
||||
volumes:
|
||||
appwrite-mariadb:
|
||||
|
|
Loading…
Reference in a new issue