Compare commits

...

3 Commits

Author SHA1 Message Date
Paul Rastoin 483ef905ff [RenameIndexCommand] Fix orphaned index edge case (#16539)
We've been facing orphaned metadata index that would result in alter
error, now if we encounter one we just delete it
2025-12-12 17:45:46 +01:00
Weiko 228ab5f760 Fix rest metadata version missing (#16536)
## Context

The REST pipeline re-fetches/sets the metadata version later in
RestApiBaseHandler#getObjectMetadata by reading from DB and seeding the
cache if it’s missing. That’s the place that actually needs it and
already handles the “undefined” case.

This also mirror the graphql path that was updated 3 weeks ago
2025-12-12 17:45:39 +01:00
Paul Rastoin d7533bef8c fix(server): non blocking CleanEmptyStringNullInTextFieldsCommand error (#16529)
# Introduction
Getting query timeout on prod upgrade for workspace that has huge
timeline activity table
2025-12-12 16:06:06 +01:00
3 changed files with 73 additions and 58 deletions
@@ -85,26 +85,33 @@ export class CleanEmptyStringNullInTextFieldsCommand extends ActiveOrSuspendedWo
});
for (const objectMetadataItem of objectMetadataItems) {
const tableName = computeObjectTargetTable(objectMetadataItem);
try {
const tableName = computeObjectTargetTable(objectMetadataItem);
if (!objectMetadataItem.isCustom) {
await this.cleanUpEmptyStringDefaultsInTextFieldsInStandardObjects(
objectMetadataItem,
tableName,
schemaName,
dataSource,
isDryRun,
);
}
if (!objectMetadataItem.isCustom) {
await this.cleanUpEmptyStringDefaultsInTextFieldsInStandardObjects(
objectMetadataItem,
tableName,
schemaName,
dataSource,
isDryRun,
);
}
if (objectMetadataItem.isCustom) {
await this.cleanUpEmptyStringDefaultsAndSetNullableInNameFieldInCustomObjects(
objectMetadataItem,
tableName,
schemaName,
dataSource,
isDryRun,
if (objectMetadataItem.isCustom) {
await this.cleanUpEmptyStringDefaultsAndSetNullableInNameFieldInCustomObjects(
objectMetadataItem,
tableName,
schemaName,
dataSource,
isDryRun,
);
}
} catch (error) {
this.logger.error(
`Could not cleanup ${objectMetadataItem.isCustom ? 'custom' : 'standard'} object ${objectMetadataItem.nameSingular} records for workspace ${workspaceId}`,
);
this.logger.error(error);
}
}
}
@@ -63,6 +63,7 @@ export class RenameIndexNameCommand extends ActiveOrSuspendedWorkspacesMigration
]);
let hasIndexNameChanges = false;
let hasRemovedIndexMetadata = false;
for (const index of Object.values(flatIndexMaps.byId).filter(isDefined)) {
const flatObjectMetadata = findFlatEntityByIdInFlatEntityMapsOrThrow({
@@ -84,43 +85,62 @@ export class RenameIndexNameCommand extends ActiveOrSuspendedWorkspacesMigration
if (indexNameV2 === index.name) {
this.logger.log(`Index ${index.name} is V2`);
continue;
} else {
this.logger.log(`Renaming index ${index.name} to ${indexNameV2}`);
}
this.logger.log(`Renaming index ${index.name} to ${indexNameV2}`);
if (isDryRun) {
continue;
}
const queryRunner = this.coreDataSource.createQueryRunner();
await queryRunner.connect();
await queryRunner.startTransaction();
try {
await queryRunner.query(
`ALTER INDEX "${schemaName}"."${index.name}" RENAME TO "${indexNameV2}"`,
);
await queryRunner.manager.update(IndexMetadataEntity, index.id, {
name: indexNameV2,
});
await queryRunner.commitTransaction();
hasIndexNameChanges = true;
if (!isDryRun) {
const queryRunner = this.coreDataSource.createQueryRunner();
} catch (error) {
await queryRunner.rollbackTransaction();
await queryRunner.connect();
await queryRunner.startTransaction();
// PostgreSQL error code 42704: undefined_object (index does not exist)
if (error.code === '42704') {
this.logger.log(
`Index ${index.name} does not exist in schema ${schemaName}, removing metadata`,
);
try {
await queryRunner.query(
`ALTER INDEX "${schemaName}"."${index.name}" RENAME TO "${indexNameV2}"`,
);
await queryRunner.manager.update(IndexMetadataEntity, index.id, {
name: indexNameV2,
});
await queryRunner.commitTransaction();
} catch (error) {
await queryRunner.rollbackTransaction();
throw error;
} finally {
await queryRunner.release();
}
await this.coreDataSource.manager.delete(
IndexMetadataEntity,
index.id,
);
hasRemovedIndexMetadata = true;
} else {
throw error;
}
} finally {
await queryRunner.release();
}
}
if (hasIndexNameChanges) {
const shouldInvalidateCache =
hasIndexNameChanges || hasRemovedIndexMetadata;
if (shouldInvalidateCache) {
this.logger.log('Invalidating workspace cache');
if (!isDryRun) {
await this.workspaceCacheService.invalidateAndRecompute(workspaceId, [
'flatFieldMetadataMaps',
'flatIndexMaps',
]);
}
await this.workspaceCacheService.invalidateAndRecompute(workspaceId, [
'flatFieldMetadataMaps',
'flatIndexMaps',
]);
}
}
}
@@ -106,18 +106,6 @@ export class MiddlewareService {
)
: undefined;
if (metadataVersion === undefined && isDefined(data.workspace)) {
await this.flatEntityMapsCacheService.invalidateFlatEntityMaps({
workspaceId: data.workspace.id,
flatMapsKeys: [
'flatObjectMetadataMaps',
'flatFieldMetadataMaps',
'flatIndexMaps',
],
});
throw new Error('Metadata cache version not found');
}
const dataSourcesMetadata = data.workspace
? await this.dataSourceService.getDataSourcesMetadataFromWorkspaceId(
data.workspace.id,