.do
ScaleServices-as-Software

Service Lifecycle Management

Managing service versions, updates, and deprecation

Learn how to manage the complete lifecycle of your Services-as-Software from launch to sunset.

stateDiagram-v2 [*] --> Development Development --> Testing Testing --> Staging Staging --> Production Production --> Active Active --> Maintenance Maintenance --> Active Active --> Deprecated Deprecated --> Sunset Sunset --> [*] Testing --> Development: Bugs Found Staging --> Development: Issues Found note right of Development Code, test, iterate end note note right of Active Serving customers end note note right of Deprecated 6-12 month notice end note

Versioning Strategy

Semantic Versioning

Use semantic versioning (MAJOR.MINOR.PATCH):

export default service({
  name: 'My Service',
  version: '2.1.3',
  // 2 = Major version (breaking changes)
  // 1 = Minor version (new features)
  // 3 = Patch version (bug fixes)
})

Version increments:

  • MAJOR: Breaking changes to API or behavior
  • MINOR: New features, backward compatible
  • PATCH: Bug fixes, no API changes

Version Declaration

Declare version in your service:

export default service({
  name: 'Customer Support Service',
  version: '2.0.0',

  // Version metadata
  versionInfo: {
    releaseDate: '2025-10-24',
    changelog: 'Added AI-powered categorization',
    breaking: ['Removed legacy API endpoints'],
    deprecated: ['Manual categorization'],
  },
})

Release Management

flowchart LR Feature[Feature Branch] --> Bump[Version Bump] Bump --> Patch{Type?} Patch -->|Patch| V1[x.x.+1] Patch -->|Minor| V2[x.+1.0] Patch -->|Major| V3[+1.0.0] V1 & V2 & V3 --> Stage[Deploy Staging] Stage --> Test[Test & Verify] Test --> Pass{Tests Pass?} Pass -->|No| Fix[Fix Issues] Fix --> Feature Pass -->|Yes| Prod[Deploy Production] Prod --> Tag[Git Tag Release] Tag --> Monitor[Monitor]

Development Workflow

  1. Feature Development

    $ git checkout -b feature/new-capability
    $ do dev --watch
    # Develop and test
  2. Version Bump

    $ do version patch  # or minor, major
  3. Deploy to Staging

    $ do deploy --env staging
  4. Test in Staging

    $ do test --env staging
  5. Deploy to Production

    $ do deploy --env production

Release Types

Patch Release

Bug fixes and minor improvements:

$ do release patch --notes "Fixed email notification bug"

Minor Release

New features, backward compatible:

$ do release minor --notes "Added batch processing support"

Major Release

Breaking changes:

$ do release major --notes "New API design with breaking changes"

Backward Compatibility

API Versioning

Support multiple API versions:

api: {
  // v2 API
  'POST /v2/process': async (req) => {
    return await processV2(await req.json())
  },

  // v1 API (deprecated but supported)
  'POST /v1/process': async (req) => {
    const data = await req.json()
    // Transform v1 format to v2
    const v2Data = transformV1toV2(data)
    return await processV2(v2Data)
  },
}

Feature Flags

Gradually roll out new features:

export default service({
  name: 'My Service',

  features: {
    'ai-categorization': {
      enabled: true,
      rollout: 50, // 50% of users
    },
    'batch-processing': {
      enabled: true,
      rollout: 100, // 100% of users
    },
  },

  on: {
    '$.Request.process': async (event) => {
      // Check feature flag
      if (await $.feature.enabled('ai-categorization', event.data.userId)) {
        return await aiCategorize(event.data)
      } else {
        return await legacyCategorize(event.data)
      }
    },
  },
})

Schema Evolution

Handle schema changes gracefully:

on: {
  '$.Data.process': async (event) => {
    let data = event.data

    // Migrate old format to new
    if (data.version === '1.0') {
      data = migrateV1toV2(data)
    }

    // Process with current schema
    return await process(data)
  },
}

Deprecation Strategy

Announcing Deprecation

Warn users about upcoming changes:

api: {
  'POST /v1/process': async (req) => {
    // Send deprecation warning
    const response = await processV1(await req.json())

    // Add deprecation header
    return new Response(JSON.stringify(response), {
      headers: {
        'X-API-Deprecated': 'true',
        'X-API-Sunset-Date': '2026-01-01',
        'X-API-Migration-Guide': 'https://docs.example.com/migrate-v2',
      },
    })
  },
}

Gradual Phase-Out

Remove features gradually:

export default service({
  name: 'My Service',

  deprecated: {
    'legacy-api': {
      deprecatedAt: '2025-10-01',
      sunsetAt: '2026-01-01',
      migrationGuide: 'https://docs.example.com/migrate',
      replacement: 'v2-api',
    },
  },
})

User Migration

Help users migrate:

on: {
  '$.API.legacy-used': async (event) => {
    const customer = event.data.customer

    // Send migration reminder
    await $.Email.send({
      to: customer.email,
      template: 'api-migration-reminder',
      data: {
        sunsetDate: '2026-01-01',
        migrationGuide: 'https://docs.example.com/migrate',
        apiUsage: await $.Usage.get(customer.id, 'legacy-api'),
      },
    })
  },
}

