github.com/ergo-services/ergo@v1.999.224/gen/saga_worker.go (about) 1 package gen 2 3 import ( 4 "fmt" 5 6 "github.com/ergo-services/ergo/etf" 7 "github.com/ergo-services/ergo/lib" 8 ) 9 10 // SagaWorkerBehavior 11 type SagaWorkerBehavior interface { 12 ServerBehavior 13 // Mandatory callbacks 14 15 // HandleJobStart invoked on a worker start 16 HandleJobStart(process *SagaWorkerProcess, job SagaJob) error 17 // HandleJobCancel invoked if transaction was canceled before the termination. 18 HandleJobCancel(process *SagaWorkerProcess, reason string) 19 20 // Optional callbacks 21 22 // HandleJobCommit invoked if this job was a part of the transaction 23 // with enabled TwoPhaseCommit option. All workers involved in this TX 24 // handling are receiving this call. Callback invoked before the termination. 25 HandleJobCommit(process *SagaWorkerProcess, final interface{}) 26 27 // HandleWorkerInfo this callback is invoked on Process.Send. This method is optional 28 // for the implementation 29 HandleWorkerInfo(process *SagaWorkerProcess, message etf.Term) ServerStatus 30 // HandleWorkerCast this callback is invoked on ServerProcess.Cast. This method is optional 31 // for the implementation 32 HandleWorkerCast(process *SagaWorkerProcess, message etf.Term) ServerStatus 33 // HandleWorkerCall this callback is invoked on ServerProcess.Call. This method is optional 34 // for the implementation 35 HandleWorkerCall(process *SagaWorkerProcess, from ServerFrom, message etf.Term) (etf.Term, ServerStatus) 36 // HandleWorkerDirect this callback is invoked on Process.Direct. This method is optional 37 // for the implementation 38 HandleWorkerDirect(process *SagaWorkerProcess, ref etf.Ref, message interface{}) (interface{}, DirectStatus) 39 40 // HandleWorkerTerminate this callback invoked on a process termination 41 HandleWorkerTerminate(process *SagaWorkerProcess, reason string) 42 } 43 44 // SagaWorker 45 type SagaWorker struct { 46 Server 47 } 48 49 // SagaWorkerProcess 50 type SagaWorkerProcess struct { 51 ServerProcess 52 53 behavior SagaWorkerBehavior 54 job SagaJob 55 done bool 56 cancel bool 57 } 58 59 type messageSagaJobStart struct { 60 job SagaJob 61 } 62 type messageSagaJobDone struct{} 63 type messageSagaJobCancel struct { 64 reason string 65 } 66 type messageSagaJobCommit struct { 67 final interface{} 68 } 69 type messageSagaJobInterim struct { 70 pid etf.Pid 71 interim interface{} 72 } 73 type messageSagaJobResult struct { 74 pid etf.Pid 75 result interface{} 76 } 77 type messageSagaJobLifespan struct { 78 pid etf.Pid 79 } 80 81 // 82 // SagaWorkerProcess methods 83 // 84 85 // SendResult sends the result and terminates this worker if 2PC is disabled. Otherwise, 86 // will be waiting for cancel/commit signal. 87 func (wp *SagaWorkerProcess) SendResult(result interface{}) error { 88 if wp.done { 89 return ErrSagaResultAlreadySent 90 } 91 if wp.cancel { 92 return ErrSagaTxCanceled 93 } 94 message := messageSagaJobResult{ 95 pid: wp.Self(), 96 result: result, 97 } 98 err := wp.Cast(wp.job.saga, message) 99 if err != nil { 100 return err 101 } 102 wp.done = true 103 104 // if 2PC is enable do not terminate this worker 105 if wp.job.commit { 106 return nil 107 } 108 109 wp.Cast(wp.Self(), messageSagaJobDone{}) 110 return nil 111 } 112 113 // SendInterim 114 func (wp *SagaWorkerProcess) SendInterim(interim interface{}) error { 115 if wp.done { 116 return ErrSagaResultAlreadySent 117 } 118 if wp.cancel { 119 return ErrSagaTxCanceled 120 } 121 message := messageSagaJobInterim{ 122 pid: wp.Self(), 123 interim: interim, 124 } 125 return wp.Cast(wp.job.saga, message) 126 } 127 128 // Server callbacks 129 130 // Init 131 func (w *SagaWorker) Init(process *ServerProcess, args ...etf.Term) error { 132 behavior, ok := process.Behavior().(SagaWorkerBehavior) 133 if !ok { 134 return fmt.Errorf("Not a SagaWorkerBehavior") 135 } 136 workerProcess := &SagaWorkerProcess{ 137 ServerProcess: *process, 138 behavior: behavior, 139 } 140 process.State = workerProcess 141 return nil 142 } 143 144 // HandleCast 145 func (w *SagaWorker) HandleCast(process *ServerProcess, message etf.Term) ServerStatus { 146 wp := process.State.(*SagaWorkerProcess) 147 switch m := message.(type) { 148 case messageSagaJobStart: 149 wp.job = m.job 150 err := wp.behavior.HandleJobStart(wp, wp.job) 151 if err != nil { 152 return err 153 } 154 155 // if job is done and 2PC is disabled 156 // stop this worker with 'normal' as a reason 157 if wp.done && !wp.job.commit { 158 return ServerStatusStop 159 } 160 return ServerStatusOK 161 case messageSagaJobDone: 162 return ServerStatusStop 163 case messageSagaJobCommit: 164 wp.behavior.HandleJobCommit(wp, m.final) 165 return ServerStatusStop 166 case messageSagaJobCancel: 167 wp.cancel = true 168 wp.behavior.HandleJobCancel(wp, m.reason) 169 return ServerStatusStop 170 default: 171 return wp.behavior.HandleWorkerCast(wp, message) 172 } 173 } 174 175 // HandleCall 176 func (w *SagaWorker) HandleCall(process *ServerProcess, from ServerFrom, message etf.Term) (etf.Term, ServerStatus) { 177 p := process.State.(*SagaWorkerProcess) 178 return p.behavior.HandleWorkerCall(p, from, message) 179 } 180 181 // HandleDirect 182 func (w *SagaWorker) HandleDirect(process *ServerProcess, ref etf.Ref, message interface{}) (interface{}, DirectStatus) { 183 p := process.State.(*SagaWorkerProcess) 184 return p.behavior.HandleWorkerDirect(p, ref, message) 185 } 186 187 // HandleInfo 188 func (w *SagaWorker) HandleInfo(process *ServerProcess, message etf.Term) ServerStatus { 189 p := process.State.(*SagaWorkerProcess) 190 return p.behavior.HandleWorkerInfo(p, message) 191 } 192 193 // Terminate 194 func (w *SagaWorker) Terminate(process *ServerProcess, reason string) { 195 p := process.State.(*SagaWorkerProcess) 196 p.behavior.HandleWorkerTerminate(p, reason) 197 return 198 } 199 200 // default callbacks 201 202 // HandleJobCommit 203 func (w *SagaWorker) HandleJobCommit(process *SagaWorkerProcess, final interface{}) { 204 lib.Warning("HandleJobCommit: unhandled message %#v", final) 205 return 206 } 207 208 // HandleWorkerInfo 209 func (w *SagaWorker) HandleWorkerInfo(process *SagaWorkerProcess, message etf.Term) ServerStatus { 210 lib.Warning("HandleWorkerInfo: unhandled message %#v", message) 211 return ServerStatusOK 212 } 213 214 // HandleWorkerCast 215 func (w *SagaWorker) HandleWorkerCast(process *SagaWorkerProcess, message etf.Term) ServerStatus { 216 lib.Warning("HandleWorkerCast: unhandled message %#v", message) 217 return ServerStatusOK 218 } 219 220 // HandleWorkerCall 221 func (w *SagaWorker) HandleWorkerCall(process *SagaWorkerProcess, from ServerFrom, message etf.Term) (etf.Term, ServerStatus) { 222 lib.Warning("HandleWorkerCall: unhandled message (from %#v) %#v", from, message) 223 return etf.Atom("ok"), ServerStatusOK 224 } 225 226 // HandleWorkerDirect 227 func (w *SagaWorker) HandleWorkerDirect(process *SagaWorkerProcess, ref etf.Ref, message interface{}) (interface{}, DirectStatus) { 228 lib.Warning("HandleWorkerDirect: unhandled message %#v", message) 229 return nil, DirectStatusOK 230 } 231 232 // HandleWorkerTerminate 233 func (w *SagaWorker) HandleWorkerTerminate(process *SagaWorkerProcess, reason string) { 234 return 235 }