mirror of
https://github.com/appwrite/appwrite.git
synced 2026-05-26 13:51:13 +00:00
Use orchestrator PHP SDK for builds
This commit is contained in:
+8
-2
@@ -96,7 +96,8 @@
|
||||
"spomky-labs/otphp": "11.*",
|
||||
"webonyx/graphql-php": "15.32.*",
|
||||
"league/csv": "9.14.*",
|
||||
"enshrined/svg-sanitize": "0.22.*"
|
||||
"enshrined/svg-sanitize": "0.22.*",
|
||||
"open-runtimes/orchestrator-client-php": "dev-add-jobs-sdk"
|
||||
},
|
||||
"require-dev": {
|
||||
"ext-fileinfo": "*",
|
||||
@@ -119,5 +120,10 @@
|
||||
"php-http/discovery": true,
|
||||
"tbachert/spi": true
|
||||
}
|
||||
}
|
||||
},
|
||||
"repositories": [{
|
||||
"name": "open-runtimes-orchestrator-client-php",
|
||||
"type": "vcs",
|
||||
"url": "https://github.com/open-runtimes/orchestrator-client-php"
|
||||
}]
|
||||
}
|
||||
|
||||
Generated
+76
-2
@@ -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": "597066d71be48add0c649828d820a505",
|
||||
"content-hash": "585b14725484cb2786ecad186f6284da",
|
||||
"packages": [
|
||||
{
|
||||
"name": "adhocore/jwt",
|
||||
@@ -1224,6 +1224,78 @@
|
||||
],
|
||||
"time": "2023-11-08T09:30:43+00:00"
|
||||
},
|
||||
{
|
||||
"name": "open-runtimes/orchestrator-client-php",
|
||||
"version": "dev-add-jobs-sdk",
|
||||
"source": {
|
||||
"type": "git",
|
||||
"url": "https://github.com/open-runtimes/orchestrator-client-php.git",
|
||||
"reference": "5b44ad8f056d180e63368f844d01d167f706b13e"
|
||||
},
|
||||
"dist": {
|
||||
"type": "zip",
|
||||
"url": "https://api.github.com/repos/open-runtimes/orchestrator-client-php/zipball/5b44ad8f056d180e63368f844d01d167f706b13e",
|
||||
"reference": "5b44ad8f056d180e63368f844d01d167f706b13e",
|
||||
"shasum": ""
|
||||
},
|
||||
"require": {
|
||||
"ext-curl": "*",
|
||||
"ext-json": "*",
|
||||
"php": ">=8.3",
|
||||
"utopia-php/fetch": "^1.1"
|
||||
},
|
||||
"require-dev": {
|
||||
"laravel/pint": "^1.22",
|
||||
"phpstan/phpstan": "^2.1",
|
||||
"phpunit/phpunit": "^13.1",
|
||||
"rector/rector": "^2.4"
|
||||
},
|
||||
"type": "library",
|
||||
"autoload": {
|
||||
"psr-4": {
|
||||
"OpenRuntimes\\Orchestrator\\": "src/"
|
||||
}
|
||||
},
|
||||
"autoload-dev": {
|
||||
"psr-4": {
|
||||
"OpenRuntimes\\Orchestrator\\Tests\\": "tests/"
|
||||
}
|
||||
},
|
||||
"scripts": {
|
||||
"format": [
|
||||
"vendor/bin/pint"
|
||||
],
|
||||
"format:check": [
|
||||
"vendor/bin/pint --test"
|
||||
],
|
||||
"analyze": [
|
||||
"vendor/bin/phpstan analyze --memory-limit=512M"
|
||||
],
|
||||
"refactor": [
|
||||
"vendor/bin/rector process"
|
||||
],
|
||||
"refactor:check": [
|
||||
"vendor/bin/rector process --dry-run"
|
||||
],
|
||||
"test": [
|
||||
"vendor/bin/phpunit"
|
||||
],
|
||||
"fix": [
|
||||
"@refactor",
|
||||
"@analyze",
|
||||
"@format"
|
||||
]
|
||||
},
|
||||
"license": [
|
||||
"MIT"
|
||||
],
|
||||
"description": "PHP SDK for the Open Runtimes orchestrator Jobs API.",
|
||||
"support": {
|
||||
"source": "https://github.com/open-runtimes/orchestrator-client-php/tree/add-jobs-sdk",
|
||||
"issues": "https://github.com/open-runtimes/orchestrator-client-php/issues"
|
||||
},
|
||||
"time": "2026-05-22T18:46:15+00:00"
|
||||
},
|
||||
{
|
||||
"name": "open-telemetry/api",
|
||||
"version": "1.9.0",
|
||||
@@ -8550,7 +8622,9 @@
|
||||
],
|
||||
"aliases": [],
|
||||
"minimum-stability": "dev",
|
||||
"stability-flags": {},
|
||||
"stability-flags": {
|
||||
"open-runtimes/orchestrator-client-php": 20
|
||||
},
|
||||
"prefer-stable": true,
|
||||
"prefer-lowest": false,
|
||||
"platform": {
|
||||
|
||||
@@ -4,6 +4,11 @@ namespace Appwrite\Builds;
|
||||
|
||||
use Executor\Exception as ExecutorException;
|
||||
use Executor\Exception\Timeout as ExecutorTimeout;
|
||||
use OpenRuntimes\Orchestrator\Client as OrchestratorSdkClient;
|
||||
use OpenRuntimes\Orchestrator\DTO\JobRequest;
|
||||
use OpenRuntimes\Orchestrator\Exception\ApiException as OrchestratorApiException;
|
||||
use OpenRuntimes\Orchestrator\Exception\OrchestratorException;
|
||||
use OpenRuntimes\Orchestrator\Exception\TimeoutException as OrchestratorTimeout;
|
||||
use Utopia\System\System;
|
||||
|
||||
class OrchestratorClient
|
||||
@@ -17,59 +22,46 @@ class OrchestratorClient
|
||||
$this->apiKey = System::getEnv('_APP_ORCHESTRATOR_API_KEY', '');
|
||||
}
|
||||
|
||||
public function createJob(array $payload, int $timeout): array
|
||||
public function createJob(JobRequest $request, int $timeout): array
|
||||
{
|
||||
return $this->call('POST', '/v1/jobs', $payload, $timeout);
|
||||
try {
|
||||
$response = $this->client()->jobs()->create($request, $timeout);
|
||||
|
||||
return [
|
||||
'id' => $response->id,
|
||||
'status' => $response->status->value,
|
||||
];
|
||||
} catch (OrchestratorTimeout $e) {
|
||||
throw new ExecutorTimeout($e->getMessage(), $e->timeoutSeconds, previous: $e);
|
||||
} catch (OrchestratorApiException $e) {
|
||||
throw new ExecutorException($e->body !== '' ? $e->body : $e->getMessage(), $e->statusCode, $e);
|
||||
} catch (OrchestratorException $e) {
|
||||
throw new ExecutorException($e->getMessage(), $e->getCode(), $e);
|
||||
}
|
||||
}
|
||||
|
||||
public function deleteJob(string $jobId): void
|
||||
{
|
||||
$this->call('DELETE', '/v1/jobs/' . \rawurlencode($jobId), [], 30);
|
||||
try {
|
||||
$this->client()->jobs()->delete($jobId);
|
||||
} catch (OrchestratorTimeout $e) {
|
||||
throw new ExecutorTimeout($e->getMessage(), $e->timeoutSeconds, previous: $e);
|
||||
} catch (OrchestratorApiException $e) {
|
||||
throw new ExecutorException($e->body !== '' ? $e->body : $e->getMessage(), $e->statusCode, $e);
|
||||
} catch (OrchestratorException $e) {
|
||||
throw new ExecutorException($e->getMessage(), $e->getCode(), $e);
|
||||
}
|
||||
}
|
||||
|
||||
private function call(string $method, string $path, array $payload, int $timeout): array
|
||||
private function client(): OrchestratorSdkClient
|
||||
{
|
||||
if (empty($this->endpoint)) {
|
||||
throw new ExecutorException('Orchestrator host is not configured');
|
||||
}
|
||||
|
||||
$headers = ['content-type: application/json'];
|
||||
if (!empty($this->apiKey)) {
|
||||
$headers[] = 'authorization: Bearer ' . $this->apiKey;
|
||||
}
|
||||
|
||||
$ch = \curl_init($this->endpoint . $path);
|
||||
\curl_setopt($ch, CURLOPT_CUSTOMREQUEST, $method);
|
||||
\curl_setopt($ch, CURLOPT_FOLLOWLOCATION, true);
|
||||
\curl_setopt($ch, CURLOPT_HTTPHEADER, $headers);
|
||||
\curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
|
||||
\curl_setopt($ch, CURLOPT_TIMEOUT, $timeout);
|
||||
|
||||
if ($method !== 'GET' && $method !== 'DELETE') {
|
||||
\curl_setopt($ch, CURLOPT_POSTFIELDS, \json_encode($payload));
|
||||
}
|
||||
|
||||
$body = \curl_exec($ch);
|
||||
$status = \curl_getinfo($ch, CURLINFO_HTTP_CODE);
|
||||
$error = \curl_errno($ch);
|
||||
$errorMessage = \curl_error($ch);
|
||||
|
||||
if ($error) {
|
||||
if ($error === CURLE_OPERATION_TIMEDOUT) {
|
||||
throw new ExecutorTimeout('Orchestrator request timed out', $timeout);
|
||||
}
|
||||
throw new ExecutorException($errorMessage, $status);
|
||||
}
|
||||
|
||||
if ($status >= 400) {
|
||||
throw new ExecutorException(\is_string($body) ? $body : 'Orchestrator request failed', $status);
|
||||
}
|
||||
|
||||
if (empty($body)) {
|
||||
return [];
|
||||
}
|
||||
|
||||
$decoded = \json_decode((string) $body, true);
|
||||
return \is_array($decoded) ? $decoded : [];
|
||||
return new OrchestratorSdkClient(
|
||||
endpoint: $this->endpoint,
|
||||
apiKey: $this->apiKey !== '' ? $this->apiKey : null,
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -21,6 +21,12 @@ use Appwrite\Vcs\Comment;
|
||||
use Exception;
|
||||
use Executor\Exception\Timeout as ExecutorTimeout;
|
||||
use Executor\Executor;
|
||||
use OpenRuntimes\Orchestrator\DTO\Artifact\ArchiveArtifact;
|
||||
use OpenRuntimes\Orchestrator\DTO\Artifact\DownloadArtifact;
|
||||
use OpenRuntimes\Orchestrator\DTO\Artifact\UploadArtifact;
|
||||
use OpenRuntimes\Orchestrator\DTO\Callback;
|
||||
use OpenRuntimes\Orchestrator\DTO\JobRequest;
|
||||
use OpenRuntimes\Orchestrator\Enum\CallbackEvent;
|
||||
use Swoole\Coroutine as Co;
|
||||
use Utopia\Cache\Cache;
|
||||
use Utopia\Config\Config;
|
||||
@@ -1386,65 +1392,55 @@ class Builds extends Action
|
||||
$environment['OPEN_RUNTIMES_OUTPUT_DIRECTORY'] = $outputDirectory;
|
||||
}
|
||||
|
||||
$encodedSourceToken = \rawurlencode($sourceToken);
|
||||
$sourceUrl = "{$base}/{$resourcePath}/{$resourceId}/deployments/{$deploymentId}/artifacts/source?{$projectQuery}&token={$encodedSourceToken}";
|
||||
$artifacts = [
|
||||
[
|
||||
'id' => 'source',
|
||||
'type' => 'download',
|
||||
'in' => "{$base}/{$resourcePath}/{$resourceId}/deployments/{$deploymentId}/artifacts/source?{$projectQuery}&token=" . \rawurlencode($sourceToken),
|
||||
'out' => 'code.tar.gz',
|
||||
'headers' => $appwriteProjectHeader,
|
||||
],
|
||||
new DownloadArtifact('source', $sourceUrl, 'code.tar.gz', headers: $appwriteProjectHeader),
|
||||
];
|
||||
|
||||
if ($version === 'v2') {
|
||||
$artifacts[] = [
|
||||
'id' => 'build',
|
||||
'type' => 'archive',
|
||||
'in' => 'build-output',
|
||||
'out' => 'build.tar.gz',
|
||||
'format' => 'tar.gz',
|
||||
'depends' => 'job',
|
||||
];
|
||||
$artifacts[] = new ArchiveArtifact('build', 'build-output', 'build.tar.gz', depends: 'job');
|
||||
}
|
||||
|
||||
$artifacts[] = [
|
||||
'id' => 'upload',
|
||||
'type' => 'upload',
|
||||
'in' => 'build.tar.gz',
|
||||
'out' => "{$base}/{$resourcePath}/{$resourceId}/deployments/{$deploymentId}/artifacts/build?{$projectQuery}&token=" . \rawurlencode($buildToken),
|
||||
'depends' => $version === 'v2' ? 'build' : 'job',
|
||||
'headers' => $appwriteProjectHeader,
|
||||
'chunked' => true,
|
||||
];
|
||||
$encodedBuildToken = \rawurlencode($buildToken);
|
||||
$buildUrl = "{$base}/{$resourcePath}/{$resourceId}/deployments/{$deploymentId}/artifacts/build?{$projectQuery}&token={$encodedBuildToken}";
|
||||
$artifacts[] = new UploadArtifact(
|
||||
'upload',
|
||||
'build.tar.gz',
|
||||
$buildUrl,
|
||||
depends: $version === 'v2' ? 'build' : 'job',
|
||||
headers: $appwriteProjectHeader,
|
||||
chunked: true,
|
||||
);
|
||||
|
||||
$client = new OrchestratorClient();
|
||||
$client->createJob([
|
||||
'id' => $jobId,
|
||||
'meta' => [
|
||||
$client->createJob(new JobRequest(
|
||||
id: $jobId,
|
||||
meta: [
|
||||
'projectId' => $project->getId(),
|
||||
'resourceId' => $resourceId,
|
||||
'resourceType' => $resource->getCollection(),
|
||||
'deploymentId' => $deploymentId,
|
||||
],
|
||||
'image' => $runtime['image'],
|
||||
'command' => $buildCommand,
|
||||
'cpu' => $jobCpus,
|
||||
'memory' => $memory,
|
||||
'timeoutSeconds' => $timeout,
|
||||
'workspace' => '/tmp',
|
||||
'environment' => $environment,
|
||||
'artifacts' => $artifacts,
|
||||
'callback' => [
|
||||
'url' => "{$callbackBase}/{$resourcePath}/{$resourceId}/deployments/{$deploymentId}/events?{$projectQuery}",
|
||||
'key' => System::getEnv('_APP_ORCHESTRATOR_CALLBACK_SECRET', System::getEnv('_APP_OPENSSL_KEY_V1', '')),
|
||||
'headers' => $appwriteProjectHeader,
|
||||
'events' => [
|
||||
'orchestrator.job.log',
|
||||
'orchestrator.job.artifact',
|
||||
'orchestrator.job.exit',
|
||||
image: (string) $runtime['image'],
|
||||
command: $buildCommand,
|
||||
cpu: $jobCpus,
|
||||
memory: $memory,
|
||||
timeoutSeconds: $timeout,
|
||||
workspace: '/tmp',
|
||||
environment: $environment,
|
||||
artifacts: $artifacts,
|
||||
callback: new Callback(
|
||||
url: "{$callbackBase}/{$resourcePath}/{$resourceId}/deployments/{$deploymentId}/events?{$projectQuery}",
|
||||
events: [
|
||||
CallbackEvent::Log,
|
||||
CallbackEvent::Artifact,
|
||||
CallbackEvent::Exit,
|
||||
],
|
||||
],
|
||||
], $timeout);
|
||||
key: System::getEnv('_APP_ORCHESTRATOR_CALLBACK_SECRET', System::getEnv('_APP_OPENSSL_KEY_V1', '')),
|
||||
headers: $appwriteProjectHeader,
|
||||
),
|
||||
), $timeout);
|
||||
}
|
||||
|
||||
protected function applyOrchestratorEvent(
|
||||
|
||||
Reference in New Issue
Block a user