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  }