- 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.
298 lines
6.3 KiB
Markdown
298 lines
6.3 KiB
Markdown
# 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
|
|
|
|
```bash
|
|
cd examples/router
|
|
dotnet build Examples.Router.sln
|
|
```
|
|
|
|
### Run with Docker Compose
|
|
|
|
```bash
|
|
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:
|
|
|
|
```bash
|
|
# 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:
|
|
```bash
|
|
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:
|
|
```bash
|
|
curl http://localhost:8080/invoices/INV-12345
|
|
```
|
|
|
|
Upload an attachment (streaming):
|
|
```bash
|
|
curl -X POST http://localhost:8080/invoices/INV-12345/attachments \
|
|
-H "Content-Type: application/octet-stream" \
|
|
--data-binary @document.pdf
|
|
```
|
|
|
|
### Inventory Service
|
|
|
|
List items:
|
|
```bash
|
|
curl "http://localhost:8080/items?page=1&pageSize=20"
|
|
```
|
|
|
|
List items by category:
|
|
```bash
|
|
curl "http://localhost:8080/items?category=widgets"
|
|
```
|
|
|
|
Get a specific item:
|
|
```bash
|
|
curl http://localhost:8080/items/SKU-001
|
|
```
|
|
|
|
## Adding New Endpoints
|
|
|
|
### 1. Create the Endpoint Class
|
|
|
|
```csharp
|
|
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
|
|
|
|
```csharp
|
|
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`:
|
|
|
|
```csharp
|
|
[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:
|
|
|
|
1. The client disconnects
|
|
2. The request timeout is exceeded
|
|
3. The gateway shuts down
|
|
|
|
Always respect the cancellation token in long-running operations:
|
|
|
|
```csharp
|
|
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`:
|
|
|
|
```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
|
|
|
|
```bash
|
|
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)
|
|
|
|
```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)
|
|
|
|
```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:
|
|
1. Gateway is running and healthy
|
|
2. Router host/port in microservice.yaml matches gateway
|
|
3. Network connectivity between services
|
|
|
|
### Request timeouts
|
|
|
|
Increase the timeout in the endpoint attribute:
|
|
|
|
```csharp
|
|
[StellaEndpoint("POST", "/long-operation", TimeoutSeconds = 120)]
|
|
```
|
|
|
|
### Streaming not working
|
|
|
|
Ensure the endpoint:
|
|
1. Is marked with `SupportsStreaming = true`
|
|
2. Implements `IRawStellaEndpoint`
|
|
3. Does not buffer the entire body before processing
|
|
|
|
## License
|
|
|
|
AGPL-3.0-or-later
|