You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
103 lines
2.1 KiB
103 lines
2.1 KiB
package simulation |
|
|
|
import "math/rand" |
|
|
|
type MicroserviceNode struct { |
|
ID string |
|
Label string |
|
APIEndpoint string |
|
RateLimit int // max requests per tick |
|
CircuitBreaker bool |
|
CircuitState string // "closed", "open", "half-open" |
|
ErrorCount int |
|
CurrentLoad int |
|
Queue []*Request |
|
Output []*Request |
|
Alive bool |
|
Targets []string |
|
} |
|
|
|
func (n *MicroserviceNode) GetID() string { return n.ID } |
|
|
|
func (n *MicroserviceNode) Type() string { return "microservice" } |
|
|
|
func (n *MicroserviceNode) IsAlive() bool { return n.Alive } |
|
|
|
func (n *MicroserviceNode) Receive(req *Request) { |
|
n.Queue = append(n.Queue, req) |
|
} |
|
|
|
func (n *MicroserviceNode) Emit() []*Request { |
|
out := append([]*Request(nil), n.Output...) |
|
n.Output = n.Output[:0] |
|
return out |
|
} |
|
|
|
func (n *MicroserviceNode) Tick(tick int, currentTimeMs int) { |
|
if !n.Alive { |
|
return |
|
} |
|
|
|
// Simulate circuit breaker state transitions |
|
switch n.CircuitState { |
|
case "open": |
|
// Skip processing |
|
return |
|
case "half-open": |
|
// Allow limited testing traffic |
|
if len(n.Queue) == 0 { |
|
return |
|
} |
|
req := n.Queue[0] |
|
n.Queue = n.Queue[1:] |
|
req.LatencyMS += 15 |
|
req.Path = append(req.Path, n.ID+"(half-open)") |
|
success := simulateSuccess() |
|
if success { |
|
n.CircuitState = "closed" |
|
n.ErrorCount = 0 |
|
n.Output = append(n.Output, req) |
|
} else { |
|
n.ErrorCount++ |
|
n.CircuitState = "open" |
|
} |
|
return |
|
} |
|
|
|
// "closed" circuit - normal processing |
|
toProcess := min(len(n.Queue), n.RateLimit) |
|
for i := 0; i < toProcess; i++ { |
|
req := n.Queue[i] |
|
req.LatencyMS += 10 |
|
req.Path = append(req.Path, n.ID) |
|
|
|
if simulateFailure() { |
|
n.ErrorCount++ |
|
if n.CircuitBreaker && n.ErrorCount > 5 { |
|
n.CircuitState = "open" |
|
break |
|
} |
|
continue |
|
} |
|
|
|
n.Output = append(n.Output, req) |
|
} |
|
n.Queue = n.Queue[toProcess:] |
|
|
|
// Health check: simple example |
|
n.Alive = n.CircuitState != "open" |
|
} |
|
|
|
func simulateFailure() bool { |
|
// Simulate 10% failure rate |
|
return randInt(1, 100) <= 10 |
|
} |
|
|
|
func simulateSuccess() bool { |
|
// Simulate 90% success rate |
|
return randInt(1, 100) <= 90 |
|
} |
|
|
|
func randInt(min, max int) int { |
|
return min + rand.Intn(max-min+1) |
|
}
|
|
|