[Upgrade] Fix workspace creation cursor (#19701)
The upgrade migration system required new workspaces to always start from a workspace command, which was too rigid. When the system was mid-upgrade within an instance command (IC) segment, workspace creation would fail or produce inconsistent state. Instance commands now write upgrade migration rows for **all active/suspended workspaces** alongside the global row. This means every workspace has a complete migration history, including instance command records. - `InstanceCommandRunnerService` reloads `activeOrSuspendedWorkspaceIds` immediately before writing records (both success and failure paths) to mitigate race conditions with concurrent workspace creation. - `recordUpgradeMigration` in `UpgradeMigrationService` accepts a discriminated union over `status`, handles `error: unknown` formatting internally, and writes global + workspace rows in batch. `getInitialCursorForNewWorkspace` now accepts the last **attempted** (not just completed) instance command with its status: - If the IC is `completed` and the next step is a workspace segment → cursor is set to the last WC of that segment (existing behavior). - If the IC is `failed` or not the last of its segment → cursor is set to that IC itself, preserving its status. This allows workspaces to be created at any point during the upgrade lifecycle, including mid-IC-segment and after IC failure. `validateWorkspaceCursorsAreInWorkspaceSegment` accepts workspaces whose cursor is: 1. Within the current workspace segment, OR 2. At the immediately preceding instance command with `completed` status (handles the `-w` single-workspace upgrade scenario). Workspaces with cursors in a previous segment, ahead of the current segment, or at a preceding IC with `failed` status are rejected. created empty workspaces to allow testing upgrade with several active workspaces
This commit is contained in:
@@ -62,6 +62,9 @@ export class RunInstanceCommandsCommand extends CommandRunner {
|
||||
await this.checkWorkspaceVersionSafety(options);
|
||||
await this.runLegacyPendingTypeOrmMigrations();
|
||||
|
||||
const activeOrSuspendedWorkspaceIds =
|
||||
await this.workspaceVersionService.getActiveOrSuspendedWorkspaceIds();
|
||||
|
||||
for (const {
|
||||
command,
|
||||
name,
|
||||
@@ -79,9 +82,6 @@ export class RunInstanceCommandsCommand extends CommandRunner {
|
||||
}
|
||||
|
||||
if (options.includeSlow) {
|
||||
const hasWorkspaces =
|
||||
await this.workspaceVersionService.hasActiveOrSuspendedWorkspaces();
|
||||
|
||||
for (const {
|
||||
command,
|
||||
name,
|
||||
@@ -90,7 +90,7 @@ export class RunInstanceCommandsCommand extends CommandRunner {
|
||||
await this.instanceUpgradeService.runSlowInstanceCommand({
|
||||
command,
|
||||
name,
|
||||
skipDataMigration: !hasWorkspaces,
|
||||
skipDataMigration: activeOrSuspendedWorkspaceIds.length === 0,
|
||||
});
|
||||
|
||||
if (result.status === 'failed') {
|
||||
@@ -119,10 +119,10 @@ export class RunInstanceCommandsCommand extends CommandRunner {
|
||||
return;
|
||||
}
|
||||
|
||||
const activeWorkspaceIds =
|
||||
const activeOrSuspendedWorkspaceIds =
|
||||
await this.workspaceVersionService.getActiveOrSuspendedWorkspaceIds();
|
||||
|
||||
if (activeWorkspaceIds.length === 0) {
|
||||
if (activeOrSuspendedWorkspaceIds.length === 0) {
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -141,7 +141,7 @@ export class RunInstanceCommandsCommand extends CommandRunner {
|
||||
const allAtPreviousVersion =
|
||||
await this.upgradeMigrationService.areAllWorkspacesAtCommand({
|
||||
commandName: lastWorkspaceCommand.name,
|
||||
workspaceIds: activeWorkspaceIds,
|
||||
workspaceIds: activeOrSuspendedWorkspaceIds,
|
||||
});
|
||||
|
||||
if (!allAtPreviousVersion) {
|
||||
|
||||
Reference in New Issue
Block a user