atomic

package module
v0.0.0-...-dd0ea4f Latest Latest
Warning

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

Go to latest
Published: May 29, 2024 License: MIT Imports: 6 Imported by: 0

README

go-atomic GoDoc Build Status Coverage Status Go Report Card

A package enabling go business layers to define blocks of code accessing remote systems in a sql-transaction like way. Essentially this allows the use of the Unit of Work pattern with go repositories.

Installation

$ go get -u github.com/beeemT/go-atomic

Usage

  1. Choose the appropriate executor for your datasource.
  2. Open the data source as usual.
  3. Create an executor with the data source.
  4. Create a function which generates new resource/repository instances from the provided remote interface (eg generic sql remote).
  5. Create a new transacter with the executor and generation function.
  6. Perform the data source interaction within the transacter's Transact block.

It is most useful to put interactions with services which do not allow the use of transactions at the and of the transact block. This yields consistency between the systems in more scenarios.

Since Transact allows automatic retries (depending on executor and the transacter options) it is a good practice (if possible) to implement idempotency keys in remote systems if they do not allow the use of transactions (using keys which are not generated within a Transact block).

Since these transact blocks (depending on interactions with remote systems) might result in longer running transactions this can lead to contention on the data source. It is generally a good practice to implement optional row locking on reading data which will later be updated in the Transact block. One such example would be cockroachdb's / postgresql's 'SELECT ... FOR UPDATE'.

Example

// Choose whichever executor fits your use case
sqlDb, err := stdlibsql.Open("postgres", "postgresql://user:password@localhost:5432/dbname")
if err != nil {
	panic(err)
}

executor := sql.NewExecuter(sqlDb)

guard := generic.NewTransacter[generic.SQLRemote, Resources](
	executor,
	resourcesFactory,
)

err = guard.Transact(context.TODO(), func(ctx context.Context, resources Resources) error {
	err := resources.Foos.Create(ctx, Foo{
		ID: int(1),
	})
	if err != nil {
		return errors.Wrap(err, "creating foo")
	}

	err = resources.Bars.Create(ctx, Bar{
		ID: int(1),
	})
	if err != nil {
		return errors.Wrap(err, "creating bar")
	}

	// eg here we can do some more business logic, like payments or other things
	// Foo and Bar only get committed if the payment was successful

	return nil
})

if err != nil {
	panic(err)
}

See the documentation for a complete API specification.

For an example see the example folder of the relevant version.

Development Status

Building tests.


Released under the MIT License.

Documentation

Overview

Package atomic contains interfaces and shared code for the individual driver implementations to achieve transaction like behavior on access of remote systems in an implementation agnostic manner in business layers.

Index

Constants

This section is empty.

Variables

View Source
var DefaultBackoffs = []time.Duration{
	100 * time.Millisecond,
	time.Second,
	5 * time.Second,
	10 * time.Second,
	30 * time.Second,
	1 * time.Minute,
	5 * time.Minute,
}

DefaultBackoffs are the default backoffs for transacters

Functions

func DefaultRetry

func DefaultRetry(backoffs []time.Duration, run func() error) error

DefaultRetry is the default retry function for transacters. It retries errors that are have one of the following errors in their chain: - context.DeadlineExceeded - net.ErrClosed - os.ErrDeadlineExceeded It retries for a maximum of len(backoffs) times.

Types

type ContextKey

type ContextKey string

ContextKey is the type of the context keys used by the transacter.

const (
	// SessionContextKey is the key used to store active transacter sessions in context.
	SessionContextKey ContextKey = "session"
)

type Transacter

type Transacter[Resources any] interface {
	// Transact executes run atomically, rolling back on error and committing on return.
	// Atomicity (depending on implementation in the remote systems accessed) can only be guaranteed
	// for statements made on the fields of the provided Resources type.
	// Transact opens a new session before calling run and inserts it into the context.
	// If a Transact session is already present in the provided context Transact will reuse that
	// session.
	// Depending on the implementation of Transact it is possible that this leads to nested
	// transactions.
	// In this case on error in the inner call to Transact only the statements made in the inner run
	// functions are rollbacked.
	// For this to work it is necessary to always pass the use the context provided to run as the
	// parent context in statements inside the run function.
	Transact(ctx context.Context, run func(context.Context, Resources) error) error
}

Transacter interface consists of the Transact method.

Directories

Path Synopsis
Package example provides a minimal example implementation of how to use the generic transacter.
Package example provides a minimal example implementation of how to use the generic transacter.
Package generic implements a generic Transacter which is compatible with a wide range of executors for different data sources.
Package generic implements a generic Transacter which is compatible with a wide range of executors for different data sources.
crdb
Package crdb implements [generic.Executer] for cockroachdb
Package crdb implements [generic.Executer] for cockroachdb
gorm
Package gorm provides a way to integrate multiple different versions of gorm / potentially other databases go-atomic if they implement the GormlikeDB interface.
Package gorm provides a way to integrate multiple different versions of gorm / potentially other databases go-atomic if they implement the GormlikeDB interface.
sql
Package sql implements [generic.Executer] for the stdlib sql db
Package sql implements [generic.Executer] for the stdlib sql db
sqlx
Package sqlx implements [generic.Executer] for the sqlx databases
Package sqlx implements [generic.Executer] for the sqlx databases

Jump to

Keyboard shortcuts

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