tcc

package module
v0.0.0-...-428be16 Latest Latest
Warning

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

Go to latest
Published: Mar 11, 2020 License: MIT Imports: 4 Imported by: 0

README

tcc - Tiny and minimal TCC (Try - Confirm - Cancel) pattern implementation

Build Status Coverage Status Go Report Card GoDoc

Abstract

In distributed system, transactions over network (distributed transaction) is a hard thing. There are some patterns to achieve distributed transactions, the one of them is called TCC. This library enables to implement TCC easily.

Usage

Working sample is in _example directory, or you can try the code in Go Playground.

package main

import (
	"log"

	"github.com/dty1er/tcc"
)

var (
	flightService = tcc.NewService(
		"flight reservation",
		db.tryReserveFlightSeat,
		db.confirmFlightSeatReservation,
		db.cancelFlightSeat,
	)

	hotelService = tcc.NewService(
		"hotel reservation",
		db.tryReserveHotelRoom,
		db.confirmHotelRoomReservation,
		db.cancelHotelRoom,
	)
)

func main() {
	doFirstReservation(db)
	doSecondReservation(db)
}

func doFirstReservation(db *FakeDB) {
	orchestrator := tcc.NewOrchestrator([]*tcc.Service{flightService, hotelService}, tcc.WithMaxRetries(1))
	err := orchestrator.Orchestrate()
	if err != nil {
		log.Printf("error happened in 1st reservation: %s", err)
	}
}

func doSecondReservation(db *FakeDB) {
	// In second reservation, flight seat is not enough
	// Please refer to working example
	orchestrator := tcc.NewOrchestrator([]*tcc.Service{flightService, hotelService}, tcc.WithMaxRetries(1))
	err := orchestrator.Orchestrate()
	if err != nil {
		log.Printf("error happened in 2nd reservation: %s", err)
	}

	// When error is returned, it can be casted into *tcc.Error
	tccErr := err.(*tcc.Error)
	log.Printf("tccErr.Error: %v", tccErr.Error())
	log.Printf("tccErr.FailedPhase == ErrTryFailed: %v", tccErr.FailedPhase() == tcc.ErrTryFailed)
	log.Printf("tccErr.ServiceName: %v", tccErr.ServiceName())
}
Documents

Described in GoDoc.

Ref

References for TCC pattern.

Eventual Data Consistency Solution in ServiceComb - part 3 Transactions for the REST of Us

License

MIT

Documentation

Index

Constants

View Source
const (
	// ErrTryFailed means at least 1 error happened in Try phase,
	// but successfully canceled.
	ErrTryFailed = iota

	// ErrConfirmFailed means Try phase finished in success, but
	// at least 1 error happened in Confirm phase and never succeeded after some retries.
	// This should be never happened because if Try finished successfully,
	// Confirm must be finished successfully.
	// Basically, you need to fix inconsistent state manually
	ErrConfirmFailed

	// ErrCancelFailed means Try phase didn't finish in success,
	// and attempted to cancel all the services, but some resources could not be canceled.
	// Basically, you need to fix inconsistent state manually
	ErrCancelFailed
)

Variables

This section is empty.

Functions

This section is empty.

Types

type Error

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

Error knows what err happened in try/confirm/cancel phase.

func (*Error) Error

func (e *Error) Error() string

Error satisfies error interface

func (*Error) FailedPhase

func (e *Error) FailedPhase() int

FailedPhase returns FailedPhase code.

func (*Error) ServiceName

func (e *Error) ServiceName() string

ServiceName returns the name of service which is failed to try/confirm/cancel.

type Option

type Option func(s *orchestrator)

Option can set option to service Option can be passed to NewService() and NewOrchestrator, if you pass it to both, the one which is passed to NewOrchestrator will be used

func WithMaxRetries

func WithMaxRetries(maxRetries uint64) Option

WithMaxRetries sets limitation of retry times

type Orchestrator

type Orchestrator interface {
	Orchestrate() error
}

Orchestrator can orchestrate multiple service First, call every service's try() asynchronously. If all the try succeeded, call every service's confirm(). If even one of the services' try fails, every service's cancel will be called.

func NewOrchestrator

func NewOrchestrator(services []*Service, opts ...Option) Orchestrator

NewOrchestrator returns interface Orchestrator

type Service

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

Service can be TCC service, which can Try(), Confirm(), and Cancel()

func NewService

func NewService(name string, try, confirm, cancel func() error) *Service

NewService returns service with passed functions

func (*Service) Cancel

func (s *Service) Cancel() error

Cancel executes passed cancel function. This will be called after Try phase failed. In Cancel phase, service will revert the state which is changed by try phase. Basically Confirm should never return error, except network or infrastructure issues. This will be retried 10 times by default.

func (*Service) CancelSucceeded

func (s *Service) CancelSucceeded() bool

CancelSucceeded returns if the service cancel() succeeded

func (*Service) Canceled

func (s *Service) Canceled() bool

Canceled returns if the service cancel() is called

func (*Service) Confirm

func (s *Service) Confirm() error

Confirm executes passed confirm function. In confirm phase, service will confirm things which is reserved in try phase. Basically Confirm should never return error, except network or infrastructure issues. This will be retried 10 times by default.

func (*Service) ConfirmSucceeded

func (s *Service) ConfirmSucceeded() bool

ConfirmSucceeded returns if the service confirm() succeeded

func (*Service) Confirmed

func (s *Service) Confirmed() bool

Confirmed returns if the service confirm() called

func (*Service) Tried

func (s *Service) Tried() bool

Tried returns if the service try() called

func (*Service) Try

func (s *Service) Try() error

Try executes passed try function. In try phase, service will do some reservation or precondition satisfyment. After try phase is finished successfully, Confirm called. Try can fail, but if try succeeded, confirm must succeed. If try fails, Cancel will be called. Try never be retried.

func (*Service) TrySucceeded

func (s *Service) TrySucceeded() bool

TrySucceeded returns if the service try() succeeded

Directories

Path Synopsis

Jump to

Keyboard shortcuts

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