This repository has no description
0

Configure Feed

Select the types of activity you want to include in your feed.

core / spindle / mill / lease.go
3.9 kB 186 lines
1package mill 2 3import ( 4 "sync" 5 6 "tangled.org/core/spindle/models" 7 8 millv1 "tangled.org/core/spindle/mill/proto/gen" 9) 10 11// the mill's view of a remote attempt 12type leaseState int32 13 14const ( 15 // won a bid, executor is holding a seat, not yet committed 16 leaseReserved leaseState = iota 17 // CommitLease sent. the executor may already be running, but the mill 18 // may not have seen Committed yet 19 leaseCommitting 20 // CommitLease sent and acked. job is running on the executor 21 leaseRunning 22 // terminal result arrived or we gave up, no further action 23 leaseDone 24) 25 26type cancelAction int 27 28const ( 29 cancelNoop cancelAction = iota 30 cancelLocal 31 cancelRemote 32) 33 34// mill-side fencing token for one placed job 35type RemoteLease struct { 36 id string 37 nodeID string 38 epoch string 39 engine string 40 wid models.WorkflowId // job this lease carries, set once placed 41 // restored after a mill restart. no RunStep waits on it, so terminals 42 // and death are authored directly. set before publication, never mutated 43 orphaned bool 44 claimed bool 45 cancelAcked bool 46 cleanedUp bool 47 cleanupRetry bool 48 49 mu sync.Mutex 50 state leaseState 51 cancel bool 52 reason string 53 released bool 54 terminal chan *millv1.AttemptResult // buffered(1), RunStep waits here 55 56 finishMu sync.Mutex 57} 58 59func newLease(id, nodeID, epoch, engine string) *RemoteLease { 60 return &RemoteLease{ 61 id: id, 62 nodeID: nodeID, 63 epoch: epoch, 64 engine: engine, 65 state: leaseReserved, 66 terminal: make(chan *millv1.AttemptResult, 1), 67 } 68} 69 70func (l *RemoteLease) setState(s leaseState) { 71 l.mu.Lock() 72 l.state = s 73 l.mu.Unlock() 74} 75 76func (l *RemoteLease) markCommitting() bool { 77 l.mu.Lock() 78 defer l.mu.Unlock() 79 if l.state == leaseDone { 80 return false 81 } 82 if l.state == leaseReserved { 83 l.state = leaseCommitting 84 } 85 return true 86} 87 88func (l *RemoteLease) markRunning() { 89 l.mu.Lock() 90 defer l.mu.Unlock() 91 if l.state != leaseDone { 92 l.state = leaseRunning 93 } 94} 95 96func (l *RemoteLease) getState() leaseState { 97 l.mu.Lock() 98 defer l.mu.Unlock() 99 return l.state 100} 101 102// only one caller gets to mark it done 103func (l *RemoteLease) markDone() bool { 104 l.mu.Lock() 105 defer l.mu.Unlock() 106 if l.state == leaseDone { 107 return false 108 } 109 l.state = leaseDone 110 return true 111} 112 113func (l *RemoteLease) requestCancel(reason string) cancelAction { 114 l.mu.Lock() 115 defer l.mu.Unlock() 116 if l.state == leaseDone { 117 return cancelNoop 118 } 119 l.cancel = true 120 l.reason = reason 121 if l.state == leaseReserved { 122 return cancelLocal 123 } 124 return cancelRemote 125} 126 127func (l *RemoteLease) cancelRequested() (bool, string) { 128 l.mu.Lock() 129 defer l.mu.Unlock() 130 return l.cancel, l.reason 131} 132 133func (l *RemoteLease) releaseState() (leaseState, bool) { 134 l.mu.Lock() 135 defer l.mu.Unlock() 136 l.released = true 137 return l.state, l.cancel 138} 139 140func (l *RemoteLease) cleanupReady() bool { 141 l.mu.Lock() 142 defer l.mu.Unlock() 143 return l.released && l.state == leaseDone 144} 145 146func (l *RemoteLease) deliverCancelled(reason string) { 147 l.deliverTerminal(&millv1.AttemptResult{ 148 Status: millv1.TerminalStatus_CANCELLED, 149 Error: reason, 150 }) 151} 152 153// hands the terminal to a waiting RunStep without blocking. duplicates 154// (eg. reconnect replays) just drop, the channel holds one and the lease 155// is already done 156func (l *RemoteLease) deliverTerminal(res *millv1.AttemptResult) { 157 if !l.markDone() { 158 return 159 } 160 select { 161 case l.terminal <- res: 162 default: 163 } 164} 165 166// mill's synthetic single step. real steps run on the executor and the 167// mill never mirrors them 168type remoteStep struct{} 169 170func (remoteStep) Name() string { return "remote execution" } 171func (remoteStep) Command() string { return "" } 172func (remoteStep) Kind() models.StepKind { return models.StepKindSystem } 173 174// what AcquireWorkflowSlot returns. Release unwinds placement 175type millSlot struct { 176 fleet *Mill 177 lease *RemoteLease 178 once sync.Once 179} 180 181func (s *millSlot) Release() { 182 if s == nil { 183 return 184 } 185 s.once.Do(func() { s.fleet.releaseSlot(s) }) 186}