- Implemented tests for RouterConfig, RoutingOptions, StaticInstanceConfig, and RouterConfigOptions to ensure default values are set correctly. - Added tests for RouterConfigProvider to validate configurations and ensure defaults are returned when no file is specified. - Created tests for ConfigValidationResult to check success and error scenarios. - Developed tests for ServiceCollectionExtensions to verify service registration for RouterConfig. - Introduced UdpTransportTests to validate serialization, connection, request-response, and error handling in UDP transport. - Added scripts for signing authority gaps and hashing DevPortal SDK snippets.
6.3 KiB
StellaOps Router Example
This example demonstrates the StellaOps Router, Gateway, and Microservice SDK working together.
Overview
The example includes:
- Examples.Gateway - HTTP gateway that routes requests to microservices
- Examples.Billing.Microservice - Sample billing service with typed and streaming endpoints
- Examples.Inventory.Microservice - Sample inventory service demonstrating multi-service routing
- Examples.Integration.Tests - End-to-end integration tests
Prerequisites
- .NET 10 SDK
- Docker and Docker Compose (for containerized deployment)
Project Structure
examples/router/
├── Examples.Router.sln
├── docker-compose.yaml
├── README.md
├── src/
│ ├── Examples.Gateway/
│ │ ├── Program.cs
│ │ ├── router.yaml
│ │ └── appsettings.json
│ ├── Examples.Billing.Microservice/
│ │ ├── Program.cs
│ │ ├── microservice.yaml
│ │ └── Endpoints/
│ │ ├── CreateInvoiceEndpoint.cs
│ │ ├── GetInvoiceEndpoint.cs
│ │ └── UploadAttachmentEndpoint.cs
│ └── Examples.Inventory.Microservice/
│ ├── Program.cs
│ └── Endpoints/
│ ├── ListItemsEndpoint.cs
│ └── GetItemEndpoint.cs
└── tests/
└── Examples.Integration.Tests/
Running Locally
Build the Solution
cd examples/router
dotnet build Examples.Router.sln
Run with Docker Compose
docker-compose up --build
This starts:
- Gateway on port 8080 (HTTP) and 5100 (TCP transport)
- Billing microservice
- Inventory microservice
- RabbitMQ (optional, for message-based transport)
Run Without Docker
Start each service in separate terminals:
# Terminal 1: Gateway
cd src/Examples.Gateway
dotnet run
# Terminal 2: Billing Microservice
cd src/Examples.Billing.Microservice
dotnet run
# Terminal 3: Inventory Microservice
cd src/Examples.Inventory.Microservice
dotnet run
Example API Calls
Billing Service
Create an invoice:
curl -X POST http://localhost:8080/invoices \
-H "Content-Type: application/json" \
-d '{"customerId": "CUST-001", "amount": 99.99, "description": "Service fee"}'
Get an invoice:
curl http://localhost:8080/invoices/INV-12345
Upload an attachment (streaming):
curl -X POST http://localhost:8080/invoices/INV-12345/attachments \
-H "Content-Type: application/octet-stream" \
--data-binary @document.pdf
Inventory Service
List items:
curl "http://localhost:8080/items?page=1&pageSize=20"
List items by category:
curl "http://localhost:8080/items?category=widgets"
Get a specific item:
curl http://localhost:8080/items/SKU-001
Adding New Endpoints
1. Create the Endpoint Class
using StellaOps.Microservice;
[StellaEndpoint("POST", "/orders", TimeoutSeconds = 30)]
public sealed class CreateOrderEndpoint : IStellaEndpoint<CreateOrderRequest, CreateOrderResponse>
{
public Task<CreateOrderResponse> HandleAsync(
CreateOrderRequest request,
CancellationToken cancellationToken)
{
// Implementation
return Task.FromResult(new CreateOrderResponse { OrderId = "ORD-123" });
}
}
2. Register in Program.cs
builder.Services.AddScoped<CreateOrderEndpoint>();
3. Update router.yaml (if needed)
Add routing rules for the new endpoint path.
Streaming Endpoints
For endpoints that handle large payloads (file uploads, etc.), implement IRawStellaEndpoint:
[StellaEndpoint("POST", "/files/{id}", SupportsStreaming = true)]
public sealed class UploadFileEndpoint : IRawStellaEndpoint
{
public async Task<RawResponse> HandleAsync(
RawRequestContext context,
CancellationToken cancellationToken)
{
var id = context.PathParameters["id"];
// Stream body directly without buffering
await using var stream = context.Body;
// Process stream...
return RawResponse.Ok("{}");
}
}
Cancellation Behavior
All endpoints receive a CancellationToken that is triggered when:
- The client disconnects
- The request timeout is exceeded
- The gateway shuts down
Always respect the cancellation token in long-running operations:
public async Task<Response> HandleAsync(Request request, CancellationToken ct)
{
// Check cancellation periodically
ct.ThrowIfCancellationRequested();
// Or pass to async operations
await SomeLongOperation(ct);
}
Payload Limits
Default limits are configured in router.yaml:
payloadLimits:
maxRequestBodySizeBytes: 10485760 # 10 MB
maxChunkSizeBytes: 65536 # 64 KB
For streaming endpoints, the body is not buffered so these limits apply per-chunk.
Running Tests
cd tests/Examples.Integration.Tests
dotnet test
The integration tests verify:
- End-to-end request routing
- Multi-service registration
- Streaming uploads
- Request cancellation
- Payload limit enforcement
Configuration
Gateway (router.yaml)
# Microservice routing rules
services:
billing:
routes:
- path: /invoices
methods: [GET, POST]
- path: /invoices/{id}
methods: [GET, PUT, DELETE]
- path: /invoices/{id}/attachments
methods: [POST]
inventory:
routes:
- path: /items
methods: [GET]
- path: /items/{sku}
methods: [GET]
Microservice (microservice.yaml)
service:
name: billing
version: 1.0.0
region: demo
endpoints:
- path: /invoices
method: POST
timeoutSeconds: 30
- path: /invoices/{id}
method: GET
timeoutSeconds: 10
routers:
- host: localhost
port: 5100
transportType: InMemory
Troubleshooting
Microservice not registering
Check that:
- Gateway is running and healthy
- Router host/port in microservice.yaml matches gateway
- Network connectivity between services
Request timeouts
Increase the timeout in the endpoint attribute:
[StellaEndpoint("POST", "/long-operation", TimeoutSeconds = 120)]
Streaming not working
Ensure the endpoint:
- Is marked with
SupportsStreaming = true - Implements
IRawStellaEndpoint - Does not buffer the entire body before processing
License
AGPL-3.0-or-later