Lifecycle & Workflows

Migration script lifecycle and error handling workflows.

Table of contents

  1. Migration Script Lifecycle
    1. High-Level Workflow
    2. Detailed Phase Interactions
      1. Initialization and Discovery
      2. Execution Loop
    3. State Transitions
    4. Script Object Evolution
  2. Error Handling Strategy
    1. Fail-Fast Philosophy
    2. Error Flow (with Rollback Strategies)
    3. Recovery Process
      1. BACKUP Strategy
      2. DOWN Strategy
      3. BOTH Strategy
      4. NONE Strategy

Migration Script Lifecycle

High-Level Workflow

This simplified diagram shows the main phases of migration execution:

graph TD
    Start[User calls migrate] --> Init[Initialize Schema and Backup]
    Init --> Discover[Discover and Filter Scripts]
    Discover --> Validate[Validate Pending Scripts]
    Validate --> ValidCheck{Valid?}
    ValidCheck -->|No| Rollback[Rollback Changes]
    ValidCheck -->|Yes| Execute[Execute Scripts]
    Execute --> ExecCheck{Success?}
    ExecCheck -->|No| Rollback
    ExecCheck -->|Yes| Cleanup[Delete Backup]
    Cleanup --> Render[Render Results]
    Render --> Done[Return Success]
    Rollback --> RenderFail[Render Errors]
    RenderFail --> Fail[Return Failure]

Detailed Phase Interactions

Initialization and Discovery

sequenceDiagram
    participant Executor as MigrationScriptExecutor
    participant Backup as BackupService
    participant Schema as SchemaVersionService
    participant Scanner as MigrationScanner

    Executor->>Schema: init()
    Schema-->>Executor: Schema table ready

    Executor->>Backup: createBackup()
    Backup-->>Executor: Backup created

    Executor->>Scanner: scan(folder)
    Scanner-->>Executor: Pending migrations

Execution Loop

sequenceDiagram
    participant Executor as MigrationScriptExecutor
    participant Execution as MigrationExecutionService
    participant Schema as SchemaVersionService
    participant Rollback as RollbackService

    loop For each pending migration
        Executor->>Execution: execute(script)
        Execution-->>Executor: Success or Error

        alt Success
            Executor->>Schema: add(script)
            Schema-->>Executor: Saved
        else Error
            Executor->>Rollback: rollback()
            Rollback-->>Executor: Rolled back
        end
    end

State Transitions

This state diagram illustrates the various states a migration script can be in throughout its lifecycle, from discovery to completion or failure:

stateDiagram
    [*] --> Discovered: File found
    Discovered --> Filtered: Check status
    Filtered --> Pending: Not yet run
    Filtered --> Ignored: Skipped
    Filtered --> Migrated: Already run
    Pending --> Validated: Pass validation
    Validated --> Initialized: Load module
    Initialized --> Executing: Run up method
    Executing --> Completed: Success
    Executing --> Failed: Error
    Failed --> RollingBack: Trigger rollback
    RollingBack --> RolledBack: Restore state
    Completed --> Saved: Save to DB
    Saved --> [*]
    RolledBack --> [*]

Script Object Evolution

// 1. Discovery (MigrationService)
{
  name: "V202311020036_create_users.ts",
  filepath: "/path/../version-migration/V202311020036_create_users.ts",
  timestamp: 202311020036,
  script: undefined  // Not loaded yet
}

// 2. Initialization (script.init())
{
  name: "V202311020036_create_users.ts",
  filepath: "/path/../version-migration/V202311020036_create_users.ts",
  timestamp: 202311020036,
  script: {
    up: async (db, info, handler) => { ... }
  }
}

// 3. Execution (MigrationRunner)
{
  name: "V202311020036_create_users.ts",
  filepath: "/path/../version-migration/V202311020036_create_users.ts",
  timestamp: 202311020036,
  username: "developer",        // ← Added
  startedAt: 1699999999000,     // ← Added
  finishedAt: 1699999999500,    // ← Added
  result: "Created 3 tables",   // ← Added (from up() return)
  script: { up: ... }
}

Error Handling Strategy

Fail-Fast Philosophy

MSR stops execution immediately on the first error to prevent cascading failures and maintain database consistency.

Script 1: ✓ Success
Script 2: ✓ Success
Script 3: ✗ FAILS
Script 4: ⊗ Not executed (stopped)
Script 5: ⊗ Not executed (stopped)

Action: Restore from backup, rollback all changes

Error Flow (with Rollback Strategies)

try {
  // Conditional backup based on strategy
  if (strategy === BACKUP || strategy === BOTH) {
    await backup.create()
  }

  await schema.init()
  await runner.execute(scripts)  // ← Error here

  if (backupPath) {
    backup.delete()
  }
  return { success: true }

} catch (error) {
  // Handle rollback based on configured strategy
  switch (strategy) {
    case BACKUP:
      await backup.restore()
      break

    case DOWN:
      await rollbackWithDown(executedScripts)
      break

    case BOTH:
      try {
        await rollbackWithDown(executedScripts)
      } catch (downError) {
        await backup.restore()  // Fallback
      }
      break

    case NONE:
      logger.warn('No rollback configured')
      break
  }

  if (backupPath) {
    backup.delete()  // Cleanup
  }

  return {
    success: false,
    errors: [error]
  }
}

Recovery Process

BACKUP Strategy

  1. Error Occurs - Migration script throws exception
  2. Stop Execution - Remaining scripts not executed
  3. Restore Backup - Database rolled back to pre-migration state
  4. Delete Backup - Cleanup temporary backup file
  5. Return Result - Report failure with error details

DOWN Strategy

  1. Error Occurs - Migration script throws exception
  2. Stop Execution - Remaining scripts not executed
  3. Call down() Methods - Execute down() on all attempted migrations in reverse order
  4. Return Result - Report failure with error details

BOTH Strategy

  1. Error Occurs - Migration script throws exception
  2. Stop Execution - Remaining scripts not executed
  3. Try down() First - Attempt to rollback using down() methods
  4. Fallback to Backup - If down() fails, restore from backup
  5. Delete Backup - Cleanup temporary backup file
  6. Return Result - Report failure with error details

NONE Strategy

  1. Error Occurs - Migration script throws exception
  2. Stop Execution - Remaining scripts not executed
  3. Log Warning - No rollback performed, database may be inconsistent
  4. Return Result - Report failure with error details