Artifact 1d9f957c99ffe50e972f6337aaeab189b67d98aea3a8e23cf29243b915177e9d:
- File
sim/schedule.go
— part of check-in
[eda7960b81]
at
2026-04-23 19:23:42
on branch trunk
— rename module to github.com/danmestas/EdgeSync
Fix the case-sensitive module path to match the actual GitHub repo URL (danmestas/EdgeSync). Remove tracked leaf/leaf binary and ignore .claude/skills/ scratchpad dirs. (user: [email protected], size: 3255) [annotate] [blame] [check-ins using] [more...]
package sim import ( "fmt" "math/rand" "sort" "strings" "time" ) type FaultType int const ( FaultPartition FaultType = iota FaultHealPartition FaultLatency FaultHealLatency FaultDropConns FaultBridgeRestart FaultLeafRestart FaultHealAll ) func (f FaultType) String() string { switch f { case FaultPartition: return "partition" case FaultHealPartition: return "heal-partition" case FaultLatency: return "latency" case FaultHealLatency: return "heal-latency" case FaultDropConns: return "drop-connections" case FaultBridgeRestart: return "bridge-restart" case FaultLeafRestart: return "leaf-restart" case FaultHealAll: return "heal-all" } return "unknown" } type FaultEvent struct { Time time.Duration Type FaultType Target string Param time.Duration } func (e FaultEvent) String() string { s := fmt.Sprintf("t=%s %s", e.Time, e.Type) if e.Target != "" { s += " " + e.Target } if e.Param > 0 { s += fmt.Sprintf(" (%s)", e.Param) } return s } type FaultSchedule struct { Events []FaultEvent } func (s *FaultSchedule) String() string { var lines []string for _, e := range s.Events { lines = append(lines, e.String()) } return strings.Join(lines, "\n") } func GenerateSchedule(seed int64, severity Level, faultDuration time.Duration, numLeaves int) *FaultSchedule { if severity == LevelNormal { return &FaultSchedule{} } rng := rand.New(rand.NewSource(seed)) var events []FaultEvent var numFaults int switch severity { case LevelAdversarial: numFaults = 2 + rng.Intn(4) case LevelHostile: numFaults = 5 + rng.Intn(6) } for range numFaults { offset := time.Duration(rng.Int63n(int64(faultDuration))) var ft FaultType switch severity { case LevelAdversarial: switch rng.Intn(3) { case 0: ft = FaultPartition case 1: ft = FaultLatency case 2: ft = FaultDropConns } case LevelHostile: switch rng.Intn(5) { case 0: ft = FaultPartition case 1: ft = FaultLatency case 2: ft = FaultDropConns case 3: ft = FaultBridgeRestart case 4: ft = FaultLeafRestart } } target := fmt.Sprintf("leaf-%d", rng.Intn(numLeaves)) if ft == FaultBridgeRestart { target = "bridge" } param := time.Duration(0) if ft == FaultLatency { param = time.Duration(100+rng.Intn(900)) * time.Millisecond } events = append(events, FaultEvent{ Time: offset, Type: ft, Target: target, Param: param, }) if ft == FaultPartition { healOffset := offset + time.Duration(1+rng.Intn(5))*time.Second if healOffset > faultDuration { healOffset = faultDuration } events = append(events, FaultEvent{ Time: healOffset, Type: FaultHealPartition, Target: target, }) } if ft == FaultLatency { healOffset := offset + time.Duration(1+rng.Intn(3))*time.Second if healOffset > faultDuration { healOffset = faultDuration } events = append(events, FaultEvent{ Time: healOffset, Type: FaultHealLatency, }) } } events = append(events, FaultEvent{ Time: faultDuration, Type: FaultHealAll, }) sort.Slice(events, func(i, j int) bool { return events[i].Time < events[j].Time }) return &FaultSchedule{Events: events} }