Documentation ¶
Index ¶
Examples ¶
Constants ¶
This section is empty.
Variables ¶
This section is empty.
Functions ¶
This section is empty.
Types ¶
type R ¶
type R struct {
// contains filtered or unexported fields
}
R is a utility struct that can save rollback functions that need to be executed when something fails. It is meant to be declared as a value near the start of a function followed by a deferred call to R.Execute or R.MustExecute. The function can proceed normally and for every successful mutation it does it can register a function in R which rolls back that mutation. If the function succeeds it should call R.Skip before returning to skip the rollback.
Example:
func foo() error { var r rollback.R defer r.MustExecute() // call action that mutates state and can fail err := mutableAction() if err != nil { return err } // append reversal of mutableAction1 to rollback r.Append(rollbackOfMutableAction) // do more mutable actions and append rollbacks to r // ... r.Skip() // all actions succeeded, skip rollbacks return nil }
func (*R) Append ¶
Append appends a function that can fail to R that will be called in Execute when executing a rollback.
func (*R) AppendPure ¶
func (r *R) AppendPure(f func())
AppendPure appends a function that can't fail to R that will be called in Execute when executing a rollback.
func (*R) Execute ¶
Execute will run all appended functions in the reverse order (similar as a defer call). At the end it cleans up the appended functions, meaning that calling Execute a second time won't execute the functions anymore. If a rollback function returns an error Execute panics.
Example ¶
package main import ( "fmt" "github.com/conduitio/conduit/pkg/foundation/cerrors" "github.com/conduitio/conduit/pkg/foundation/rollback" ) const maxState = 5 var state int func main() { state = 0 // reset state runExample(maxState + 1) fmt.Printf("end state: %d\n", state) } // runExample will run the incrementState function a number of times and roll // back the state if needed. func runExample(incrementTimes int) { var r rollback.R defer r.MustExecute() for i := 0; i < incrementTimes; i++ { err := incrementState() if err != nil { fmt.Printf("error: could not increment state: %s\n", err.Error()) fmt.Println("returning and rolling back") return } r.Append(decrementState) } r.Skip() } func incrementState() error { if state >= maxState { return cerrors.New("max state reached") } state++ fmt.Printf("incremented state, new value: %d\n", state) return nil } func decrementState() error { if state <= 0 { return cerrors.New("min state reached") } state-- fmt.Printf("decremented state, new value: %d\n", state) return nil }
Output: incremented state, new value: 1 incremented state, new value: 2 incremented state, new value: 3 incremented state, new value: 4 incremented state, new value: 5 error: could not increment state: max state reached returning and rolling back decremented state, new value: 4 decremented state, new value: 3 decremented state, new value: 2 decremented state, new value: 1 decremented state, new value: 0 end state: 0
func (*R) MustExecute ¶
func (r *R) MustExecute()
MustExecute will call Execute and panic if it returns an error.
func (*R) Skip ¶
func (r *R) Skip()
Skip will remove all previously appended rollback functions from R. Any function that will be appended after the call to Skip will still be executed.
Example ¶
package main import ( "fmt" "github.com/conduitio/conduit/pkg/foundation/cerrors" "github.com/conduitio/conduit/pkg/foundation/rollback" ) const maxState = 5 var state int func main() { state = 0 // reset state runExample(maxState) fmt.Printf("end state: %d\n", state) } // runExample will run the incrementState function a number of times and roll // back the state if needed. func runExample(incrementTimes int) { var r rollback.R defer r.MustExecute() for i := 0; i < incrementTimes; i++ { err := incrementState() if err != nil { fmt.Printf("error: could not increment state: %s\n", err.Error()) fmt.Println("returning and rolling back") return } r.Append(decrementState) } r.Skip() } func incrementState() error { if state >= maxState { return cerrors.New("max state reached") } state++ fmt.Printf("incremented state, new value: %d\n", state) return nil } func decrementState() error { if state <= 0 { return cerrors.New("min state reached") } state-- fmt.Printf("decremented state, new value: %d\n", state) return nil }
Output: incremented state, new value: 1 incremented state, new value: 2 incremented state, new value: 3 incremented state, new value: 4 incremented state, new value: 5 end state: 5