• Stars
    star
    147
  • Rank 251,347 (Top 5 %)
  • Language
    Go
  • License
    MIT License
  • Created almost 6 years ago
  • Updated 3 months ago

Reviews

There are no reviews yet. Be the first to send feedback to the community and the maintainers!

Repository Details

Go lang implementation of saga pattern

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.