Merge remote-tracking branch 'origin/1.6.x' into chore-16x-specs
This commit is contained in:
commit
70fc5e6676
5 changed files with 192 additions and 25 deletions
|
@ -566,6 +566,12 @@ return [
|
|||
'code' => 404,
|
||||
],
|
||||
|
||||
Exception::EXECUTION_IN_PROGRESS => [
|
||||
'name' => Exception::EXECUTION_IN_PROGRESS,
|
||||
'description' => 'Can\'t delete ongoing execution. Please wait for execution to finish before deleting it.',
|
||||
'code' => 400,
|
||||
],
|
||||
|
||||
/** Databases */
|
||||
Exception::DATABASE_NOT_FOUND => [
|
||||
'name' => Exception::DATABASE_NOT_FOUND,
|
||||
|
|
|
@ -11,6 +11,7 @@ use Appwrite\Event\Validator\FunctionEvent;
|
|||
use Appwrite\Extend\Exception;
|
||||
use Appwrite\Extend\Exception as AppwriteException;
|
||||
use Appwrite\Messaging\Adapter\Realtime;
|
||||
use Appwrite\Platform\Tasks\ScheduleExecutions;
|
||||
use Appwrite\Task\Validator\Cron;
|
||||
use Appwrite\Utopia\Database\Validator\CustomId;
|
||||
use Appwrite\Utopia\Database\Validator\Queries\Deployments;
|
||||
|
@ -1725,7 +1726,7 @@ App::post('/v1/functions/:functionId/executions')
|
|||
'deploymentInternalId' => $deployment->getInternalId(),
|
||||
'deploymentId' => $deployment->getId(),
|
||||
'trigger' => (!is_null($scheduledAt)) ? 'schedule' : 'http',
|
||||
'status' => $status, // waiting / processing / completed / failed
|
||||
'status' => $status, // waiting / processing / completed / failed / scheduled
|
||||
'responseStatusCode' => 0,
|
||||
'responseHeaders' => [],
|
||||
'requestPath' => $path,
|
||||
|
@ -1771,7 +1772,7 @@ App::post('/v1/functions/:functionId/executions')
|
|||
|
||||
$dbForConsole->createDocument('schedules', new Document([
|
||||
'region' => System::getEnv('_APP_REGION', 'default'),
|
||||
'resourceType' => 'execution',
|
||||
'resourceType' => ScheduleExecutions::getSupportedResource(),
|
||||
'resourceId' => $execution->getId(),
|
||||
'resourceInternalId' => $execution->getInternalId(),
|
||||
'resourceUpdatedAt' => DateTime::now(),
|
||||
|
@ -2040,6 +2041,74 @@ App::get('/v1/functions/:functionId/executions/:executionId')
|
|||
$response->dynamic($execution, Response::MODEL_EXECUTION);
|
||||
});
|
||||
|
||||
App::delete('/v1/functions/:functionId/executions/:executionId')
|
||||
->groups(['api', 'functions'])
|
||||
->desc('Delete execution')
|
||||
->label('scope', 'execution.write')
|
||||
->label('event', 'functions.[functionId].executions.[executionId].delete')
|
||||
->label('audits.event', 'executions.delete')
|
||||
->label('audits.resource', 'function/{request.functionId}')
|
||||
->label('sdk.auth', [APP_AUTH_TYPE_KEY])
|
||||
->label('sdk.namespace', 'functions')
|
||||
->label('sdk.method', 'deleteExecution')
|
||||
->label('sdk.description', '/docs/references/functions/delete-execution.md')
|
||||
->label('sdk.response.code', Response::STATUS_CODE_NOCONTENT)
|
||||
->label('sdk.response.model', Response::MODEL_NONE)
|
||||
->param('functionId', '', new UID(), 'Function ID.')
|
||||
->param('executionId', '', new UID(), 'Execution ID.')
|
||||
->inject('response')
|
||||
->inject('dbForProject')
|
||||
->inject('dbForConsole')
|
||||
->inject('queueForEvents')
|
||||
->action(function (string $functionId, string $executionId, Response $response, Database $dbForProject, Database $dbForConsole, Event $queueForEvents) {
|
||||
$function = $dbForProject->getDocument('functions', $functionId);
|
||||
|
||||
if ($function->isEmpty()) {
|
||||
throw new Exception(Exception::FUNCTION_NOT_FOUND);
|
||||
}
|
||||
|
||||
$execution = $dbForProject->getDocument('executions', $executionId);
|
||||
if ($execution->isEmpty()) {
|
||||
throw new Exception(Exception::EXECUTION_NOT_FOUND);
|
||||
}
|
||||
|
||||
if ($execution->getAttribute('functionId') !== $function->getId()) {
|
||||
throw new Exception(Exception::EXECUTION_NOT_FOUND);
|
||||
}
|
||||
$status = $execution->getAttribute('status');
|
||||
|
||||
if (!in_array($status, ['completed', 'failed', 'scheduled'])) {
|
||||
throw new Exception(Exception::EXECUTION_IN_PROGRESS);
|
||||
}
|
||||
|
||||
if (!$dbForProject->deleteDocument('executions', $execution->getId())) {
|
||||
throw new Exception(Exception::GENERAL_SERVER_ERROR, 'Failed to remove execution from DB');
|
||||
}
|
||||
|
||||
if ($status === 'scheduled') {
|
||||
$schedule = $dbForConsole->findOne('schedules', [
|
||||
Query::equal('resourceId', [$execution->getId()]),
|
||||
Query::equal('resourceType', [ScheduleExecutions::getSupportedResource()]),
|
||||
Query::equal('active', [true]),
|
||||
]);
|
||||
|
||||
if ($schedule && !$schedule->isEmpty()) {
|
||||
$schedule
|
||||
->setAttribute('resourceUpdatedAt', DateTime::now())
|
||||
->setAttribute('active', false);
|
||||
|
||||
Authorization::skip(fn () => $dbForConsole->updateDocument('schedules', $schedule->getId(), $schedule));
|
||||
}
|
||||
}
|
||||
|
||||
$queueForEvents
|
||||
->setParam('functionId', $function->getId())
|
||||
->setParam('executionId', $execution->getId())
|
||||
->setPayload($response->output($execution, Response::MODEL_EXECUTION));
|
||||
|
||||
$response->noContent();
|
||||
});
|
||||
|
||||
// Variables
|
||||
|
||||
App::post('/v1/functions/:functionId/variables')
|
||||
|
|
1
docs/references/functions/delete-execution.md
Normal file
1
docs/references/functions/delete-execution.md
Normal file
|
@ -0,0 +1 @@
|
|||
Delete a function execution by its unique ID.
|
|
@ -168,6 +168,7 @@ class Exception extends \Exception
|
|||
|
||||
/** Execution */
|
||||
public const EXECUTION_NOT_FOUND = 'execution_not_found';
|
||||
public const EXECUTION_IN_PROGRESS = 'execution_in_progress';
|
||||
|
||||
/** Databases */
|
||||
public const DATABASE_NOT_FOUND = 'database_not_found';
|
||||
|
|
|
@ -454,7 +454,6 @@ class FunctionsCustomServerTest extends Scope
|
|||
|
||||
$this->assertEquals(200, $functionDetails['headers']['status-code']);
|
||||
$this->assertEquals('cli', $functionDetails['body']['type']);
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -671,12 +670,16 @@ class FunctionsCustomServerTest extends Scope
|
|||
/**
|
||||
* Test search queries
|
||||
*/
|
||||
$function = $this->client->call(Client::METHOD_GET, '/functions/' . $data['functionId'] . '/deployments', array_merge([
|
||||
$function = $this->client->call(
|
||||
Client::METHOD_GET,
|
||||
'/functions/' . $data['functionId'] . '/deployments',
|
||||
array_merge([
|
||||
'content-type' => 'application/json',
|
||||
'x-appwrite-project' => $this->getProject()['$id'],
|
||||
], $this->getHeaders(), [
|
||||
'search' => $data['functionId']
|
||||
]));
|
||||
])
|
||||
);
|
||||
|
||||
$this->assertEquals($function['headers']['status-code'], 200);
|
||||
$this->assertEquals(3, $function['body']['total']);
|
||||
|
@ -732,12 +735,16 @@ class FunctionsCustomServerTest extends Scope
|
|||
$this->assertEquals($function['headers']['status-code'], 200);
|
||||
$this->assertCount(0, $function['body']['deployments']);
|
||||
|
||||
$function = $this->client->call(Client::METHOD_GET, '/functions/' . $data['functionId'] . '/deployments', array_merge([
|
||||
$function = $this->client->call(
|
||||
Client::METHOD_GET,
|
||||
'/functions/' . $data['functionId'] . '/deployments',
|
||||
array_merge([
|
||||
'content-type' => 'application/json',
|
||||
'x-appwrite-project' => $this->getProject()['$id'],
|
||||
], $this->getHeaders(), [
|
||||
'search' => 'Test'
|
||||
]));
|
||||
])
|
||||
);
|
||||
|
||||
$this->assertEquals($function['headers']['status-code'], 200);
|
||||
$this->assertEquals(3, $function['body']['total']);
|
||||
|
@ -745,12 +752,16 @@ class FunctionsCustomServerTest extends Scope
|
|||
$this->assertCount(3, $function['body']['deployments']);
|
||||
$this->assertEquals($function['body']['deployments'][0]['$id'], $data['deploymentId']);
|
||||
|
||||
$function = $this->client->call(Client::METHOD_GET, '/functions/' . $data['functionId'] . '/deployments', array_merge([
|
||||
$function = $this->client->call(
|
||||
Client::METHOD_GET,
|
||||
'/functions/' . $data['functionId'] . '/deployments',
|
||||
array_merge([
|
||||
'content-type' => 'application/json',
|
||||
'x-appwrite-project' => $this->getProject()['$id'],
|
||||
], $this->getHeaders(), [
|
||||
'search' => 'php-8.0'
|
||||
]));
|
||||
])
|
||||
);
|
||||
|
||||
$this->assertEquals($function['headers']['status-code'], 200);
|
||||
$this->assertEquals(3, $function['body']['total']);
|
||||
|
@ -977,6 +988,85 @@ class FunctionsCustomServerTest extends Scope
|
|||
return $data;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* @depends testGetExecution
|
||||
*/
|
||||
public function testDeleteExecution($data): array
|
||||
{
|
||||
/**
|
||||
* Test for SUCCESS
|
||||
*/
|
||||
$execution = $this->client->call(Client::METHOD_DELETE, '/functions/' . $data['functionId'] . '/executions/' . $data['executionId'], array_merge([
|
||||
'content-type' => 'application/json',
|
||||
'x-appwrite-project' => $this->getProject()['$id'],
|
||||
], $this->getHeaders()));
|
||||
|
||||
$this->assertEquals(204, $execution['headers']['status-code']);
|
||||
$this->assertEmpty($execution['body']);
|
||||
|
||||
$execution = $this->client->call(Client::METHOD_DELETE, '/functions/' . $data['functionId'] . '/executions/' . $data['executionId'], array_merge([
|
||||
'content-type' => 'application/json',
|
||||
'x-appwrite-project' => $this->getProject()['$id'],
|
||||
], $this->getHeaders()));
|
||||
|
||||
$this->assertEquals(404, $execution['headers']['status-code']);
|
||||
$this->assertStringContainsString('Execution with the requested ID could not be found', $execution['body']['message']);
|
||||
|
||||
/**
|
||||
* Test for FAILURE
|
||||
*/
|
||||
$execution = $this->client->call(Client::METHOD_POST, '/functions/' . $data['functionId'] . '/executions', array_merge([
|
||||
'content-type' => 'application/json',
|
||||
'x-appwrite-project' => $this->getProject()['$id'],
|
||||
], $this->getHeaders()), [
|
||||
'async' => true,
|
||||
]);
|
||||
|
||||
$executionId = $execution['body']['$id'] ?? '';
|
||||
$this->assertEquals(202, $execution['headers']['status-code']);
|
||||
|
||||
$execution = $this->client->call(Client::METHOD_DELETE, '/functions/' . $data['functionId'] . '/executions/' . $executionId, array_merge([
|
||||
'content-type' => 'application/json',
|
||||
'x-appwrite-project' => $this->getProject()['$id'],
|
||||
], $this->getHeaders()));
|
||||
|
||||
$this->assertEquals(400, $execution['headers']['status-code']);
|
||||
$this->assertStringContainsString('execution_in_progress', $execution['body']['type']);
|
||||
$this->assertStringContainsString('Can\'t delete ongoing execution.', $execution['body']['message']);
|
||||
|
||||
return $data;
|
||||
}
|
||||
|
||||
/**
|
||||
* @depends testGetExecution
|
||||
*/
|
||||
public function testDeleteScheduledExecution($data): array
|
||||
{
|
||||
$futureTime = (new \DateTime())->add(new \DateInterval('PT10H'))->format('Y-m-d H:i:s');
|
||||
|
||||
$execution = $this->client->call(Client::METHOD_POST, '/functions/' . $data['functionId'] . '/executions', array_merge([
|
||||
'content-type' => 'application/json',
|
||||
'x-appwrite-project' => $this->getProject()['$id'],
|
||||
], $this->getHeaders()), [
|
||||
'async' => true,
|
||||
'scheduledAt' => $futureTime,
|
||||
]);
|
||||
|
||||
$executionId = $execution['body']['$id'] ?? '';
|
||||
$this->assertEquals(202, $execution['headers']['status-code']);
|
||||
sleep(5);
|
||||
$execution = $this->client->call(Client::METHOD_DELETE, '/functions/' . $data['functionId'] . '/executions/' . $executionId, array_merge([
|
||||
'content-type' => 'application/json',
|
||||
'x-appwrite-project' => $this->getProject()['$id'],
|
||||
], $this->getHeaders()));
|
||||
|
||||
$this->assertEquals(204, $execution['headers']['status-code']);
|
||||
$this->assertEmpty($execution['body']);
|
||||
|
||||
return $data;
|
||||
}
|
||||
|
||||
/**
|
||||
* @depends testGetExecution
|
||||
*/
|
||||
|
|
Loading…
Reference in a new issue