1
0
Fork 0
mirror of synced 2024-06-15 09:14:50 +12:00

Make new database work with the executor

+ New DB now works with executor
+ events now work with new execution model
This commit is contained in:
Bradley Schofield 2021-10-14 10:37:00 +01:00
parent efaa2227e0
commit 7649a2c677
7 changed files with 172 additions and 184 deletions

2
.env
View file

@ -35,7 +35,7 @@ _APP_SMTP_PASSWORD=
_APP_STORAGE_LIMIT=10000000
_APP_FUNCTIONS_TIMEOUT=900
_APP_FUNCTIONS_CONTAINERS=10
_APP_FUNCTIONS_CPUS=12
_APP_FUNCTIONS_CPUS=4
_APP_FUNCTIONS_MEMORY=2000
_APP_FUNCTIONS_MEMORY_SWAP=2000
_APP_EXECUTOR_SECRET=a-randomly-generated-key

View file

@ -1471,7 +1471,7 @@ $collections = [
[
'$collection' => Database::SYSTEM_COLLECTION_RULES,
'label' => 'Build Path',
'key' => 'builtPath',
'key' => 'buildPath',
'type' => Database::SYSTEM_VAR_TYPE_TEXT,
'default' => '',
'required' => false,

View file

@ -1971,7 +1971,7 @@ $collections = [
'filters' => [],
],
[
'$id' => 'builtPath',
'$id' => 'buildPath',
'type' => Database::VAR_STRING,
'format' => '',
'size' => 2048,

View file

@ -24,7 +24,7 @@ use Utopia\Validator\Range;
use Utopia\Validator\WhiteList;
use Utopia\Config\Config;
use Cron\CronExpression;
use Utopia\Validator\Boolean;
use Utopia\CLI\Console;
include_once __DIR__ . '/../shared/api.php';
@ -331,7 +331,7 @@ App::patch('/v1/functions/:functionId/tag')
\curl_setopt($ch, CURLOPT_CONNECTTIMEOUT, 10);
\curl_setopt($ch, CURLOPT_HTTPHEADER, [
'Content-Type: application/json',
'X-Appwrite-Project: '.$project->getId(),
'x-appwrite-project: '.$project->getId(),
'x-appwrite-executor-key: '. App::getEnv('_APP_EXECUTOR_SECRET', '')
]);
@ -369,7 +369,8 @@ App::delete('/v1/functions/:functionId')
->inject('response')
->inject('dbForInternal')
->inject('deletes')
->action(function ($functionId, $response, $dbForInternal, $deletes) {
->inject('project')
->action(function ($functionId, $response, $dbForInternal, $deletes, $project) {
/** @var Appwrite\Utopia\Response $response */
/** @var Utopia\Database\Database $dbForInternal */
/** @var Appwrite\Event\Event $deletes */
@ -388,7 +389,7 @@ App::delete('/v1/functions/:functionId')
\curl_setopt($ch, CURLOPT_CONNECTTIMEOUT, 10);
\curl_setopt($ch, CURLOPT_HTTPHEADER, [
'Content-Type: application/json',
'X-Appwrite-Project: '.$project->getId(),
'x-appwrite-project: '.$project->getId(),
'x-appwrite-executor-key: '. App::getEnv('_APP_EXECUTOR_SECRET', '')
]);
@ -502,9 +503,9 @@ App::post('/v1/functions/:functionId/tags')
'entrypoint' => $entrypoint,
'path' => $path,
'size' => $size,
'search' => implode(' ', [$tagId, $command]),
'search' => implode(' ', [$tagId, $entrypoint]),
'status' => 'pending',
'builtPath' => '',
'buildPath' => '',
'buildStdout' => '',
'buildStderr' => ''
]));
@ -626,10 +627,12 @@ App::delete('/v1/functions/:functionId/tags/:tagId')
->inject('response')
->inject('dbForInternal')
->inject('usage')
->action(function ($functionId, $tagId, $response, $dbForInternal, $usage) {
->inject('project')
->action(function ($functionId, $tagId, $response, $dbForInternal, $usage, $project) {
/** @var Appwrite\Utopia\Response $response */
/** @var Utopia\Database\Database $dbForInternal */
/** @var Appwrite\Event\Event $usage */
/** @var Utopia\Database\Document $project */
$function = $dbForInternal->getDocument('functions', $functionId);
@ -659,7 +662,7 @@ App::delete('/v1/functions/:functionId/tags/:tagId')
\curl_setopt($ch, CURLOPT_CONNECTTIMEOUT, 10);
\curl_setopt($ch, CURLOPT_HTTPHEADER, [
'Content-Type: application/json',
'X-Appwrite-Project: '.$project->getId(),
'x-appwrite-project: '.$project->getId(),
'x-appwrite-executor-key: '. App::getEnv('_APP_EXECUTOR_SECRET', '')
]);
@ -831,6 +834,7 @@ App::post('/v1/functions/:functionId/executions')
\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', '')
]);

View file

@ -1,12 +1,10 @@
<?php
require_once __DIR__ . '/../vendor/autoload.php';
use Appwrite\Database\Database;
use Appwrite\Database\Document;
use Appwrite\Database\Adapter\MySQL as MySQLAdapter;
use Appwrite\Database\Adapter\Redis as RedisAdapter;
use Appwrite\Database\Validator\Authorization;
use Appwrite\Database\Validator\UID;
use Utopia\Database\Document;
use Utopia\Database\Database;
use Utopia\Database\Validator\Authorization;
use Utopia\Database\Validator\UID;
use Appwrite\Event\Event;
use Appwrite\Utopia\Response\Model\Execution;
use Appwrite\Messaging\Adapter\Realtime;
@ -96,7 +94,7 @@ App::post('/v1/execute') // Define Route
->param('executionId', '', new Text(1024), '', true)
->param('functionId', '', new Text(1024))
->param('event', '', new Text(1024), '', true)
->param('eventData', '', new Text(1024), '', true)
->param('eventData', '', new Text(10240), '', true)
->param('data', '', new Text(1024), '', true)
->param('webhooks', [], new ArrayList(new JSON()), [], true)
->param('userId', '', new Text(1024), '', true)
@ -134,25 +132,25 @@ App::post('/v1/cleanup/function')
global $orchestration;
try {
Authorization::disable();
$function = $dbForInternal->getDocument($functionId);
Authorization::reset();
$function = Authorization::skip(function () use ($dbForInternal, $functionId) {
return $dbForInternal->getDocument('functions', $functionId);
});
if (\is_null($function->getId()) || Database::SYSTEM_COLLECTION_FUNCTIONS != $function->getCollection()) {
if ($function->isEmpty()) {
throw new Exception('Function not found', 404);
}
Authorization::disable();
$results = $dbForInternal->getCollection([
'limit' => 999,
'offset' => 0,
'orderType' => 'ASC',
'filters' => [
'$collection=' . Database::SYSTEM_COLLECTION_TAGS,
'functionId=' . $functionId,
],
]);
Authorization::reset();
$results = Authorization::skip(function () use ($dbForInternal, $functionId) {
return $dbForInternal->getCollection([
'limit' => 999,
'offset' => 0,
'orderType' => 'ASC',
'filters' => [
'$collection=' . 'tags',
'functionId=' . $functionId,
],
]);
});
// If amount is 0 then we simply return true
if (count($results) === 0) {
@ -190,11 +188,11 @@ App::post('/v1/cleanup/tag')
global $orchestration;
try {
Authorization::disable();
$tag = $dbForInternal->getDocument($tagId);
Authorization::reset();
$tag = Authorization::skip(function () use ($dbForInternal, $tagId) {
return $dbForInternal->getDocument('tags', $tagId);
});
if (\is_null($tag->getId()) || Database::SYSTEM_COLLECTION_TAGS != $tag->getCollection()) {
if ($tag->isEmpty()) {
throw new Exception('Tag not found', 404);
}
@ -219,16 +217,19 @@ App::post('/v1/tag')
->inject('dbForInternal')
->inject('projectID')
->action(function ($functionId, $tagId, $response, $dbForInternal, $projectID) {
Authorization::disable();
$function = $dbForInternal->getDocument('functions', $functionId);
$tag = $dbForInternal->getDocument('tags', $tagId);
Authorization::reset();
$function = Authorization::skip(function() use ($functionId, $dbForInternal) {
return $dbForInternal->getDocument('functions', $functionId);
});
if (empty($function->getId()) || Database::SYSTEM_COLLECTION_FUNCTIONS != $function->getCollection()) {
$tag = Authorization::skip(function() use ($tagId, $dbForInternal) {
return $dbForInternal->getDocument('tags', $tagId);
});
if ($function->isEmpty()) {
throw new Exception('Function not found', 404);
}
if (empty($tag->getId()) || Database::SYSTEM_COLLECTION_TAGS != $tag->getCollection()) {
if ($tag->isEmpty()) {
throw new Exception('Tag not found', 404);
}
@ -236,12 +237,12 @@ App::post('/v1/tag')
$cron = (empty($function->getAttribute('tag')) && !empty($schedule)) ? new CronExpression($schedule) : null;
$next = (empty($function->getAttribute('tag')) && !empty($schedule)) ? $cron->getNextRunDate()->format('U') : 0;
Authorization::disable();
$function = $dbForInternal->updateDocument('functions', $function->getId(), new Document(array_merge($function->getArrayCopy(), [
'tag' => $tag->getId(),
'scheduleNext' => (int)$next,
])));
Authorization::reset();
$function = Authorization::skip(function() use ($function, $dbForInternal, $tag, $next) {
return $function = $dbForInternal->updateDocument('functions', $function->getId(), new Document(array_merge($function->getArrayCopy(), [
'tag' => $tag->getId(),
'scheduleNext' => (int)$next,
])));
});
// Build Code
go(function () use ($dbForInternal, $projectID, $function, $tagId, $functionId) {
@ -281,22 +282,22 @@ function runBuildStage(string $tagID, Document $function, string $projectID, Dat
$buildStderr = '';
// Check if tag is already built
Authorization::disable();
$tag = $database->getDocument($tagID);
Authorization::reset();
$tag = Authorization::skip(function () use ($tagID, $database) {
return $database->getDocument('tags', $tagID);
});
try {
// If we already have a built package ready there is no need to rebuild.
if ($tag->getAttribute('status') === 'ready' && \file_exists($tag->getAttribute('builtPath'))) {
if ($tag->getAttribute('status') === 'ready' && \file_exists($tag->getAttribute('buildPath'))) {
return $tag;
}
// Update Tag Status
Authorization::disable();
$tag = $database->updateDocument(array_merge($tag->getArrayCopy(), [
'status' => 'building'
]));
Authorization::reset();
$tag->setAttribute('status', 'building');
Authorization::skip(function () use ($tag, $database) {
$database->updateDocument('tags', $tag->getId(), $tag);
});
// Check if runtime is active
$runtime = (isset($runtimes[$function->getAttribute('runtime', '')]))
@ -354,6 +355,12 @@ function runBuildStage(string $tagID, Document $function, string $projectID, Dat
$value = strval($value);
}
if (!\file_exists('/tmp/project-' . $projectID . '/' . $tag->getId() . '/builtCode')) {
if (!\mkdir('/tmp/project-' . $projectID . '/' . $tag->getId() . '/builtCode', 0755, true)) {
throw new Exception('Can\'t create directory /tmp/project-' . $projectID . '/' . $tag->getId() . '/builtCode');
}
};
$id = $orchestration->run(
image: $runtime['base'],
name: $container,
@ -451,28 +458,29 @@ function runBuildStage(string $tagID, Document $function, string $projectID, Dat
throw new Exception('Failed moving file', 500);
}
$tag->setAttribute('buildPath', $path)
->setAttribute('status', 'ready')
->setAttribute('buildStdout', \utf8_encode(\mb_substr($buildStdout, -4096)))
->setAttribute('buildStderr', \utf8_encode(\mb_substr($buildStderr, -4096)));
// Update tag with built code attribute
Authorization::disable();
$tag = $database->updateDocument(array_merge($tag->getArrayCopy(), [
'builtPath' => $path,
'status' => 'ready',
'buildStdout' => $buildStdout,
'buildStderr' => $buildStderr
]));
Authorization::enable();
$tag = Authorization::skip(function () use ($tag, $tagID, $database) {
return $database->updateDocument('tags', $tagID, $tag);
});
$buildEnd = \microtime(true);
Console::info('Tag Built in ' . ($buildEnd - $buildStart) . ' seconds');
} catch (Exception $e) {
Console::error('Tag build failed: ' . $e->getMessage());
Authorization::disable();
$tag = $database->updateDocument(array_merge($tag->getArrayCopy(), [
'status' => 'failed',
'buildStdout' => $buildStdout,
'buildStderr' => $buildStderr,
]));
Authorization::enable();
$tag->setAttribute('status', 'failed')
->setAttribute('buildStdout', \utf8_encode(\mb_substr($buildStdout, -4096)))
->setAttribute('buildStderr', \utf8_encode(\mb_substr($buildStderr, -4096)));
Authorization::skip(function () use ($tag, $tagID, $database) {
return $database->updateDocument('tags', $tagID, $tag);
});
// also remove the container if it exists
if ($id) {
@ -491,9 +499,9 @@ function createRuntimeServer(string $functionId, string $projectId, Document $ta
global $activeFunctions;
// Grab Tag Document
Authorization::disable();
$function = $database->getDocument($functionId);
Authorization::reset();
$function = Authorization::skip(function () use ($database, $functionId) {
return $database->getDocument('functions', $functionId);
});
// Check if function isn't already created
$functions = $orchestration->list(['label' => 'appwrite-type=function', 'name' => 'appwrite-function-' . $tag->getId()]);
@ -553,7 +561,7 @@ function createRuntimeServer(string $functionId, string $projectId, Document $ta
}
// Grab Tag Files
$tagPath = $tag->getAttribute('builtPath', '');
$tagPath = $tag->getAttribute('buildPath', '');
$tagPathTarget = '/tmp/project-' . $projectId . '/' . $tag->getId() . '/builtCode/code.tar.gz';
$tagPathTargetDir = \pathinfo($tagPathTarget, PATHINFO_DIRNAME);
@ -636,51 +644,54 @@ function execute(string $trigger, string $projectId, string $executionId, string
global $register;
// Grab Tag Document
Authorization::disable();
$function = $database->getDocument($functionId);
$tag = $database->getDocument($function->getAttribute('tag', ''));
Authorization::reset();
$function = Authorization::skip(function () use ($database, $functionId) {
return $database->getDocument('functions', $functionId);
});
$tag = Authorization::skip(function () use ($database, $function) {
return $database->getDocument('tags', $function->getAttribute('tag', ''));
});
if ($tag->getAttribute('functionId') !== $function->getId()) {
throw new Exception('Tag not found', 404);
}
Authorization::disable();
// Grab execution document if exists
// It it doesn't exist, create a new one.
$execution = (!empty($executionId)) ? $database->getDocument($executionId) : $database->createDocument([
'$collection' => Database::SYSTEM_COLLECTION_EXECUTIONS,
'$permissions' => [
'read' => [],
'write' => [],
],
'dateCreated' => time(),
'functionId' => $function->getId(),
'trigger' => $trigger, // http / schedule / event
'status' => 'processing', // waiting / processing / completed / failed
'exitCode' => 0,
'stdout' => '',
'stderr' => '',
'time' => 0,
]);
$execution = Authorization::skip(function () use ($database, $executionId, $userId, $function, $tag, $trigger, $functionId) {
return (!empty($executionId)) ? $database->getDocument('executions', $executionId) : $database->createDocument('executions', new Document([
'$id' => $executionId,
'$read' => (!$userId == '') ? ['user:' . $userId] : [],
'$write' => [],
'dateCreated' => time(),
'functionId' => $function->getId(),
'tagId' => $tag->getId(),
'trigger' => $trigger, // http / schedule / event
'status' => 'processing', // waiting / processing / completed / failed
'exitCode' => 0,
'stdout' => '',
'stderr' => '',
'time' => 0.0,
'search' => implode(' ', [$functionId, $executionId]),
]));
});
if (false === $execution || ($execution instanceof Document && $execution->isEmpty())) {
throw new Exception('Failed to create or read execution');
}
Authorization::reset();
if ($tag->getAttribute('status') == 'building') {
Console::error('Execution Failed. Reason: Code was still being built.');
Authorization::disable();
$execution = $database->updateDocument(array_merge($execution->getArrayCopy(), [
'tagId' => $tag->getId(),
'status' => 'failed',
'exitCode' => 1,
'stderr' => 'Tag is still being built.', // log last 4000 chars output
'time' => 0
]));
Authorization::reset();
$execution->setAttribute('status', 'failed')
->setAttribute('exitCode', 1)
->setAttribute('stderr', 'Tag is still being built.')
->setAttribute('time', 0);
Authorization::skip(function () use ($database, $execution) {
return $database->updateDocument('executions', $execution->getId(), $execution);
});
throw new Exception('Tag is still being built.');
}
@ -718,13 +729,14 @@ function execute(string $trigger, string $projectId, string $executionId, string
}
} catch (Exception $e) {
Console::error('Something went wrong building the code. ' . $e->getMessage());
$execution = $database->updateDocument(array_merge($execution->getArrayCopy(), [
'tagId' => $tag->getId(),
'status' => 'failed',
'exitCode' => 1,
'stderr' => \utf8_encode(\mb_substr($e->getMessage(), -4000)), // log last 4000 chars output
'time' => 0
]));
$execution->setAttribute('status', 'failed')
->setAttribute('exitCode', 1)
->setAttribute('stderr', \utf8_encode(\mb_substr($e->getMessage(), -4000))) // log last 4000 chars output
->setAttribute('time', 0);
Authorization::skip(function () use ($database, $execution) {
return $database->updateDocument('executions', $execution->getId(), $execution);
});
}
try {
@ -737,15 +749,15 @@ function execute(string $trigger, string $projectId, string $executionId, string
}
} catch (Exception $e) {
Console::error('Something went wrong building the runtime server. ' . $e->getMessage());
Authorization::disable();
$execution = $database->updateDocument(array_merge($execution->getArrayCopy(), [
'tagId' => $tag->getId(),
'status' => 'failed',
'exitCode' => 1,
'stderr' => \utf8_encode(\mb_substr($e->getMessage(), -4000)), // log last 4000 chars output
'time' => 0
]));
Authorization::enable();
$execution->setAttribute('status', 'failed')
->setAttribute('exitCode', 1)
->setAttribute('stderr', \utf8_encode(\mb_substr($e->getMessage(), -4000))) // log last 4000 chars output
->setAttribute('time', 0);
$execution = Authorization::skip(function () use ($database, $execution) {
return $database->updateDocument('executions', $execution->getId(), $execution);
});
return [
'status' => 'failed',
'response' => \utf8_encode(\mb_substr($e->getMessage(), -4000)), // log last 4000 chars output
@ -865,15 +877,15 @@ function execute(string $trigger, string $projectId, string $executionId, string
Console::info('Function executed in ' . ($executionEnd - $executionStart) . ' seconds, status: ' . $functionStatus);
$execution = Authorization::skip(function () use ($database, $execution, $tag, $functionStatus, $exitCode, $stdout, $stderr, $executionTime) {
return $database->updateDocument('executions', $execution->getId(), new Document(array_merge($execution->getArrayCopy(), [
'tagId' => $tag->getId(),
'status' => $functionStatus,
'exitCode' => $exitCode,
'stdout' => \utf8_encode(\mb_substr($stdout, -8000)), // log last 8000 chars output
'stderr' => \utf8_encode(\mb_substr($stderr, -8000)), // log last 8000 chars output
'time' => (float)$executionTime,
])));
$execution->setAttribute('tagId', $tag->getId())
->setAttribute('status', $functionStatus)
->setAttribute('exitCode', $exitCode)
->setAttribute('stdout', \utf8_encode(\mb_substr($stdout, -8000)))
->setAttribute('stderr', \utf8_encode(\mb_substr($stderr, -8000)))
->setAttribute('time', $executionTime);
$execution = Authorization::skip(function () use ($database, $execution) {
return $database->updateDocument('executions', $execution->getId(), $execution);
});
$executionModel = new Execution();
@ -898,7 +910,7 @@ function execute(string $trigger, string $projectId, string $executionId, string
roles: $target['roles']
);
if (App::getEnv('_APP_USAGE_STATS', 'enabled') == 'enabled') {
if(App::getEnv('_APP_USAGE_STATS', 'enabled') == 'enabled') {
$statsd = $register->get('statsd');
$usage = new Stats($statsd);
@ -911,15 +923,12 @@ function execute(string $trigger, string $projectId, string $executionId, string
->setParam('functionExecutionTime', $executionTime * 1000) // ms
->setParam('networkRequestSize', 0)
->setParam('networkResponseSize', 0)
->submit();
->submit()
;
$usage->submit();
}
if (App::getEnv('_APP_USAGE_STATS', 'enabled') == 'enabled') {
$usage->trigger();
}
return [
'status' => $functionStatus,
'response' => $stdout,
@ -960,52 +969,20 @@ $http->on('request', function (SwooleRequest $swooleRequest, SwooleResponse $swo
$response = new Response($swooleResponse);
$app = new App('UTC');
$db = $register->get('dbPool')->get();
App::setResource('db', function () use (&$db) {
$dbHost = App::getEnv('_APP_DB_HOST', '');
$dbUser = App::getEnv('_APP_DB_USER', '');
$dbPass = App::getEnv('_APP_DB_PASS', '');
$dbScheme = App::getEnv('_APP_DB_SCHEMA', '');
$pdo = new PDO("mysql:host={$dbHost};dbname={$dbScheme};charset=utf8mb4", $dbUser, $dbPass, array(
PDO::MYSQL_ATTR_INIT_COMMAND => 'SET NAMES utf8mb4',
PDO::ATTR_TIMEOUT => 3, // Seconds
PDO::ATTR_PERSISTENT => true,
PDO::ATTR_DEFAULT_FETCH_MODE => PDO::FETCH_ASSOC,
PDO::ATTR_ERRMODE => PDO::ERRMODE_EXCEPTION,
));
return $pdo;
return $db;
});
$redis = $register->get('redisPool')->get();
App::setResource('cache', function () use (&$redis) {
$redis = new Redis();
$redis->pconnect(App::getEnv('_APP_REDIS_HOST', ''), App::getEnv('_APP_REDIS_PORT', ''));
$redis->setOption(Redis::OPT_READ_TIMEOUT, -1);
return $redis;
});
App::setResource('dbForConsole', function($db, $cache) {
$cache = new Cache(new RedisCache($cache));
$database = new Database(new MariaDB($db), $cache);
$database->setNamespace('project_console_internal');
return $database;
}, ['db', 'cache']);
$projectId = $request->getHeader('x-appwrite-project', '');
App::setResource('project', function ($dbForConsole) use ($projectId) {
Authorization::disable();
$project = $dbForConsole->getDocument('projects', $projectId);
Authorization::reset();
return $project;
}, ['dbForConsole']);
Storage::setDevice('functions', new Local(APP_STORAGE_FUNCTIONS . '/app-' . $projectId));
// Check environment variable key
@ -1021,16 +998,14 @@ $http->on('request', function (SwooleRequest $swooleRequest, SwooleResponse $swo
return $swooleResponse->end('401: Authentication Error');
}
App::setResource('dbForInternal', function ($db, $cache, $project) {
App::setResource('dbForInternal', function($db, $cache) use ($projectId) {
$cache = new Cache(new RedisCache($cache));
$test = $project->getId();
$database = new Database(new MariaDB($db), $cache);
$database->setNamespace('project_' . $project->getId() . '_internal');
$database->setNamespace('project_'.$projectId.'_internal');
return $database;
}, ['db', 'cache', 'project']);
}, ['db', 'cache']);
App::error(function ($error, $utopia, $request, $response) {
/** @var Exception $error */
@ -1094,6 +1069,14 @@ $http->on('request', function (SwooleRequest $swooleRequest, SwooleResponse $swo
} catch (Exception $e) {
Console::error('There\'s a problem with ' . $request->getURI());
$swooleResponse->end('500: Server Error');
} finally {
/** @var PDOPool $dbPool */
$dbPool = $register->get('dbPool');
$dbPool->put($db);
/** @var RedisPool $redisPool */
$redisPool = $register->get('redisPool');
$redisPool->put($redis);
}
});

View file

@ -269,7 +269,7 @@ class FunctionsV1 extends Worker
'executionId' => $executionId,
'functionId' => $function->getId(),
'event' => $event,
'eventData' => $eventData,
'eventData' => json_encode($eventData),
'data' => $data,
'webhooks' => $webhooks,
'userId' => $userId,
@ -280,6 +280,7 @@ class FunctionsV1 extends Worker
\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', '')
]);

4
composer.lock generated
View file

@ -119,7 +119,7 @@
"source": {
"type": "git",
"url": "https://github.com/PineappleIOnic/php-runtimes.git",
"reference": "f6dbfb76cbf52934085d4e119f5de28f33b69aa1"
"reference": "fb25cb8d382148d53146d614eaa9f954bef2986f"
},
"require": {
"php": ">=8.0",
@ -156,7 +156,7 @@
"php",
"runtimes"
],
"time": "2021-10-11T10:57:42+00:00"
"time": "2021-10-13T10:40:47+00:00"
},
{
"name": "chillerlan/php-qrcode",