Skip to content

itimofeev/go-saga

Folders and files

NameName
Last commit message
Last commit date

Latest commit

 

History

31 Commits
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 

Repository files navigation

go-saga Build Status codecov

Saga pattern implementation in Go

This library implements Choreography-based saga pattern. This pattern used when you need to deal with distributed transaction. Often in microservice architecture we need to do some actions in one service, then send request to second service, then send notification via third service. Saga allows defining compensation functions for each step that will be automatically applied in case of error on any step.

You can read more details about this pattern here https://microservices.io/patterns/data/saga.html#example-choreography-based-saga

Installing

go get github.com/itimofeev/go-saga

Getting started

func TestExample(t *testing.T) {
    // defines new saga
    s := NewSaga("saga name")
    
    x := 0 // saga will change x by adding 10 than adding 100
    require.NoError(t, s.AddStep(&Step{
        Name:           "1",
        Func:           func(context.Context) error { x += 10; return nil },
        CompensateFunc: func(context.Context) error { x -= 10; return nil },
    }))
    require.NoError(t, s.AddStep(&Step{
        Name:           "2",
        // suppose function in second step returns error
        Func:           func(context.Context) error { x += 100; return errors.New("err") },
        CompensateFunc: func(context.Context) error { x -= 100; return nil },
    }))
    
    store := New()
    c := NewCoordinator(context.Background(), context.Background(), s, store)
    require.Error(t, c.Play().ExecutionError)
    
    // x is still 0, because saga rolled back all applied steps
    require.Equal(t, 0, x)
}

Store

Coordinator stores all sagas executions using Store interface.

type Store interface {
	AppendLog(log *Log) error
	GetAllLogsByExecutionID(executionID string) ([]*Log, error)
	GetStepLogsToCompensate(executionID string) ([]*Log, error)
}

This library implements only in-memory store to eliminate dependencies. But it's easy to implement this interface using any DB, for example PostgreSQL.