Update Management

Automatic Updates

Users receive updates automatically:

export default service({
  name: 'My Service',

  updates: {
    strategy: 'automatic',
    notifyUsers: true,
    rollback: {
      enabled: true,
      errorThreshold: 0.05,
    },
  },
})

Opt-In Updates

Let users control updates:

export default service({
  name: 'My Service',

  updates: {
    strategy: 'opt-in',
    channels: ['stable', 'beta', 'alpha'],
  },
})

Update Notifications

Notify users of updates:

on: {
  '$.Service.updated': async (event) => {
    const customers = await $.Customer.findMany({
      where: { serviceId: event.data.serviceId },
    })

    for (const customer of customers) {
      await $.Email.send({
        to: customer.email,
        template: 'service-update',
        data: {
          version: event.data.version,
          changes: event.data.changelog,
        },
      })
    }
  },
}

Monitoring Service Health

Health Metrics

Track service health:

api: {
  'GET /health': async () => {
    const health = {
      status: 'healthy',
      version: '2.1.3',
      uptime: process.uptime(),
      checks: {
        database: await $.db.ping(),
        ai: await $.ai.health(),
        external: await checkExternalAPIs(),
      },
    }

    const allHealthy = Object.values(health.checks).every(Boolean)

    return {
      ...health,
      status: allHealthy ? 'healthy' : 'degraded',
    }
  },
}

Error Tracking

Monitor errors:

on: {
  '$.Error.occurred': async (event) => {
    const error = event.data

    // Track error rate
    await $.metric.increment('errors', {
      type: error.type,
      version: '2.1.3',
    })

    // Alert if threshold exceeded
    const errorRate = await $.metric.rate('errors', '5m')
    if (errorRate > 0.05) {
      await $.alert('high-error-rate', {
        rate: errorRate,
        version: '2.1.3',
      })
    }
  },
}

Performance Monitoring

Track performance:

on: {
  '$.Request.received': async (event) => {
    const start = Date.now()

    try {
      const result = await processRequest(event.data)

      // Record latency
      await $.metric.histogram('latency', Date.now() - start, {
        endpoint: event.data.endpoint,
        version: '2.1.3',
      })

      return result
    } catch (error) {
      // Record error
      await $.metric.increment('errors', {
        endpoint: event.data.endpoint,
        version: '2.1.3',
      })
      throw error
    }
  },
}

Changelog Management

Maintain Changelog

Keep comprehensive changelog:

# Changelog

## [2.1.3] - 2025-10-24

### Fixed

- Email notifications not sending
- Incorrect categorization for edge cases

## [2.1.0] - 2025-10-20

### Added

- Batch processing support
- Advanced analytics

### Changed

- Improved AI model accuracy
- Faster response times

### Deprecated

- Legacy API endpoints (sunset 2026-01-01)

## [2.0.0] - 2025-10-15

### Breaking Changes

- New API design
- Event schema changes

### Migration Guide

See https://docs.example.com/migrate-v2

Automated Changelog

Generate changelog automatically:

$ do changelog --from v2.0.0 --to v2.1.3

Sunset Planning

Service Deprecation

Plan service end-of-life:

export default service({
  name: 'Legacy Service',

  lifecycle: {
    status: 'deprecated',
    deprecatedAt: '2025-10-01',
    sunsetAt: '2026-01-01',
    replacement: 'new-service',
    migrationGuide: 'https://docs.example.com/migrate',
  },
})

Data Migration

Help users migrate data:

api: {
  'GET /export': async (req) => {
    const customerId = req.headers.get('x-customer-id')

    // Export all customer data
    const data = await $.Data.export({
      customerId,
      format: 'json',
    })

    return {
      data,
      importInstructions: 'https://docs.example.com/import',
    }
  },
}

Final Notifications

Send sunset reminders:

scheduled: {
  // 90 days before sunset
  'sunset-90': async () => {
    await notifyCustomers({
      daysRemaining: 90,
      template: 'sunset-warning',
    })
  },

  // 30 days before sunset
  'sunset-30': async () => {
    await notifyCustomers({
      daysRemaining: 30,
      template: 'sunset-urgent',
    })
  },

  // 7 days before sunset
  'sunset-7': async () => {
    await notifyCustomers({
      daysRemaining: 7,
      template: 'sunset-final',
    })
  },
}

Best Practices

Version Control

  • Use semantic versioning
  • Tag releases in git
  • Maintain detailed changelog
  • Document breaking changes

Backward Compatibility

  • Support old versions for 6-12 months
  • Provide migration tools
  • Deprecate gradually
  • Communicate changes early

Testing

  • Test updates in staging
  • Use canary deployments
  • Monitor error rates
  • Have rollback plan

Communication

  • Announce changes in advance
  • Provide migration guides
  • Send deprecation warnings
  • Offer migration support

Next Steps