Some checks failed
Docs CI / lint-and-preview (push) Has been cancelled
Policy Lint & Smoke / policy-lint (push) Has been cancelled
Concelier Attestation Tests / attestation-tests (push) Has been cancelled
AOC Guard CI / aoc-guard (push) Has been cancelled
AOC Guard CI / aoc-verify (push) Has been cancelled
- Implemented MigrationCategoryTests to validate migration categorization for startup, release, seed, and data migrations. - Added tests for edge cases, including null, empty, and whitespace migration names. - Created StartupMigrationHostTests to verify the behavior of the migration host with real PostgreSQL instances using Testcontainers. - Included tests for migration execution, schema creation, and handling of pending release migrations. - Added SQL migration files for testing: creating a test table, adding a column, a release migration, and seeding data.
9.8 KiB
9.8 KiB
Sprint 7000-0010-0001 · Migration · WebService to Microservice
Topic & Scope
Define and document the migration path from existing StellaOps.*.WebService projects to the new microservice pattern with router. This is the final sprint that connects the router infrastructure to the rest of StellaOps.
Goal: Clear migration guide and tooling for converting WebServices to Microservices.
Working directories:
docs/router/(migration documentation)- Potentially existing WebService projects (for pilot migration)
Dependencies & Concurrency
- Upstream: All router sprints complete (7000-0001 through 7000-0009)
- Downstream: None. Final sprint.
- Parallel work: None.
- Cross-module impact: YES - This sprint affects existing StellaOps modules.
Documentation Prerequisites
docs/router/specs.md(section 14 - Migration requirements)docs/router/implplan.md(phase 11-12 guidance)- Existing WebService project structures
BLOCKED Tasks: Before working on BLOCKED tasks, review ../implplan/BLOCKED_DEPENDENCY_TREE.md for root blockers and dependencies.
Delivery Tracker
| # | Task ID | Status | Description | Notes |
|---|---|---|---|---|
| 1 | MIG-001 | TODO | Inventory all existing WebService projects | List all services |
| 2 | MIG-002 | TODO | Document HTTP routes per service | Method + Path |
| 3 | MIG-010 | TODO | Document Strategy A: In-place adaptation | |
| 4 | MIG-011 | TODO | Add SDK to existing WebService | |
| 5 | MIG-012 | TODO | Wrap controllers in [StellaEndpoint] handlers | |
| 6 | MIG-013 | TODO | Register with router alongside HTTP | |
| 7 | MIG-014 | TODO | Gradual traffic shift from HTTP to router | |
| 8 | MIG-020 | TODO | Document Strategy B: Clean split | |
| 9 | MIG-021 | TODO | Extract domain logic to shared library | |
| 10 | MIG-022 | TODO | Create new Microservice project | |
| 11 | MIG-023 | TODO | Map routes to handlers | |
| 12 | MIG-024 | TODO | Phase out original WebService | |
| 13 | MIG-030 | TODO | Document CancellationToken wiring | |
| 14 | MIG-031 | TODO | Identify async operations needing token | |
| 15 | MIG-032 | TODO | Update DB calls, HTTP calls, etc. | |
| 16 | MIG-040 | TODO | Document streaming migration | |
| 17 | MIG-041 | TODO | Convert file upload controllers | |
| 18 | MIG-042 | TODO | Convert file download controllers | |
| 19 | MIG-050 | TODO | Create migration checklist template | |
| 20 | MIG-051 | TODO | Create automated route inventory tool | Optional |
| 21 | MIG-060 | TODO | Pilot migration: choose one WebService | |
| 22 | MIG-061 | TODO | Execute pilot migration | |
| 23 | MIG-062 | TODO | Document lessons learned | |
| 24 | MIG-070 | TODO | Merge Router.sln into StellaOps.sln | |
| 25 | MIG-071 | TODO | Update CI/CD for router components |
Migration Strategies
Strategy A: In-Place Adaptation
Best for: Services that need to maintain HTTP compatibility during transition.
┌─────────────────────────────────────┐
│ StellaOps.Billing.WebService │
│ ┌─────────────────────────────┐ │
│ │ Existing HTTP Controllers │◄───┼──── HTTP clients (legacy)
│ └─────────────────────────────┘ │
│ ┌─────────────────────────────┐ │
│ │ [StellaEndpoint] Handlers │◄───┼──── Router (new)
│ └─────────────────────────────┘ │
│ ┌─────────────────────────────┐ │
│ │ Shared Domain Logic │ │
│ └─────────────────────────────┘ │
└─────────────────────────────────────┘
Steps:
- Add
StellaOps.Microservicepackage reference - Create handler classes for each route
- Handlers call existing service layer
- Register with router pool
- Test via router
- Shift traffic gradually
- Remove HTTP controllers when ready
Strategy B: Clean Split
Best for: Major refactoring or when HTTP compatibility not needed.
┌─────────────────────────────────────┐
│ StellaOps.Billing.Domain │ ◄── Shared library
│ (extracted business logic) │
└─────────────────────────────────────┘
▲ ▲
│ │
┌─────────┴───────┐ ┌───────┴─────────┐
│ (Legacy) │ │ (New) │
│ Billing.Web │ │ Billing.Micro │
│ Service │ │ service │
│ HTTP only │ │ Router only │
└─────────────────┘ └─────────────────┘
Steps:
- Extract domain logic to
.Domainlibrary - Create new
.Microserviceproject - Implement handlers using domain library
- Deploy alongside WebService
- Shift traffic to router
- Deprecate WebService
Controller to Handler Mapping
Before (ASP.NET Controller)
[ApiController]
[Route("api/invoices")]
public class InvoicesController : ControllerBase
{
private readonly IInvoiceService _service;
[HttpPost]
[Authorize(Roles = "billing-admin")]
public async Task<IActionResult> Create(
[FromBody] CreateInvoiceRequest request,
CancellationToken ct) // <-- Often missing!
{
var invoice = await _service.CreateAsync(request);
return Ok(new { invoice.Id });
}
}
After (Microservice Handler)
[StellaEndpoint("POST", "/api/invoices")]
public sealed class CreateInvoiceEndpoint : IStellaEndpoint<CreateInvoiceRequest, CreateInvoiceResponse>
{
private readonly IInvoiceService _service;
public CreateInvoiceEndpoint(IInvoiceService service) => _service = service;
public async Task<CreateInvoiceResponse> HandleAsync(
CreateInvoiceRequest request,
CancellationToken ct) // <-- Required, propagated
{
var invoice = await _service.CreateAsync(request, ct); // Pass token!
return new CreateInvoiceResponse { InvoiceId = invoice.Id };
}
}
CancellationToken Checklist
For each migrated handler, verify:
- Handler accepts CancellationToken parameter
- Token passed to all database calls
- Token passed to all HTTP client calls
- Token passed to all file I/O operations
- Long-running loops check
ct.IsCancellationRequested - Token passed to Task.Delay, WaitAsync, etc.
Streaming Migration
File Upload (Before)
[HttpPost("upload")]
public async Task<IActionResult> Upload(IFormFile file)
{
using var stream = file.OpenReadStream();
await _storage.SaveAsync(stream);
return Ok();
}
File Upload (After)
[StellaEndpoint("POST", "/upload", SupportsStreaming = true)]
public sealed class UploadEndpoint : IRawStellaEndpoint
{
public async Task<RawResponse> HandleAsync(RawRequestContext ctx, CancellationToken ct)
{
await _storage.SaveAsync(ctx.Body, ct); // Body is already a stream
return RawResponse.Ok();
}
}
Migration Checklist Template
# Migration Checklist: [ServiceName]
## Inventory
- [ ] List all HTTP routes (Method + Path)
- [ ] Identify streaming endpoints
- [ ] Identify authorization requirements
- [ ] Document external dependencies
## Preparation
- [ ] Add StellaOps.Microservice package
- [ ] Configure router connection
- [ ] Set up local gateway for testing
## Per-Route Migration
For each route:
- [ ] Create [StellaEndpoint] handler class
- [ ] Map request/response types
- [ ] Wire CancellationToken throughout
- [ ] Convert to IRawStellaEndpoint if streaming
- [ ] Write unit tests
- [ ] Write integration tests
## Cutover
- [ ] Deploy alongside existing WebService
- [ ] Verify via router routing
- [ ] Shift percentage of traffic
- [ ] Monitor for errors
- [ ] Full cutover
- [ ] Remove WebService HTTP listeners
## Cleanup
- [ ] Remove unused controller code
- [ ] Remove HTTP pipeline configuration
- [ ] Update documentation
StellaOps Modules to Migrate
| Module | WebService | Priority | Complexity |
|---|---|---|---|
| Concelier | StellaOps.Concelier.WebService | High | Medium |
| Scanner | StellaOps.Scanner.WebService | High | High (streaming) |
| Authority | StellaOps.Authority.WebService | Medium | Low |
| Orchestrator | StellaOps.Orchestrator.WebService | Medium | Medium |
| Scheduler | StellaOps.Scheduler.WebService | Low | Low |
| Notify | StellaOps.Notify.WebService | Low | Low |
Exit Criteria
Before marking this sprint DONE:
- Migration strategies documented
- Controller-to-handler mapping guide complete
- CancellationToken checklist complete
- Streaming migration guide complete
- Migration checklist template created
- Pilot migration executed successfully
- Router.sln merged into StellaOps.sln
- CI/CD updated
Execution Log
| Date (UTC) | Update | Owner |
|---|---|---|
Decisions & Risks
- Pilot migration should be a low-risk service first
- Strategy A preferred for gradual transition
- Strategy B preferred for greenfield-like rewrites
- CancellationToken wiring is the #1 source of migration bugs
- Streaming endpoints require IRawStellaEndpoint, not typed handlers
- Authorization migrates from [Authorize(Roles)] to RequiringClaims