github.com/kyma-project/kyma-environment-broker@v0.0.1/internal/process/deprovision_operation.go (about) 1 package process 2 3 import ( 4 "fmt" 5 "time" 6 7 "github.com/kyma-project/kyma-environment-broker/internal/storage/dberr" 8 9 "github.com/sirupsen/logrus" 10 11 "github.com/kyma-project/kyma-environment-broker/internal" 12 "github.com/kyma-project/kyma-environment-broker/internal/storage" 13 14 "github.com/pivotal-cf/brokerapi/v8/domain" 15 ) 16 17 type DeprovisionOperationManager struct { 18 storage storage.Operations 19 } 20 21 func NewDeprovisionOperationManager(storage storage.Operations) *DeprovisionOperationManager { 22 return &DeprovisionOperationManager{ 23 storage: storage, 24 } 25 } 26 27 // OperationSucceeded marks the operation as succeeded and only repeats it if there is a storage error 28 func (om *DeprovisionOperationManager) OperationSucceeded(operation internal.DeprovisioningOperation, description string, log logrus.FieldLogger) (internal.DeprovisioningOperation, time.Duration, error) { 29 updatedOperation, repeat, _ := om.update(operation, domain.Succeeded, description, log) 30 // repeat in case of storage error 31 if repeat != 0 { 32 return updatedOperation, repeat, nil 33 } 34 35 return updatedOperation, 0, nil 36 } 37 38 // OperationFailed marks the operation as failed and only repeats it if there is a storage error 39 func (om *DeprovisionOperationManager) OperationFailed(operation internal.DeprovisioningOperation, description string, err error, log logrus.FieldLogger) (internal.DeprovisioningOperation, time.Duration, error) { 40 updatedOperation, repeat, _ := om.update(operation, domain.Failed, description, log) 41 // repeat in case of storage error 42 if repeat != 0 { 43 return updatedOperation, repeat, nil 44 } 45 46 var retErr error 47 if err == nil { 48 // no exact err passed in 49 retErr = fmt.Errorf(description) 50 } else { 51 // keep the original err object for error categorizer 52 retErr = fmt.Errorf("%s: %w", description, err) 53 } 54 55 return updatedOperation, 0, retErr 56 } 57 58 // UpdateOperation updates a given operation and handles conflict situation 59 func (om *DeprovisionOperationManager) UpdateOperation(operation internal.DeprovisioningOperation, overwrite func(operation *internal.DeprovisioningOperation), log logrus.FieldLogger) (internal.DeprovisioningOperation, time.Duration, error) { 60 overwrite(&operation) 61 updatedOperation, err := om.storage.UpdateDeprovisioningOperation(operation) 62 switch { 63 case dberr.IsConflict(err): 64 { 65 op, err := om.storage.GetDeprovisioningOperationByID(operation.ID) 66 if err != nil { 67 log.Errorf("while getting operation: %v", err) 68 return operation, 1 * time.Minute, err 69 } 70 overwrite(op) 71 updatedOperation, err = om.storage.UpdateDeprovisioningOperation(*op) 72 if err != nil { 73 log.Errorf("while updating operation after conflict: %v", err) 74 return operation, 1 * time.Minute, err 75 } 76 } 77 case err != nil: 78 log.Errorf("while updating operation: %v", err) 79 return operation, 1 * time.Minute, err 80 } 81 return *updatedOperation, 0, nil 82 } 83 84 // InsertOperation stores operation in database 85 func (om *DeprovisionOperationManager) InsertOperation(operation internal.DeprovisioningOperation) (internal.DeprovisioningOperation, time.Duration, error) { 86 err := om.storage.InsertDeprovisioningOperation(operation) 87 if err != nil { 88 return operation, 1 * time.Minute, nil 89 } 90 return operation, 0, nil 91 } 92 93 // RetryOperationOnce retries the operation once and fails the operation when call second time 94 func (om *DeprovisionOperationManager) RetryOperationOnce(operation internal.DeprovisioningOperation, errorMessage string, err error, wait time.Duration, log logrus.FieldLogger) (internal.DeprovisioningOperation, time.Duration, error) { 95 return om.RetryOperation(operation, errorMessage, err, wait, wait+1, log) 96 } 97 98 // RetryOperation retries an operation for at maxTime in retryInterval steps and fails the operation if retrying failed 99 func (om *DeprovisionOperationManager) RetryOperation(operation internal.DeprovisioningOperation, errorMessage string, err error, retryInterval time.Duration, maxTime time.Duration, log logrus.FieldLogger) (internal.DeprovisioningOperation, time.Duration, error) { 100 since := time.Since(operation.UpdatedAt) 101 102 log.Infof("Retrying for %s in %s steps, error: %s", maxTime.String(), retryInterval.String(), errorMessage) 103 if since < maxTime { 104 return operation, retryInterval, nil 105 } 106 log.Errorf("Aborting after %s of failing retries", maxTime.String()) 107 return om.OperationFailed(operation, errorMessage, err, log) 108 } 109 110 // RetryOperationWithoutFail retries an operation for at maxTime in retryInterval steps and omits the operation if retrying failed 111 func (om *DeprovisionOperationManager) RetryOperationWithoutFail(operation internal.DeprovisioningOperation, description string, retryInterval, maxTime time.Duration, log logrus.FieldLogger) (internal.DeprovisioningOperation, time.Duration, error) { 112 since := time.Since(operation.UpdatedAt) 113 114 log.Infof("Retry Operation was triggered with message: %s", description) 115 log.Infof("Retrying for %s in %s steps", maxTime.String(), retryInterval.String()) 116 if since < maxTime { 117 return operation, retryInterval, nil 118 } 119 // update description to track failed steps 120 updatedOperation, repeat, _ := om.update(operation, domain.InProgress, description, log) 121 if repeat != 0 { 122 return updatedOperation, repeat, nil 123 } 124 125 log.Errorf("Omitting after %s of failing retries", maxTime.String()) 126 return updatedOperation, 0, nil 127 } 128 129 func (om *DeprovisionOperationManager) update(operation internal.DeprovisioningOperation, state domain.LastOperationState, description string, log logrus.FieldLogger) (internal.DeprovisioningOperation, time.Duration, error) { 130 return om.UpdateOperation(operation, func(operation *internal.DeprovisioningOperation) { 131 operation.State = state 132 operation.Description = fmt.Sprintf("%s : %s", operation.Description, description) 133 }, log) 134 }