saga

package module
v0.2.1 Latest Latest
Warning

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

Go to latest
Published: Jan 21, 2022 License: MIT Imports: 2 Imported by: 0

README

saga

package saga is a tiny library to help Golang compensating transaction.

In combination with code generator thunk, you can implement compensating transactions without nested if err != nil structures.

Usage

Example:

func (b *bookingApp) Book() (*Bookings, error) {
    // create new saga
	sg := saga.New()

    // run some process
	outboundTicket := saga.Make(sg, b.flightBookingService.Book("Tokyo", "Seoul", mustParseTime("2022/01/01 10:00")))
    // add compensation transaction, which will run if any following process failed
	sg.AddCompensation(b.flightBookingService.Cancel(outboundTicket))

	inboundTicket := saga.Make(sg, b.flightBookingService.Book("Seoul", "Tokyo", mustParseTime("2022/01/02 21:00")))
	sg.AddCompensation(b.flightBookingService.Cancel(inboundTicket))

	room := saga.Make(sg, b.hotelBookingService.Book(mustParseTime("2022/01/01 19:00")))

    // run all compensating transactions
	sg.Compensate()

	if sg.HasError() {
		return nil, sg.Error()
	}

	return &Bookings{
		outboundTicket: outboundTicket,
		inboundTicket:  inboundTicket,
		room:           room,
	}, nil
}
# happy path
$ ./book
succeed to book flight!: flight ticket: from Tokyo to Seoul, 01/01 10:00
succeed to book flight!: flight ticket: from Seoul to Tokyo, 01/02 21:00
succeed to book hotel!: hotel room: number 699, 01/01
ready for traveling!!

# error triggers compensating transactions
$ ./book
succeed to book flight!: flight ticket: from Tokyo to Seoul, 01/01 10:00
failed to book flight...flight ticket: from Seoul to Tokyo, 01/02 21:00
succeed to cancel ticket: flight ticket: from Tokyo to Seoul, 01/01 10:00
1 error occurred:
        * failed to book flight...: flight ticket: from Seoul to Tokyo, 01/02 21:00

$ ./book
succeed to book flight!: flight ticket: from Tokyo to Seoul, 01/01 10:00
succeed to book flight!: flight ticket: from Seoul to Tokyo, 01/02 21:00
failed to book hotel...: hotel room: number 755, 01/01
succeed to cancel ticket: flight ticket: from Seoul to Tokyo, 01/02 21:00
succeed to cancel ticket: flight ticket: from Tokyo to Seoul, 01/01 10:00
1 error occurred:
        * failed to book hotel...: hotel room: number 755, 01/01

Try example and check how it works!

Documentation

Index

Constants

This section is empty.

Variables

This section is empty.

Functions

func Make

func Make[T any](s *Saga, f func() (T, error)) T

Make runs the recieved function in saga and return value if the function succeeded. Raised error is kept inside saga. If any error has already been raised in saga, it does nothing.

NOTE: due to the type parameter limitation, method Saga.Make is not provided yet.

func Run

func Run(s *Saga, f func() error)

Run runs the recieved function in saga. Raised error is kept inside saga. If any error has already been raised in saga, it does nothing.

Types

type Compensation

type Compensation = func() error

Compensation is a type alias of compensating transaction function.

type Saga

type Saga struct {
	// contains filtered or unexported fields
}

Saga controls compensating transactions and keeps errors raised in the middle of exection.

func New

func New() *Saga

New creates a new saga.

func (*Saga) AddCompensation

func (s *Saga) AddCompensation(c Compensation)

AddCompensation adds a compensating transaction to the saga. if any error has already been raised in saga, it adds nothing.

func (*Saga) Compensate

func (s *Saga) Compensate()

Compensate executes compensating transactions. If no errors have been raised so far, it does nothing. The compensation transactions are executed in the reversed order of addition.

func (*Saga) Error

func (s *Saga) Error() error

Error returns an error raised during the saga. compensating transaction errors are wrapped inside.

func (*Saga) Errors

func (s *Saga) Errors() []error

Errors returns all errors raised during the saga, including compensating transaction errors.

func (*Saga) HasError

func (s *Saga) HasError() bool

HasError returns whether error(s) is raised in the saga.

func (*Saga) Run

func (s *Saga) Run(f func() error)

Run runs the recieved function. Raised error is kept inside. If any error has already been raised in saga, it does nothing.

Jump to

Keyboard shortcuts

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