promise

package module
v0.0.2 Latest Latest
Warning

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

Go to latest
Published: Mar 7, 2024 License: Apache-2.0 Imports: 6 Imported by: 2

README

Fillmore Labs Promise

Go Reference Build Status GitHub Workflow Test Coverage Maintainability Go Report Card License FOSSA Status

The promise package provides interfaces and utilities for writing asynchronous code in Go.

Motivation

Promises and futures are constructs used for asynchronous and concurrent programming, allowing developers to work with values that may not be immediately available and can be evaluated in a different execution context.

Go is known for its built-in concurrency features like goroutines and channels. The select statement further allows for efficient multiplexing and synchronization of multiple channels, thereby enabling developers to coordinate and orchestrate asynchronous operations effectively. Additionally, the context package offers a standardized way to manage cancellation, deadlines, and timeouts within concurrent and asynchronous code.

On the other hand, Go's error handling mechanism, based on explicit error values returned from functions, provides a clear and concise way to handle errors.

The purpose of this package is to provide a library which simplifies the integration of concurrent code while providing a cohesive strategy for handling asynchronous errors. By adhering to Go's standard conventions for asynchronous and concurrent code, as well as error propagation, this package aims to enhance developer productivity and code reliability in scenarios requiring asynchronous operations.

Usage

Assuming you have a synchronous function func getMyIP(ctx context.Context) (string, error) returning your external IP address (see GetMyIP for an example).

Now you can do

	ctx, cancel := context.WithTimeout(context.Background(), 2*time.Second)
	defer cancel()

	query := func() (string, error) {
		return getMyIP(ctx)
	}
	future := promise.NewAsync(query)

and elsewhere in your program, even in a different goroutine

	if ip, err := future.Await(ctx); err == nil {
		slog.Info("Found IP", "ip", ip)
	} else {
		slog.Error("Failed to fetch IP", "error", err)
	}

decoupling query construction from result processing.

GetMyIP

Sample code to retrieve your IP address:

const serverURL = "https://httpbin.org/ip"

func getMyIP(ctx context.Context) (string, error) {
	req, err := http.NewRequestWithContext(ctx, http.MethodGet, serverURL, nil)
	if err != nil {
		return "", err
	}
	req.Header.Set("Accept", "application/json")

	resp, err := http.DefaultClient.Do(req)
	if err != nil {
		return "", err
	}
	defer func() { _ = resp.Body.Close() }()

	ipResponse := struct {
		Origin string `json:"origin"`
	}{}
	err = json.NewDecoder(resp.Body).Decode(&ipResponse)

	return ipResponse.Origin, err
}

Documentation

Index

Constants

This section is empty.

Variables

View Source
var ErrNoResult = errors.New("no result")

ErrNoResult is returned when a future completes but has no defined result value.

View Source
var ErrNotReady = errors.New("future not ready")

ErrNotReady is returned when a future is not complete.

Functions

func AwaitAll added in v0.0.2

func AwaitAll[R any](ctx context.Context, futures ...Future[R]) func(yield func(int, result.Result[R]) bool)

AwaitAll returns a function that yields the results of all futures. If the context is canceled, it returns an error for the remaining futures.

func AwaitAllAny added in v0.0.2

func AwaitAllAny(ctx context.Context, futures ...AnyFuture) func(yield func(int, result.Result[any]) bool)

AwaitAllAny returns a function that yields the results of all futures. If the context is canceled, it returns an error for the remaining futures.

func AwaitAllResults added in v0.0.2

func AwaitAllResults[R any](ctx context.Context, futures ...Future[R]) []result.Result[R]

AwaitAllResults waits for all futures to complete and returns the results. If the context is canceled, it returns early with errors for the remaining futures.

func AwaitAllResultsAny added in v0.0.2

func AwaitAllResultsAny(ctx context.Context, futures ...AnyFuture) []result.Result[any]

AwaitAllResultsAny waits for all futures to complete and returns the results. If the context is canceled, it returns early with errors for the remaining futures.

func AwaitAllValues added in v0.0.2

func AwaitAllValues[R any](ctx context.Context, futures ...Future[R]) ([]R, error)

AwaitAllValues returns the values of completed futures. If any future fails or the context is canceled, it returns early with an error.

func AwaitAllValuesAny added in v0.0.2

func AwaitAllValuesAny(ctx context.Context, futures ...AnyFuture) ([]any, error)

AwaitAllValuesAny returns the values of completed futures. If any future fails or the context is canceled, it returns early with an error.

func AwaitFirst added in v0.0.2

func AwaitFirst[R any](ctx context.Context, futures ...Future[R]) (R, error)

AwaitFirst returns the result of the first completed future. If the context is canceled, it returns early with an error.

func AwaitFirstAny added in v0.0.2

func AwaitFirstAny(ctx context.Context, futures ...AnyFuture) (any, error)

AwaitFirstAny returns the result of the first completed future. If the context is canceled, it returns early with an error.

func New

func New[R any]() (Promise[R], Future[R])

New provides a simple way to create a Promise for asynchronous operations. This allows synchronous and asynchronous code to be composed seamlessly and separating initiation from running.

The returned Future can be used to retrieve the eventual result of the Promise.

Types

type AnyFuture added in v0.0.2

type AnyFuture interface {
	// contains filtered or unexported methods
}

AnyFuture matches a Future of any type.

type Future

type Future[R any] <-chan result.Result[R]

Future represents an asynchronous operation that will complete sometime in the future.

It is a read-only channel that can be used with Future.Await to retrieve the final result of a Promise.

func NewAsync

func NewAsync[R any](fn func() (R, error)) Future[R]

NewAsync runs fn asynchronously, immediately returning a Future that can be used to retrieve the eventual result. This allows separating evaluating the result from computation.

func (Future[R]) Await

func (f Future[R]) Await(ctx context.Context) (R, error)

Await returns the final result of the associated Promise. It can only be called once and blocks until a result is received or the context is canceled. If you need to read multiple times from a Future wrap it with Future.Memoize.

func (Future[R]) Memoize

func (f Future[R]) Memoize() *Memoizer[R]

Memoize returns a memoizer for the given future, consuming it in the process.

The Memoizer can be queried multiple times from multiple goroutines.

func (Future[R]) Try

func (f Future[R]) Try() (R, error)

Try returns the result when ready, ErrNotReady otherwise.

type Memoizer

type Memoizer[R any] struct {
	// contains filtered or unexported fields
}

A Memoizer is created with Future.Memoize and contains a memoized result of a future.

func (*Memoizer[R]) Await

func (m *Memoizer[R]) Await(ctx context.Context) (R, error)

Await blocks until the future is ready and returns the result.

func (*Memoizer[R]) Try

func (m *Memoizer[R]) Try() (R, error)

Try returns the result of the future if it is ready, otherwise it returns ErrNoResult.

type Promise

type Promise[R any] chan<- result.Result[R]

Promise is used to send the result of an asynchronous operation.

It is a write-only promise. Either Promise.Resolve or Promise.Reject should be called exactly once.

func (Promise[R]) Do

func (p Promise[R]) Do(f func() (R, error))

Do runs f synchronously, resolving the promise with the return value.

func (Promise[R]) Reject

func (p Promise[R]) Reject(err error)

Reject breaks the promise with an error.

func (Promise[R]) Resolve

func (p Promise[R]) Resolve(value R)

Resolve fulfills the promise with a value.

Directories

Path Synopsis

Jump to

Keyboard shortcuts

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