2023-10-01 17:39:26 +00:00
|
|
|
<?php
|
|
|
|
|
|
|
|
|
|
namespace Appwrite\Platform\Workers;
|
|
|
|
|
|
2025-01-30 02:23:39 +00:00
|
|
|
use Ahc\Jwt\JWT;
|
2025-02-11 04:03:02 +00:00
|
|
|
use Appwrite\Event\Realtime;
|
2024-03-06 17:34:21 +00:00
|
|
|
use Exception;
|
2023-10-01 17:39:26 +00:00
|
|
|
use Utopia\CLI\Console;
|
2024-07-28 06:27:18 +00:00
|
|
|
use Utopia\Config\Config;
|
2023-10-01 17:39:26 +00:00
|
|
|
use Utopia\Database\Database;
|
2024-03-06 17:34:21 +00:00
|
|
|
use Utopia\Database\Document;
|
|
|
|
|
use Utopia\Database\Exception\Authorization;
|
|
|
|
|
use Utopia\Database\Exception\Conflict;
|
|
|
|
|
use Utopia\Database\Exception\Restricted;
|
|
|
|
|
use Utopia\Database\Exception\Structure;
|
2024-05-28 16:59:54 +00:00
|
|
|
use Utopia\Migration\Destination;
|
|
|
|
|
use Utopia\Migration\Destinations\Appwrite as DestinationAppwrite;
|
2024-03-06 17:34:21 +00:00
|
|
|
use Utopia\Migration\Exception as MigrationException;
|
2023-10-01 17:39:26 +00:00
|
|
|
use Utopia\Migration\Source;
|
2024-06-19 10:26:52 +00:00
|
|
|
use Utopia\Migration\Sources\Appwrite as SourceAppwrite;
|
2025-04-16 06:25:04 +00:00
|
|
|
use Utopia\Migration\Sources\CSV;
|
2023-10-01 17:39:26 +00:00
|
|
|
use Utopia\Migration\Sources\Firebase;
|
|
|
|
|
use Utopia\Migration\Sources\NHost;
|
|
|
|
|
use Utopia\Migration\Sources\Supabase;
|
|
|
|
|
use Utopia\Migration\Transfer;
|
2024-03-06 17:34:21 +00:00
|
|
|
use Utopia\Platform\Action;
|
|
|
|
|
use Utopia\Queue\Message;
|
2025-04-09 11:05:27 +00:00
|
|
|
use Utopia\Storage\Device;
|
2025-01-30 02:23:39 +00:00
|
|
|
use Utopia\System\System;
|
2023-10-01 17:39:26 +00:00
|
|
|
|
|
|
|
|
class Migrations extends Action
|
|
|
|
|
{
|
2024-05-28 17:37:37 +00:00
|
|
|
protected Database $dbForProject;
|
2024-07-28 06:29:02 +00:00
|
|
|
|
2024-12-12 10:30:26 +00:00
|
|
|
protected Database $dbForPlatform;
|
2024-07-28 06:29:02 +00:00
|
|
|
|
2025-04-17 03:24:50 +00:00
|
|
|
protected Device $deviceForImports;
|
2025-04-09 11:05:27 +00:00
|
|
|
|
2024-05-28 17:37:37 +00:00
|
|
|
protected Document $project;
|
2023-10-01 17:39:26 +00:00
|
|
|
|
2025-05-01 05:52:19 +00:00
|
|
|
/**
|
2025-05-01 06:01:51 +00:00
|
|
|
* Cached for performance.
|
2025-05-01 05:52:19 +00:00
|
|
|
*
|
2025-05-01 06:01:51 +00:00
|
|
|
* @var array<string, int>
|
2025-05-01 05:52:19 +00:00
|
|
|
*/
|
2025-05-01 06:46:07 +00:00
|
|
|
protected array $sourceReport = [];
|
2025-05-01 05:52:19 +00:00
|
|
|
|
2025-03-17 06:21:31 +00:00
|
|
|
/**
|
|
|
|
|
* @var callable
|
|
|
|
|
*/
|
2024-11-13 01:29:43 +00:00
|
|
|
protected $logError;
|
2024-11-12 02:29:19 +00:00
|
|
|
|
2023-10-01 17:39:26 +00:00
|
|
|
public static function getName(): string
|
|
|
|
|
{
|
|
|
|
|
return 'migrations';
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* @throws Exception
|
|
|
|
|
*/
|
|
|
|
|
public function __construct()
|
|
|
|
|
{
|
|
|
|
|
$this
|
|
|
|
|
->desc('Migrations worker')
|
|
|
|
|
->inject('message')
|
2025-01-16 06:05:22 +00:00
|
|
|
->inject('project')
|
2023-10-17 03:44:36 +00:00
|
|
|
->inject('dbForProject')
|
2024-12-12 10:30:26 +00:00
|
|
|
->inject('dbForPlatform')
|
2024-11-13 01:29:43 +00:00
|
|
|
->inject('logError')
|
2025-02-11 04:03:02 +00:00
|
|
|
->inject('queueForRealtime')
|
2025-04-17 03:24:50 +00:00
|
|
|
->inject('deviceForImports')
|
2025-03-12 09:54:52 +00:00
|
|
|
->callback([$this, 'action']);
|
2023-10-01 17:39:26 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* @throws Exception
|
|
|
|
|
*/
|
2025-04-17 03:24:50 +00:00
|
|
|
public function action(Message $message, Document $project, Database $dbForProject, Database $dbForPlatform, callable $logError, Realtime $queueForRealtime, Device $deviceForImports): void
|
2023-10-01 17:39:26 +00:00
|
|
|
{
|
|
|
|
|
$payload = $message->getPayload() ?? [];
|
2025-04-17 03:24:50 +00:00
|
|
|
$this->deviceForImports = $deviceForImports;
|
2023-10-01 17:39:26 +00:00
|
|
|
|
|
|
|
|
if (empty($payload)) {
|
|
|
|
|
throw new Exception('Missing payload');
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
$events = $payload['events'] ?? [];
|
|
|
|
|
$migration = new Document($payload['migration'] ?? []);
|
|
|
|
|
|
|
|
|
|
if ($project->getId() === 'console') {
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
|
2023-10-17 03:44:36 +00:00
|
|
|
$this->dbForProject = $dbForProject;
|
2024-12-12 10:30:26 +00:00
|
|
|
$this->dbForPlatform = $dbForPlatform;
|
2024-05-28 17:37:37 +00:00
|
|
|
$this->project = $project;
|
2024-11-13 01:29:43 +00:00
|
|
|
$this->logError = $logError;
|
2023-10-01 17:39:26 +00:00
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* Handle Event execution.
|
|
|
|
|
*/
|
|
|
|
|
if (! empty($events)) {
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
|
2025-02-11 04:03:02 +00:00
|
|
|
$this->processMigration($migration, $queueForRealtime);
|
2023-10-01 17:39:26 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* @throws Exception
|
|
|
|
|
*/
|
2024-06-19 08:45:07 +00:00
|
|
|
protected function processSource(Document $migration): Source
|
2023-10-01 17:39:26 +00:00
|
|
|
{
|
2024-06-19 08:45:07 +00:00
|
|
|
$source = $migration->getAttribute('source');
|
2025-04-09 11:05:27 +00:00
|
|
|
$resourceId = $migration->getAttribute('resourceId');
|
2024-06-19 08:45:07 +00:00
|
|
|
$credentials = $migration->getAttribute('credentials');
|
2025-04-14 09:33:30 +00:00
|
|
|
$migrationOptions = $migration->getAttribute('options');
|
2024-06-19 08:45:07 +00:00
|
|
|
|
2025-05-01 05:52:19 +00:00
|
|
|
$migrationSource = match ($source) {
|
2023-10-01 17:39:26 +00:00
|
|
|
Firebase::getName() => new Firebase(
|
|
|
|
|
json_decode($credentials['serviceAccount'], true),
|
|
|
|
|
),
|
|
|
|
|
Supabase::getName() => new Supabase(
|
|
|
|
|
$credentials['endpoint'],
|
|
|
|
|
$credentials['apiKey'],
|
|
|
|
|
$credentials['databaseHost'],
|
|
|
|
|
'postgres',
|
|
|
|
|
$credentials['username'],
|
|
|
|
|
$credentials['password'],
|
|
|
|
|
$credentials['port'],
|
|
|
|
|
),
|
|
|
|
|
NHost::getName() => new NHost(
|
|
|
|
|
$credentials['subdomain'],
|
|
|
|
|
$credentials['region'],
|
|
|
|
|
$credentials['adminSecret'],
|
|
|
|
|
$credentials['database'],
|
|
|
|
|
$credentials['username'],
|
|
|
|
|
$credentials['password'],
|
|
|
|
|
$credentials['port'],
|
|
|
|
|
),
|
2024-05-28 17:12:58 +00:00
|
|
|
SourceAppwrite::getName() => new SourceAppwrite(
|
2024-08-12 08:15:14 +00:00
|
|
|
$credentials['projectId'],
|
2024-10-30 05:23:24 +00:00
|
|
|
$credentials['endpoint'] === 'http://localhost/v1' ? 'http://appwrite/v1' : $credentials['endpoint'],
|
2024-08-12 08:15:14 +00:00
|
|
|
$credentials['apiKey'],
|
2024-05-28 17:05:36 +00:00
|
|
|
),
|
2025-04-16 06:25:04 +00:00
|
|
|
CSV::getName() => new CSV(
|
2025-04-09 11:05:27 +00:00
|
|
|
$resourceId,
|
2025-04-14 09:33:30 +00:00
|
|
|
$migrationOptions['path'],
|
2025-04-17 03:24:50 +00:00
|
|
|
$this->deviceForImports,
|
2025-04-09 12:54:59 +00:00
|
|
|
$this->dbForProject
|
2025-04-09 11:05:27 +00:00
|
|
|
),
|
2023-10-01 17:39:26 +00:00
|
|
|
default => throw new \Exception('Invalid source type'),
|
|
|
|
|
};
|
2025-05-01 05:52:19 +00:00
|
|
|
|
|
|
|
|
$this->sourceReport = $migrationSource->report();
|
|
|
|
|
|
|
|
|
|
return $migrationSource;
|
2023-10-01 17:39:26 +00:00
|
|
|
}
|
|
|
|
|
|
2024-05-28 16:59:54 +00:00
|
|
|
/**
|
|
|
|
|
* @throws Exception
|
|
|
|
|
*/
|
2024-10-30 05:23:24 +00:00
|
|
|
protected function processDestination(Document $migration, string $apiKey): Destination
|
2024-05-28 16:59:54 +00:00
|
|
|
{
|
2024-06-19 08:45:07 +00:00
|
|
|
$destination = $migration->getAttribute('destination');
|
|
|
|
|
|
2024-05-28 16:59:54 +00:00
|
|
|
return match ($destination) {
|
|
|
|
|
DestinationAppwrite::getName() => new DestinationAppwrite(
|
2024-10-30 05:23:24 +00:00
|
|
|
$this->project->getId(),
|
|
|
|
|
'http://appwrite/v1',
|
|
|
|
|
$apiKey,
|
2024-07-28 06:27:18 +00:00
|
|
|
$this->dbForProject,
|
2024-07-28 06:29:02 +00:00
|
|
|
Config::getParam('collections', [])['databases']['collections'],
|
2024-05-28 16:59:54 +00:00
|
|
|
),
|
|
|
|
|
default => throw new \Exception('Invalid destination type'),
|
|
|
|
|
};
|
|
|
|
|
}
|
|
|
|
|
|
2023-10-01 17:39:26 +00:00
|
|
|
/**
|
|
|
|
|
* @throws Authorization
|
|
|
|
|
* @throws Structure
|
|
|
|
|
* @throws Conflict
|
|
|
|
|
* @throws \Utopia\Database\Exception
|
|
|
|
|
* @throws Exception
|
|
|
|
|
*/
|
2025-02-11 04:03:02 +00:00
|
|
|
protected function updateMigrationDocument(Document $migration, Document $project, Realtime $queueForRealtime): Document
|
2023-10-01 17:39:26 +00:00
|
|
|
{
|
2025-06-12 05:13:35 +00:00
|
|
|
$errorMessages = [];
|
|
|
|
|
$clonedMigrationDocument = clone $migration;
|
|
|
|
|
|
|
|
|
|
// we cannot use #sensitive because
|
|
|
|
|
// `errors` is nested which requires an override.
|
|
|
|
|
$errors = $clonedMigrationDocument->getAttribute('errors', []);
|
|
|
|
|
|
|
|
|
|
foreach ($errors as $error) {
|
|
|
|
|
$decoded = json_decode($error, true);
|
|
|
|
|
|
|
|
|
|
if (is_array($decoded) && isset($decoded['trace'])) {
|
|
|
|
|
unset($decoded['trace']);
|
|
|
|
|
$errorMessages[] = json_encode($decoded);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// set the errors back without trace
|
|
|
|
|
$clonedMigrationDocument->setAttribute('errors', $errorMessages);
|
|
|
|
|
|
|
|
|
|
|
2025-02-11 04:03:02 +00:00
|
|
|
/** Trigger Realtime Events */
|
|
|
|
|
$queueForRealtime
|
|
|
|
|
->setProject($project)
|
2025-02-27 07:23:13 +00:00
|
|
|
->setSubscribers(['console', $project->getId()])
|
2025-02-11 04:03:02 +00:00
|
|
|
->setEvent('migrations.[migrationId].update')
|
|
|
|
|
->setParam('migrationId', $migration->getId())
|
2025-06-12 05:13:35 +00:00
|
|
|
->setPayload($clonedMigrationDocument->getArrayCopy(), ['options', 'credentials'])
|
2025-02-11 04:03:02 +00:00
|
|
|
->trigger();
|
2023-10-01 17:39:26 +00:00
|
|
|
|
|
|
|
|
return $this->dbForProject->updateDocument('migrations', $migration->getId(), $migration);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* @throws Exception
|
|
|
|
|
*/
|
2025-01-30 02:23:39 +00:00
|
|
|
protected function generateAPIKey(Document $project): string
|
2023-10-01 17:39:26 +00:00
|
|
|
{
|
2025-01-30 02:23:39 +00:00
|
|
|
$jwt = new JWT(System::getEnv('_APP_OPENSSL_KEY_V1'), 'HS256', 86400, 0);
|
2025-02-11 09:02:20 +00:00
|
|
|
|
2025-01-30 02:23:39 +00:00
|
|
|
$apiKey = $jwt->encode([
|
2023-10-01 17:39:26 +00:00
|
|
|
'projectId' => $project->getId(),
|
2025-02-12 11:19:51 +00:00
|
|
|
'disabledMetrics' => [
|
|
|
|
|
METRIC_DATABASES_OPERATIONS_READS,
|
|
|
|
|
METRIC_DATABASES_OPERATIONS_WRITES,
|
|
|
|
|
METRIC_NETWORK_REQUESTS,
|
|
|
|
|
METRIC_NETWORK_INBOUND,
|
|
|
|
|
METRIC_NETWORK_OUTBOUND,
|
|
|
|
|
],
|
2023-10-01 17:39:26 +00:00
|
|
|
'scopes' => [
|
|
|
|
|
'users.read',
|
|
|
|
|
'users.write',
|
|
|
|
|
'teams.read',
|
|
|
|
|
'teams.write',
|
|
|
|
|
'buckets.read',
|
|
|
|
|
'buckets.write',
|
|
|
|
|
'files.read',
|
|
|
|
|
'files.write',
|
|
|
|
|
'functions.read',
|
|
|
|
|
'functions.write',
|
2025-01-30 03:38:19 +00:00
|
|
|
'databases.read',
|
|
|
|
|
'collections.read',
|
|
|
|
|
'documents.read',
|
2025-02-06 09:55:32 +00:00
|
|
|
'documents.write',
|
|
|
|
|
'tokens.read',
|
|
|
|
|
'tokens.write',
|
2025-02-04 16:56:14 +00:00
|
|
|
]
|
2023-10-01 17:39:26 +00:00
|
|
|
]);
|
|
|
|
|
|
2025-01-30 02:23:39 +00:00
|
|
|
return API_KEY_DYNAMIC . '_' . $apiKey;
|
2023-10-01 17:39:26 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* @throws Authorization
|
|
|
|
|
* @throws Conflict
|
|
|
|
|
* @throws Restricted
|
|
|
|
|
* @throws Structure
|
|
|
|
|
* @throws \Utopia\Database\Exception
|
2024-06-19 09:03:32 +00:00
|
|
|
* @throws Exception
|
2023-10-01 17:39:26 +00:00
|
|
|
*/
|
2025-02-11 04:03:02 +00:00
|
|
|
protected function processMigration(Document $migration, Realtime $queueForRealtime): void
|
2023-10-01 17:39:26 +00:00
|
|
|
{
|
2024-05-28 17:37:37 +00:00
|
|
|
$project = $this->project;
|
2024-12-12 10:30:26 +00:00
|
|
|
$projectDocument = $this->dbForPlatform->getDocument('projects', $project->getId());
|
2023-10-01 17:39:26 +00:00
|
|
|
$tempAPIKey = $this->generateAPIKey($projectDocument);
|
2024-08-08 16:46:44 +00:00
|
|
|
|
2024-06-19 09:03:32 +00:00
|
|
|
$transfer = $source = $destination = null;
|
2023-10-01 17:39:26 +00:00
|
|
|
|
|
|
|
|
try {
|
2024-08-12 08:15:14 +00:00
|
|
|
if (
|
2024-10-30 05:23:24 +00:00
|
|
|
$migration->getAttribute('source') === SourceAppwrite::getName() &&
|
|
|
|
|
empty($migration->getAttribute('credentials', []))
|
2024-08-12 08:15:14 +00:00
|
|
|
) {
|
|
|
|
|
$credentials = $migration->getAttribute('credentials', []);
|
|
|
|
|
|
|
|
|
|
$credentials['projectId'] = $credentials['projectId'] ?? $projectDocument->getId();
|
|
|
|
|
$credentials['endpoint'] = $credentials['endpoint'] ?? 'http://appwrite/v1';
|
2025-01-30 02:23:39 +00:00
|
|
|
$credentials['apiKey'] = $credentials['apiKey'] ?? $tempAPIKey;
|
2024-08-12 08:15:14 +00:00
|
|
|
|
|
|
|
|
$migration->setAttribute('credentials', $credentials);
|
|
|
|
|
}
|
|
|
|
|
|
2024-06-19 09:03:32 +00:00
|
|
|
$migration->setAttribute('stage', 'processing');
|
|
|
|
|
$migration->setAttribute('status', 'processing');
|
2025-02-11 04:03:02 +00:00
|
|
|
$this->updateMigrationDocument($migration, $projectDocument, $queueForRealtime);
|
2023-10-01 17:39:26 +00:00
|
|
|
|
2024-08-08 12:14:43 +00:00
|
|
|
$source = $this->processSource($migration);
|
2025-01-30 02:23:39 +00:00
|
|
|
$destination = $this->processDestination($migration, $tempAPIKey);
|
2023-10-01 17:39:26 +00:00
|
|
|
|
|
|
|
|
$transfer = new Transfer(
|
|
|
|
|
$source,
|
|
|
|
|
$destination
|
|
|
|
|
);
|
|
|
|
|
|
|
|
|
|
/** Start Transfer */
|
2025-06-11 16:41:43 +00:00
|
|
|
if (empty($source->getErrors())) {
|
|
|
|
|
$migration->setAttribute('stage', 'migrating');
|
|
|
|
|
$this->updateMigrationDocument($migration, $projectDocument, $queueForRealtime);
|
|
|
|
|
|
|
|
|
|
$transfer->run(
|
|
|
|
|
$migration->getAttribute('resources'),
|
|
|
|
|
function () use ($migration, $transfer, $projectDocument, $queueForRealtime) {
|
|
|
|
|
$migration->setAttribute('resourceData', json_encode($transfer->getCache()));
|
|
|
|
|
$migration->setAttribute('statusCounters', json_encode($transfer->getStatusCounters()));
|
|
|
|
|
$this->updateMigrationDocument($migration, $projectDocument, $queueForRealtime);
|
|
|
|
|
},
|
|
|
|
|
$migration->getAttribute('resourceId'),
|
|
|
|
|
$migration->getAttribute('resourceType')
|
|
|
|
|
);
|
|
|
|
|
}
|
2024-05-28 17:52:32 +00:00
|
|
|
$destination->shutDown();
|
2024-06-26 07:54:57 +00:00
|
|
|
$source->shutDown();
|
2024-05-28 17:52:32 +00:00
|
|
|
|
2024-02-24 14:18:55 +00:00
|
|
|
$sourceErrors = $source->getErrors();
|
|
|
|
|
$destinationErrors = $destination->getErrors();
|
2023-10-01 17:39:26 +00:00
|
|
|
|
2024-07-28 06:29:02 +00:00
|
|
|
if (! empty($sourceErrors) || ! empty($destinationErrors)) {
|
2024-06-19 09:03:32 +00:00
|
|
|
$migration->setAttribute('status', 'failed');
|
|
|
|
|
$migration->setAttribute('stage', 'finished');
|
2023-10-01 17:39:26 +00:00
|
|
|
|
|
|
|
|
$errorMessages = [];
|
2024-02-24 14:18:55 +00:00
|
|
|
foreach ($sourceErrors as $error) {
|
2025-06-12 05:13:35 +00:00
|
|
|
$errorMessages[] = json_encode($error);
|
2024-02-24 14:18:55 +00:00
|
|
|
}
|
|
|
|
|
foreach ($destinationErrors as $error) {
|
2025-06-12 05:13:35 +00:00
|
|
|
$errorMessages[] = json_encode($error);
|
2023-10-01 17:39:26 +00:00
|
|
|
}
|
|
|
|
|
|
2024-06-19 09:03:32 +00:00
|
|
|
$migration->setAttribute('errors', $errorMessages);
|
2024-05-01 17:15:16 +00:00
|
|
|
|
|
|
|
|
return;
|
2023-10-01 17:39:26 +00:00
|
|
|
}
|
|
|
|
|
|
2024-06-19 09:03:32 +00:00
|
|
|
$migration->setAttribute('status', 'completed');
|
|
|
|
|
$migration->setAttribute('stage', 'finished');
|
2023-10-01 17:39:26 +00:00
|
|
|
} catch (\Throwable $th) {
|
|
|
|
|
Console::error($th->getMessage());
|
2024-06-19 09:03:32 +00:00
|
|
|
Console::error($th->getTraceAsString());
|
2023-10-01 17:39:26 +00:00
|
|
|
|
2024-07-28 06:29:02 +00:00
|
|
|
if (! $migration->isEmpty()) {
|
2024-06-19 09:03:32 +00:00
|
|
|
$migration->setAttribute('status', 'failed');
|
|
|
|
|
$migration->setAttribute('stage', 'finished');
|
2023-10-01 17:39:26 +00:00
|
|
|
|
2024-12-11 10:57:25 +00:00
|
|
|
call_user_func($this->logError, $th, 'appwrite-worker', 'appwrite-queue-'.self::getName(), [
|
|
|
|
|
'migrationId' => $migration->getId(),
|
|
|
|
|
'source' => $migration->getAttribute('source') ?? '',
|
|
|
|
|
'destination' => $migration->getAttribute('destination') ?? '',
|
|
|
|
|
]);
|
|
|
|
|
|
2023-10-01 17:39:26 +00:00
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if ($transfer) {
|
2024-02-24 14:18:55 +00:00
|
|
|
$sourceErrors = $source->getErrors();
|
|
|
|
|
$destinationErrors = $destination->getErrors();
|
2023-10-01 17:39:26 +00:00
|
|
|
|
2024-02-24 14:18:55 +00:00
|
|
|
$errorMessages = [];
|
|
|
|
|
foreach ($sourceErrors as $error) {
|
2025-06-12 05:13:35 +00:00
|
|
|
$errorMessages[] = json_encode($error);
|
2023-10-01 17:39:26 +00:00
|
|
|
}
|
2024-02-24 14:18:55 +00:00
|
|
|
foreach ($destinationErrors as $error) {
|
2025-06-12 05:13:35 +00:00
|
|
|
$errorMessages[] = json_encode($error);
|
2024-02-24 14:18:55 +00:00
|
|
|
}
|
|
|
|
|
|
2024-06-19 09:03:32 +00:00
|
|
|
$migration->setAttribute('errors', $errorMessages);
|
2023-10-01 17:39:26 +00:00
|
|
|
}
|
|
|
|
|
} finally {
|
2025-02-11 04:03:02 +00:00
|
|
|
$this->updateMigrationDocument($migration, $projectDocument, $queueForRealtime);
|
2024-06-19 09:03:32 +00:00
|
|
|
|
2024-09-24 19:02:38 +00:00
|
|
|
if ($migration->getAttribute('status', '') === 'failed') {
|
2025-05-26 05:42:11 +00:00
|
|
|
Console::error('Migration('.$migration->getSequence().':'.$migration->getId().') failed, Project('.$this->project->getSequence().':'.$this->project->getId().')');
|
2024-09-30 08:01:01 +00:00
|
|
|
|
2024-12-11 11:31:17 +00:00
|
|
|
if ($destination) {
|
|
|
|
|
$destination->error();
|
|
|
|
|
|
|
|
|
|
foreach ($destination->getErrors() as $error) {
|
|
|
|
|
/** @var MigrationException $error */
|
|
|
|
|
call_user_func($this->logError, $error, 'appwrite-worker', 'appwrite-queue-' . self::getName(), [
|
|
|
|
|
'migrationId' => $migration->getId(),
|
|
|
|
|
'source' => $migration->getAttribute('source') ?? '',
|
|
|
|
|
'destination' => $migration->getAttribute('destination') ?? '',
|
|
|
|
|
'resourceName' => $error->getResourceName(),
|
|
|
|
|
'resourceGroup' => $error->getResourceGroup()
|
|
|
|
|
]);
|
|
|
|
|
}
|
2024-11-12 02:29:19 +00:00
|
|
|
}
|
|
|
|
|
|
2024-12-11 11:31:17 +00:00
|
|
|
if ($source) {
|
|
|
|
|
$source->error();
|
|
|
|
|
|
|
|
|
|
foreach ($source->getErrors() as $error) {
|
|
|
|
|
/** @var MigrationException $error */
|
|
|
|
|
call_user_func($this->logError, $error, 'appwrite-worker', 'appwrite-queue-' . self::getName(), [
|
|
|
|
|
'migrationId' => $migration->getId(),
|
|
|
|
|
'source' => $migration->getAttribute('source') ?? '',
|
|
|
|
|
'destination' => $migration->getAttribute('destination') ?? '',
|
|
|
|
|
'resourceName' => $error->getResourceName(),
|
|
|
|
|
'resourceGroup' => $error->getResourceGroup()
|
|
|
|
|
]);
|
|
|
|
|
}
|
2024-11-12 02:29:19 +00:00
|
|
|
}
|
2023-10-01 17:39:26 +00:00
|
|
|
}
|
2024-10-10 08:15:18 +00:00
|
|
|
|
|
|
|
|
if ($migration->getAttribute('status', '') === 'completed') {
|
2024-12-11 11:31:17 +00:00
|
|
|
$destination?->success();
|
|
|
|
|
$source?->success();
|
2024-10-10 08:15:18 +00:00
|
|
|
}
|
2023-10-01 17:39:26 +00:00
|
|
|
}
|
|
|
|
|
}
|
2024-05-01 16:46:19 +00:00
|
|
|
}
|