Add AICL example: 16_microservices.aicl
Browse files
data/aicl/examples/16_microservices.aicl
ADDED
|
@@ -0,0 +1,368 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
# AICL Example: Microservices Architecture
|
| 2 |
+
# Implements a production-grade microservices system with service discovery, API gateway,
|
| 3 |
+
# circuit breaker, saga pattern for distributed transactions, and distributed tracing.
|
| 4 |
+
|
| 5 |
+
# Level 1: Architecture
|
| 6 |
+
Goal: Build a resilient microservices architecture supporting independent service deployment,
|
| 7 |
+
cross-service communication, fault isolation, distributed transaction coordination via saga,
|
| 8 |
+
and full observability through distributed tracing.
|
| 9 |
+
|
| 10 |
+
Constraint: No service may directly reference another service's internal data store.
|
| 11 |
+
Constraint: All inter-service communication must traverse the API gateway.
|
| 12 |
+
Constraint: Each service must be independently deployable and scalable.
|
| 13 |
+
Constraint: Latency for synchronous calls must remain below 200ms p99.
|
| 14 |
+
Constraint: Saga transactions must complete within 30 seconds or compensate.
|
| 15 |
+
|
| 16 |
+
Risk: Service discovery failure leaves orphaned instances
|
| 17 |
+
Recovery: Fallback to static registry with heartbeat-based health checks and manual override
|
| 18 |
+
|
| 19 |
+
Risk: Circuit breaker cascade causes system-wide outage
|
| 20 |
+
Recovery: Bulkhead isolation per service with independent breaker pools and graceful degradation
|
| 21 |
+
|
| 22 |
+
Risk: Saga participant crash mid-transaction leaves partial state
|
| 23 |
+
Recovery: Saga orchestrator retries with exponential backoff; compensating transactions for unrecoverable failures
|
| 24 |
+
|
| 25 |
+
Risk: API gateway becomes single point of failure
|
| 26 |
+
Recovery: Deploy gateway replicas across availability zones with leader election and failover routing
|
| 27 |
+
|
| 28 |
+
Risk: Distributed trace context lost across async boundaries
|
| 29 |
+
Recovery: Inject trace context into message headers; background reconciler repairs broken traces
|
| 30 |
+
|
| 31 |
+
Risk: Network partition causes split-brain service registry
|
| 32 |
+
Recovery: Quorum-based registration with majority-wins consensus and stale-entry eviction
|
| 33 |
+
|
| 34 |
+
Layer: Infrastructure
|
| 35 |
+
SubLayer: ServiceDiscovery
|
| 36 |
+
SubLayer: APIGateway
|
| 37 |
+
SubLayer: MessageBus
|
| 38 |
+
Layer: Services
|
| 39 |
+
SubLayer: OrderService
|
| 40 |
+
SubLayer: PaymentService
|
| 41 |
+
SubLayer: InventoryService
|
| 42 |
+
SubLayer: NotificationService
|
| 43 |
+
Layer: Observability
|
| 44 |
+
SubLayer: DistributedTracing
|
| 45 |
+
SubLayer: MetricsAggregator
|
| 46 |
+
SubLayer: LogCollector
|
| 47 |
+
|
| 48 |
+
Validation: Service registry heartbeat must arrive every 5 seconds
|
| 49 |
+
Validation: API gateway route table must match deployed service count
|
| 50 |
+
Validation: Circuit breaker open duration must not exceed 60 seconds
|
| 51 |
+
Validation: Saga transaction must have a defined compensating action for every step
|
| 52 |
+
Validation: Distributed trace spans must propagate correlation IDs across all hops
|
| 53 |
+
Validation: Service health endpoint must respond within 500ms
|
| 54 |
+
|
| 55 |
+
# Level 2: Entities
|
| 56 |
+
Entity ServiceInstance
|
| 57 |
+
serviceId: string
|
| 58 |
+
host: string
|
| 59 |
+
port: integer
|
| 60 |
+
healthStatus: string
|
| 61 |
+
metadata: dict
|
| 62 |
+
registeredAt: datetime
|
| 63 |
+
lastHeartbeat: datetime
|
| 64 |
+
version: string
|
| 65 |
+
weight: integer
|
| 66 |
+
|
| 67 |
+
Entity ApiRoute
|
| 68 |
+
routeId: string
|
| 69 |
+
pathPattern: string
|
| 70 |
+
targetService: string
|
| 71 |
+
methods: list
|
| 72 |
+
rateLimit: integer
|
| 73 |
+
authRequired: boolean
|
| 74 |
+
timeout: integer
|
| 75 |
+
retryPolicy: dict
|
| 76 |
+
|
| 77 |
+
Entity CircuitBreaker
|
| 78 |
+
breakerId: string
|
| 79 |
+
serviceName: string
|
| 80 |
+
state: string
|
| 81 |
+
failureCount: integer
|
| 82 |
+
successCount: integer
|
| 83 |
+
lastFailureAt: datetime
|
| 84 |
+
openDuration: integer
|
| 85 |
+
halfOpenMaxCalls: integer
|
| 86 |
+
|
| 87 |
+
Entity SagaInstance
|
| 88 |
+
sagaId: string
|
| 89 |
+
sagaType: string
|
| 90 |
+
currentState: string
|
| 91 |
+
steps: list
|
| 92 |
+
completedSteps: list
|
| 93 |
+
compensateSteps: list
|
| 94 |
+
startedAt: datetime
|
| 95 |
+
timeoutAt: datetime
|
| 96 |
+
participantServices: list
|
| 97 |
+
|
| 98 |
+
Entity TraceSpan
|
| 99 |
+
traceId: string
|
| 100 |
+
spanId: string
|
| 101 |
+
parentSpanId: string
|
| 102 |
+
serviceName: string
|
| 103 |
+
operationName: string
|
| 104 |
+
startTime: datetime
|
| 105 |
+
endTime: datetime
|
| 106 |
+
tags: dict
|
| 107 |
+
status: string
|
| 108 |
+
|
| 109 |
+
Entity ServiceMetric
|
| 110 |
+
metricId: string
|
| 111 |
+
serviceName: string
|
| 112 |
+
metricName: string
|
| 113 |
+
value: float
|
| 114 |
+
timestamp: datetime
|
| 115 |
+
unit: string
|
| 116 |
+
tags: dict
|
| 117 |
+
percentile: float
|
| 118 |
+
|
| 119 |
+
# Level 3: Behaviors
|
| 120 |
+
Behavior RegisterService
|
| 121 |
+
Input:
|
| 122 |
+
instance: ServiceInstance
|
| 123 |
+
Output:
|
| 124 |
+
registrationId: string
|
| 125 |
+
Action:
|
| 126 |
+
Validate instance fields and health endpoint
|
| 127 |
+
Check for duplicate serviceId and host:port combination
|
| 128 |
+
Register in service discovery with TTL of 10 seconds
|
| 129 |
+
Broadcast registration event to all gateway replicas
|
| 130 |
+
Initialize circuit breaker for new service
|
| 131 |
+
Return registration confirmation
|
| 132 |
+
|
| 133 |
+
Behavior RouteRequest
|
| 134 |
+
Input:
|
| 135 |
+
route: ApiRoute
|
| 136 |
+
payload: dict
|
| 137 |
+
headers: dict
|
| 138 |
+
Output:
|
| 139 |
+
response: dict
|
| 140 |
+
latency: integer
|
| 141 |
+
Action:
|
| 142 |
+
Match incoming path and method to route definition
|
| 143 |
+
Check rate limit and authentication requirements
|
| 144 |
+
Resolve target service instance via discovery
|
| 145 |
+
Evaluate circuit breaker state before forwarding
|
| 146 |
+
Inject trace context headers
|
| 147 |
+
Forward request with timeout enforcement
|
| 148 |
+
Record latency metric and trace span
|
| 149 |
+
|
| 150 |
+
Behavior ExecuteSaga
|
| 151 |
+
Input:
|
| 152 |
+
sagaType: string
|
| 153 |
+
payload: dict
|
| 154 |
+
Output:
|
| 155 |
+
sagaId: string
|
| 156 |
+
status: string
|
| 157 |
+
Action:
|
| 158 |
+
Create saga instance with ordered steps
|
| 159 |
+
Begin first step and mark as in-progress
|
| 160 |
+
On step completion, advance to next step
|
| 161 |
+
On step failure, execute compensating actions in reverse
|
| 162 |
+
Persist saga state at each transition
|
| 163 |
+
Emit saga completion or compensation event
|
| 164 |
+
|
| 165 |
+
Behavior HandleCircuitBreaker
|
| 166 |
+
Input:
|
| 167 |
+
serviceName: string
|
| 168 |
+
result: string
|
| 169 |
+
latency: integer
|
| 170 |
+
Output:
|
| 171 |
+
newState: string
|
| 172 |
+
Action:
|
| 173 |
+
Record success or failure against breaker counters
|
| 174 |
+
If failure threshold exceeded, transition to Open state
|
| 175 |
+
If in Open state and cooldown elapsed, transition to HalfOpen
|
| 176 |
+
If HalfOpen and success threshold met, transition to Closed
|
| 177 |
+
If HalfOpen and failure detected, transition back to Open
|
| 178 |
+
Emit state change event to observability layer
|
| 179 |
+
|
| 180 |
+
Behavior DiscoverService
|
| 181 |
+
Input:
|
| 182 |
+
serviceName: string
|
| 183 |
+
version: string
|
| 184 |
+
region: string
|
| 185 |
+
Output:
|
| 186 |
+
instances: list
|
| 187 |
+
Action:
|
| 188 |
+
Query registry for matching service entries
|
| 189 |
+
Filter by version compatibility and region
|
| 190 |
+
Apply load-balancing weight to instance selection
|
| 191 |
+
Verify health status of returned instances
|
| 192 |
+
Return healthy instance list sorted by latency
|
| 193 |
+
|
| 194 |
+
Behavior CollectTrace
|
| 195 |
+
Input:
|
| 196 |
+
span: TraceSpan
|
| 197 |
+
Output:
|
| 198 |
+
accepted: boolean
|
| 199 |
+
Action:
|
| 200 |
+
Validate trace and span IDs are present
|
| 201 |
+
Link span to parent if parentSpanId exists
|
| 202 |
+
Calculate span duration from start and end times
|
| 203 |
+
Store span in trace backend
|
| 204 |
+
Check for trace completion (all spans received)
|
| 205 |
+
Emit trace-complete event if root span received
|
| 206 |
+
|
| 207 |
+
# Level 4: Conditions
|
| 208 |
+
Condition: ServiceUnhealthy
|
| 209 |
+
When service instance misses 3 consecutive heartbeats
|
| 210 |
+
Then mark instance as unhealthy and remove from active routing pool
|
| 211 |
+
|
| 212 |
+
Condition: RateLimitExceeded
|
| 213 |
+
When request count per minute exceeds route rateLimit threshold
|
| 214 |
+
Then return HTTP 429 with retry-after header and log throttle event
|
| 215 |
+
|
| 216 |
+
Condition: SagaTimeout
|
| 217 |
+
When saga execution exceeds timeoutAt without completion
|
| 218 |
+
Then trigger compensating transactions for all completed steps and mark saga as timed_out
|
| 219 |
+
|
| 220 |
+
# Level 5: Events
|
| 221 |
+
Event: OnServiceRegistered
|
| 222 |
+
On new service instance registered in discovery
|
| 223 |
+
Action: Update API gateway route table and warm connection pool to new instance
|
| 224 |
+
|
| 225 |
+
Event: OnCircuitBreakerStateChanged
|
| 226 |
+
On circuit breaker transitions between Open, Closed, or HalfOpen states
|
| 227 |
+
Action: Notify monitoring system and adjust routing weights away from degraded service
|
| 228 |
+
|
| 229 |
+
Event: OnSagaStepCompleted
|
| 230 |
+
On a saga participant confirms step completion
|
| 231 |
+
Action: Advance saga state machine and dispatch next step to next participant
|
| 232 |
+
|
| 233 |
+
Event: OnTraceAnomaly
|
| 234 |
+
On trace duration exceeds SLO threshold or error rate spikes
|
| 235 |
+
Action: Create incident alert and trigger automated diagnostic collection
|
| 236 |
+
|
| 237 |
+
# Level 6: Concurrency
|
| 238 |
+
Parallel:
|
| 239 |
+
Service health monitoring across all registered instances
|
| 240 |
+
Metrics aggregation from all services into centralized time-series store
|
| 241 |
+
Log streaming from all service containers to log collector
|
| 242 |
+
Circuit breaker state evaluation for all downstream connections
|
| 243 |
+
Trace span ingestion and parent-child linking across services
|
| 244 |
+
|
| 245 |
+
# Level 7: Optimization
|
| 246 |
+
Optimize: Inter-service call latency
|
| 247 |
+
Priority: Prefer collocated instances in same availability zone; then by lowest p99 latency history
|
| 248 |
+
|
| 249 |
+
Optimize: Gateway routing efficiency
|
| 250 |
+
Priority: Cache route lookups with LRU eviction; pre-warm connections to top percentile services
|
| 251 |
+
|
| 252 |
+
# Level 8: Learning
|
| 253 |
+
Learn: Service failure patterns
|
| 254 |
+
Goal: Predict circuit breaker trips before they occur based on latency and error rate trends
|
| 255 |
+
Adapt: Circuit breaker thresholds
|
| 256 |
+
Based: Historical failure pattern analysis across sliding 1-hour window
|
| 257 |
+
|
| 258 |
+
Learn: Optimal retry backoff intervals
|
| 259 |
+
Goal: Minimize retry storm risk while maximizing recovery speed
|
| 260 |
+
Adapt: Retry backoff multiplier and max retry count
|
| 261 |
+
Based: Downstream service recovery time distributions and error categorization
|
| 262 |
+
|
| 263 |
+
# Level 9: Security
|
| 264 |
+
Security:
|
| 265 |
+
Encrypt: All inter-service communication via mutual TLS with certificate rotation every 24 hours
|
| 266 |
+
Encrypt: Saga state payload containing PII using AES-256-GCM envelope encryption
|
| 267 |
+
Protect: API gateway against SQL injection, XSS, and request smuggling via WAF rules
|
| 268 |
+
Protect: Service registry from unauthorized writes with RBAC and signed registrations
|
| 269 |
+
Protect: Trace data from leaking sensitive headers by applying redaction rules
|
| 270 |
+
|
| 271 |
+
# Level 10: Native
|
| 272 |
+
Native: Python
|
| 273 |
+
{
|
| 274 |
+
import asyncio
|
| 275 |
+
from dataclasses import dataclass, field
|
| 276 |
+
from typing import Optional, Dict, List
|
| 277 |
+
from enum import Enum
|
| 278 |
+
import time
|
| 279 |
+
|
| 280 |
+
class BreakerState(Enum):
|
| 281 |
+
CLOSED = "closed"
|
| 282 |
+
OPEN = "open"
|
| 283 |
+
HALF_OPEN = "half_open"
|
| 284 |
+
|
| 285 |
+
@dataclass
|
| 286 |
+
class CircuitBreakerConfig:
|
| 287 |
+
failure_threshold: int = 5
|
| 288 |
+
success_threshold: int = 3
|
| 289 |
+
open_duration_seconds: int = 30
|
| 290 |
+
half_open_max_calls: int = 2
|
| 291 |
+
|
| 292 |
+
class CircuitBreaker:
|
| 293 |
+
def __init__(self, service_name: str, config: CircuitBreakerConfig = None):
|
| 294 |
+
self.service_name = service_name
|
| 295 |
+
self.config = config or CircuitBreakerConfig()
|
| 296 |
+
self.state = BreakerState.CLOSED
|
| 297 |
+
self.failure_count = 0
|
| 298 |
+
self.success_count = 0
|
| 299 |
+
self.last_failure_time: Optional[float] = None
|
| 300 |
+
self.half_open_calls = 0
|
| 301 |
+
|
| 302 |
+
def record_success(self):
|
| 303 |
+
if self.state == BreakerState.HALF_OPEN:
|
| 304 |
+
self.success_count += 1
|
| 305 |
+
if self.success_count >= self.config.success_threshold:
|
| 306 |
+
self.state = BreakerState.CLOSED
|
| 307 |
+
self.failure_count = 0
|
| 308 |
+
self.success_count = 0
|
| 309 |
+
elif self.state == BreakerState.CLOSED:
|
| 310 |
+
self.failure_count = max(0, self.failure_count - 1)
|
| 311 |
+
|
| 312 |
+
def record_failure(self):
|
| 313 |
+
self.failure_count += 1
|
| 314 |
+
self.last_failure_time = time.time()
|
| 315 |
+
if self.state == BreakerState.HALF_OPEN:
|
| 316 |
+
self.state = BreakerState.OPEN
|
| 317 |
+
self.success_count = 0
|
| 318 |
+
elif self.state == BreakerState.CLOSED:
|
| 319 |
+
if self.failure_count >= self.config.failure_threshold:
|
| 320 |
+
self.state = BreakerState.OPEN
|
| 321 |
+
|
| 322 |
+
def can_execute(self) -> bool:
|
| 323 |
+
if self.state == BreakerState.CLOSED:
|
| 324 |
+
return True
|
| 325 |
+
if self.state == BreakerState.OPEN:
|
| 326 |
+
if self.last_failure_time and \
|
| 327 |
+
(time.time() - self.last_failure_time) >= self.config.open_duration_seconds:
|
| 328 |
+
self.state = BreakerState.HALF_OPEN
|
| 329 |
+
self.success_count = 0
|
| 330 |
+
self.half_open_calls = 0
|
| 331 |
+
return True
|
| 332 |
+
return False
|
| 333 |
+
if self.state == BreakerState.HALF_OPEN:
|
| 334 |
+
return self.half_open_calls < self.config.half_open_max_calls
|
| 335 |
+
return False
|
| 336 |
+
|
| 337 |
+
class SagaOrchestrator:
|
| 338 |
+
def __init__(self):
|
| 339 |
+
self.sagas: Dict[str, dict] = {}
|
| 340 |
+
|
| 341 |
+
async def execute_saga(self, saga_id: str, steps: List[dict]):
|
| 342 |
+
self.sagas[saga_id] = {
|
| 343 |
+
"steps": steps, "completed": [], "status": "running"
|
| 344 |
+
}
|
| 345 |
+
for i, step in enumerate(steps):
|
| 346 |
+
try:
|
| 347 |
+
result = await step["action"]()
|
| 348 |
+
self.sagas[saga_id]["completed"].append(i)
|
| 349 |
+
except Exception as e:
|
| 350 |
+
self.sagas[saga_id]["status"] = "compensating"
|
| 351 |
+
await self._compensate(saga_id)
|
| 352 |
+
raise
|
| 353 |
+
|
| 354 |
+
async def _compensate(self, saga_id: str):
|
| 355 |
+
saga = self.sagas[saga_id]
|
| 356 |
+
for idx in reversed(saga["completed"]):
|
| 357 |
+
compensate = saga["steps"][idx].get("compensate")
|
| 358 |
+
if compensate:
|
| 359 |
+
try:
|
| 360 |
+
await compensate()
|
| 361 |
+
except Exception:
|
| 362 |
+
pass
|
| 363 |
+
saga["status"] = "compensated"
|
| 364 |
+
|
| 365 |
+
breaker = CircuitBreaker("payment-service")
|
| 366 |
+
if breaker.can_execute():
|
| 367 |
+
print(f"Circuit is {breaker.state.value}, request allowed")
|
| 368 |
+
}
|