Saga Runner | 220801


Saga Runner

I am working on getting the saga its list of commands to execute. I made some notes to help me with error handling

 Order of Transaction is import in passed ListOfTransactions
	 - Compensatable Transactions:
	  -- NOTE: Compensatable Transactions should have two Transaction Commands. The first one for the intended Transaction and the second one to Roll back that Transaction encase of failure/issues in any of the following Transaction. Its okay if th Compensatable does not have an Second Transaction Action Command. I think I will try and use a an empty Transaction Command to keep the logic simple in this implenatation 
	  -- Can only be in place prior in order to the Pivot Transaction and never after 
	  -- If there is no Pivot Transaction Action then there cannot be any Compensatable Transactions 
	- Pivot Transaction: 
	  -- There can only be one per list of Transactions or 
	- Retryable Transactions: 
	  -- If the Pivot Transaction exist in the List then Retryable Transactions can only be in after that Pivot Transaction
	  -- Retryable Transactions should never be in the list of Transactions prior to the Pivot Transaction if it exists  
 - NOTE Other Use Cases:
    -- You can have a Pivot Transaction without Compensatable Transaction(s) 
    -- You can just have list of Transactions without Pivot nor Compensatable Transactions(So just Retryable Transactions (Granted idk why you would tho))

_1404 So working on the Execution of the saga I was trying check the list of the transactions to confirm that it sticking to the Saga Pattern at the same time of Execution. I was doing this to keep the Big O notation on the smaller side if possible, but am running into an issue where I could execute some of the transactions then near the end of the Saga List’s of Transaction and find an issue with logically with it. Which shouldn’t be and issue per say cause the ones that change things could just Compensate. But I am trying to think of the worse case with that would that really save me time in comparison to just using a constructor for the Sagas and checking the order right there.

I think I going to implement a constructor to keep the code cleaner and try to limit myself from sending messed up Sages to Execute for time saving of O(n) to 2O(n) which are the same over a long enough time scale


func NewSagaOrchestrator(name string, transactions []Transaction) (*SagaOrchestrator, error) {  
   var sagaCreationErrorPrefix = "[ERROR] [SAGA_PATTERN] "  
  so := new(SagaOrchestrator)  
   so.Name = name  
   var countOfCommentableTransactions = 0  
  var countOfPivotTransactions = 0  
  var countOfRetryableTransactions = 0  
  // Loops through the list of transactions to check for acceptable order has been passed  
  for _, transaction := range transactions {  
 //Checks for Compensatable Transactions  
  // There cannot be a Pivot Transaction prior to any Compensatable Transaction
  // There cannot be Retryable Transactions prior to any Retryable Transactions  if transaction.GetTransactionType() == GetCompensatableTransactionType() {  
         countOfCommentableTransactions = countOfCommentableTransactions + 1  
  //Checking if it's before any Pivot Transactions  
  if countOfPivotTransactions > 0 {  
            return nil, errors.New(sagaCreationErrorPrefix + "[SAGA_CREATION] [Compensatable]| Cannot put Compensatable Transactions after a Pivot Transaction")  
         //Checking if it's before any Retryable Transactions  
  if countOfRetryableTransactions > 0 {  
            return nil, errors.New(sagaCreationErrorPrefix + "[SAGA_CREATION] [Compensatable]| Cannot put Compensatable Transactions before any Retryable Transaction(s)")  
 //Checks for Pivot Transaction  
 // There cannot be more than on pivot transaction 
 // There are no Retryable prior to the Pivot  if transaction.GetTransactionType() == GetPivotTransactionType() {  
         countOfPivotTransactions = countOfPivotTransactions + 1  
  //Checks that there is not already a Pivot Transaction in the List of Transactions  
  if countOfPivotTransactions > 1 {  
            return nil, errors.New(sagaCreationErrorPrefix + "[SAGA_CREATION] [Pivot]| There is more than one Pivot Transaction")  
         //Checks that there is not any Retryable Transactions prior in the list of Transactions  
  if countOfRetryableTransactions > 0 {  
            return nil, errors.New(sagaCreationErrorPrefix + "[SAGA_CREATION] [Pivot]| Cannot put Pivot Transaction After Retryable Transactions")  
//Checking Retryable  
//Note: currently 220801 that I do not think I need to check for anything for Retryable, cause the other two cover it. 
//but I will leave this code here just in case  if transaction.GetTransactionType() == GetPivotTransactionType() {  
         countOfRetryableTransactions = countOfRetryableTransactions + 1  
  //Checks at last Transaction in the list  
if index == lastIndex {  
   //Checks that there is a pivot if there is any Compensatable Transactions  
  if countOfPivotTransactions < 1 && countOfCompensatableTransactions > 0{  
      return nil, errors.New(sagaCreationErrorPrefix + "[SAGA_CREATION] | Compensatable Transactions have not Pivot Transactions")  
   // So it passes the checks above its good to go.   
 so.Transactions = transactions  
   return so, nil