1 import Base 2 3 # Represents the owner lifecycle around lock, recovery, endpoint, and shutdown. 4 type State is Data: 5 Starting{} 6 Locked{} 7 Recovered{} 8 Serving{} 9 Stopping{} 10 EndpointRemoved{} 11 Closed{} 12 Failed{} 13 14 # Represents one external result or requested lifecycle action. 15 type OwnerEvent is Data: 16 AcquireLock{} 17 RecoveryComplete{} 18 PublishEndpoint{} 19 BeginShutdown{} 20 RemoveEndpoint{} 21 ReleaseLock{} 22 Failure{} 23 24 # Returns the next legal state or rejects an out-of-order event. 25 type Decision is Data: 26 Advance{state: State} 27 Reject{} 28 29 # Classifies durable failures before mapping them into wire statuses. 30 type FailureKind is Data: 31 BusyFailure{} 32 TimeoutFailure{} 33 NotFoundFailure{} 34 InvalidArgumentFailure{} 35 AlreadyExistsFailure{} 36 UnsupportedPlatformFailure{} 37 ResourceLimitFailure{} 38 CorruptionFailure{} 39 IoFailure{} 40 CommitUnknownFailure{} 41 42 # Defines the typed response statuses available to coordinator clients. 43 type ReplyStatus is Data: 44 SuccessStatus{} 45 InvalidArgumentStatus{} 46 AlreadyExistsStatus{} 47 UnsupportedPlatformStatus{} 48 NotFoundStatus{} 49 BusyStatus{} 50 TimeoutStatus{} 51 ResourceLimitStatus{} 52 CorruptionStatus{} 53 IoStatus{} 54 CommitUnknownStatus{} 55 56 # Records whether the open path acquired, contended on, or failed to acquire the lock. 57 type LockOutcome is Data: 58 LockAcquired{} 59 LockBusy{} 60 LockFailed{} 61 62 # Records whether canonical endpoint inspection found a live candidate. 63 type EndpointOutcome is Data: 64 EndpointPresent{} 65 EndpointMissing{} 66 EndpointFailed{} 67 68 # Selects local ownership, remote use, or a typed open failure. 69 type OpenRole is Data: 70 LocalOwner{} 71 ExistingOwnerClient{} 72 ReturnBusy{} 73 PropagateOpenFailure{} 74 75 # Chooses local ownership or an established endpoint from lock observations. 76 def open.role(lock: LockOutcome, endpoint: EndpointOutcome) -> OpenRole: 77 match lock: 78 case LockAcquired{}: LocalOwner{} 79 case LockBusy{}: 80 match endpoint: 81 case EndpointPresent{}: ExistingOwnerClient{} 82 case EndpointMissing{}: ReturnBusy{} 83 case EndpointFailed{}: PropagateOpenFailure{} 84 case LockFailed{}: PropagateOpenFailure{} 85 86 def failure.status(kind: FailureKind) -> ReplyStatus: 87 match kind: 88 case BusyFailure{}: BusyStatus{} 89 case TimeoutFailure{}: TimeoutStatus{} 90 case NotFoundFailure{}: NotFoundStatus{} 91 case InvalidArgumentFailure{}: InvalidArgumentStatus{} 92 case AlreadyExistsFailure{}: AlreadyExistsStatus{} 93 case UnsupportedPlatformFailure{}: UnsupportedPlatformStatus{} 94 case ResourceLimitFailure{}: ResourceLimitStatus{} 95 case CorruptionFailure{}: CorruptionStatus{} 96 case IoFailure{}: IoStatus{} 97 case CommitUnknownFailure{}: CommitUnknownStatus{} 98 99 # Applies one lifecycle event without performing host effects. 100 def step(state: State, event: OwnerEvent) -> Decision: 101 match state: 102 case Starting{}: 103 match event: 104 case AcquireLock{}: Advance{Locked{}} 105 case Failure{}: Advance{Failed{}} 106 case _: Reject{} 107 case Locked{}: 108 match event: 109 case RecoveryComplete{}: Advance{Recovered{}} 110 case Failure{}: Advance{Failed{}} 111 case _: Reject{} 112 case Recovered{}: 113 match event: 114 case PublishEndpoint{}: Advance{Serving{}} 115 case Failure{}: Advance{Failed{}} 116 case _: Reject{} 117 case Serving{}: 118 match event: 119 case BeginShutdown{}: Advance{Stopping{}} 120 case Failure{}: Advance{Failed{}} 121 case _: Reject{} 122 case Stopping{}: 123 match event: 124 case RemoveEndpoint{}: Advance{EndpointRemoved{}} 125 case Failure{}: Advance{Failed{}} 126 case _: Reject{} 127 case EndpointRemoved{}: 128 match event: 129 case ReleaseLock{}: Advance{Closed{}} 130 case Failure{}: Advance{Failed{}} 131 case _: Reject{} 132 case Closed{}: Reject{} 133 case Failed{}: Reject{}