To make it deterministic, we can do something like this:
func hibernate (seconds: Int) async {
try? await Task.sleep (until: .now + .seconds (seconds))
}
actor System {
enum State {
case initial
case starting
case started
case stopping
case stopped
case error (Error)
}
private var _state: State = .initial
func set (state: State) {
self._state = state
}
func state () -> State {
return _state
}
}
nonisolated func startAllThings (_ s: System) {
Task {
await s.set (state: .starting)
// await thing.start()
await hibernate (seconds: 7)
// ready
await s.set (state: .started)
}
}
nonisolated func stopAllThings(_ s: System) {
Task {
var ttl = 7
while true {
let state = await s.state()
if case .started = state {
// all up, stop them
await s.set (state: .stopping)
// await thing.stop()
await hibernate (seconds: 3)
await s.set (state: .stopped)
break
}
else {
if ttl == 0 {
fatalError ("took too long")
}
else {
ttl -= 1
// try again after one second until ttl is zero
await hibernate (seconds: 1)
}
}
}
}
}
Now deterministic.
startAllThings()
stopAllThings()