rollback

package
v0.11.0-nightly.20240615 Latest Latest
Warning

This package is not in the latest version of its module.

Go to latest
Published: Jun 14, 2024 License: Apache-2.0 Imports: 1 Imported by: 0

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

func (r *R) Append(f func() error)

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

func (r *R) Execute() error

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

Jump to

Keyboard shortcuts

? : This menu
/ : Search site
f or F : Jump to
y or Y : Canonical URL