promise

package module
v0.0.1 Latest Latest
Warning

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

Go to latest
Published: Feb 27, 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

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 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 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 List

type List[R any] []Future[R]

List is a list of Future, representing results of asynchronous tasks.

func (List[R]) All

func (l List[R]) All(ctx context.Context) func(yield func(int, result.Result[R]) bool)

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

func (List[R]) AwaitAll

func (l List[R]) AwaitAll(ctx context.Context) []result.Result[R]

AwaitAll 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 (List[R]) AwaitAllValues

func (l List[R]) AwaitAllValues(ctx context.Context) ([]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 (List[R]) AwaitFirst

func (l List[R]) AwaitFirst(ctx context.Context) (R, error)

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

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