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.
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
Development Workflow
-
Feature Development
$ git checkout -b feature/new-capability $ do dev --watch # Develop and test -
Version Bump
$ do version patch # or minor, major -
Deploy to Staging
$ do deploy --env staging -
Test in Staging
$ do test --env staging -
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-v2Automated Changelog
Generate changelog automatically:
$ do changelog --from v2.0.0 --to v2.1.3Sunset 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
- Deployment - Deployment strategies
- Service Composition - Compose services
- Best Practices - Lifecycle best practices