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