diff --git a/app/executor.php b/app/executor.php index 83f83e6b54..1eb73df85c 100644 --- a/app/executor.php +++ b/app/executor.php @@ -177,6 +177,12 @@ App::post('/v1/runtimes') ->inject('response') ->action(function (string $runtimeId, string $source, string $destination, array $vars, array $commands, string $runtime, string $baseImage, string $entrypoint, bool $remove, string $workdir, $orchestrationPool, $activeRuntimes, Response $response) { if ($activeRuntimes->exists($runtimeId)) { + + if ($activeRuntimes->get($runtimeId)['key'] == 'Pending') { + sleep(1); + throw new \Exception('A runtime with the same ID is already being created.', 500); + } + throw new Exception('Runtime already exists.', 409); } @@ -188,6 +194,17 @@ App::post('/v1/runtimes') $endTime = 0; $orchestration = $orchestrationPool->get(); + $secret = \bin2hex(\random_bytes(16)); + + $activeRuntimes->set($runtimeId, [ + 'id' => $containerId, + 'name' => $runtimeId, + 'created' => $startTime, + 'updated' => $endTime, + 'status' => 'Pending', + 'key' => $secret, + ]); + try { Console::info('Building container : ' . $runtimeId); @@ -219,7 +236,6 @@ App::post('/v1/runtimes') /** * Create container */ - $secret = \bin2hex(\random_bytes(16)); $vars = \array_merge($vars, [ 'INTERNAL_RUNTIME_KEY' => $secret, 'INTERNAL_RUNTIME_ENTRYPOINT' => $entrypoint, @@ -440,7 +456,6 @@ App::post('/v1/execution') ->inject('response') ->action( function (string $runtimeId, array $vars, string $data, $timeout, $activeRuntimes, Response $response) { - if (!$activeRuntimes->exists($runtimeId)) { throw new Exception('Runtime not found. Please create the runtime.', 404); } diff --git a/src/Executor/Executor.php b/src/Executor/Executor.php index ba6d67df04..4ca1704705 100644 --- a/src/Executor/Executor.php +++ b/src/Executor/Executor.php @@ -4,7 +4,6 @@ namespace Executor; use Exception; use Utopia\App; -use Swoole\Table; class Executor { @@ -19,7 +18,6 @@ class Executor public const METHOD_TRACE = 'TRACE'; private $endpoint; - private $runtimeQueue; private $selfSigned = false; @@ -33,9 +31,6 @@ class Executor throw new Exception('Unsupported endpoint'); } $this->endpoint = $endpoint; - $this->runtimeQueue = new Table(1024); - $this->runtimeQueue->column('id', Table::TYPE_STRING, 128); - $this->runtimeQueue->column('state', Table::TYPE_STRING, 128); } /** @@ -87,11 +82,6 @@ class Executor 'commands' => $commands ]; - $this->runtimeQueue->set($params['runtimeId'], [ - 'id' => $params['runtimeId'], - 'state' => 'pending' - ]); - $timeout = (int) App::getEnv('_APP_FUNCTIONS_BUILD_TIMEOUT', 900); $response = $this->call(self::METHOD_POST, $route, $headers, $params, true, $timeout); @@ -174,25 +164,15 @@ class Executor /* Add 2 seconds as a buffer to the actual timeout value since there can be a slight variance*/ $requestTimeout = $timeout + 2; - $response = $this->call(self::METHOD_POST, $route, $headers, $params, true, $requestTimeout); - $status = $response['headers']['status-code']; - for ($attempts = 0; $attempts < 10; $attempts++) { + $response = $this->call(self::METHOD_POST, $route, $headers, $params, true, $requestTimeout); + $status = $response['headers']['status-code']; + try { switch (true) { case $status < 400: return $response['body']; case $status === 404: - if ($this->runtimeQueue->get($params['runtimeId'])) { - if ($this->runtimeQueue->get($params['runtimeId'])['state'] === 'pending') { - sleep(1); - continue 2; - } - } - $this->runtimeQueue->set($params['runtimeId'], [ - 'id' => $params['runtimeId'], - 'state' => 'pending' - ]); $response = $this->createRuntime( deploymentId: $deploymentId, projectId: $projectId, @@ -205,6 +185,12 @@ class Executor ); $response = $this->call(self::METHOD_POST, $route, $headers, $params, true, $requestTimeout); $status = $response['headers']['status-code']; + + // 500 usually means that the runtime is being created but is not ready, retry. + if ($status == 500) { + continue 2; + } + break; case $status === 406: $response = $this->call(self::METHOD_POST, $route, $headers, $params, true, $requestTimeout);