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