async

package module
v1.0.1 Latest Latest
Warning

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

Go to latest
Published: Jan 23, 2026 License: MIT Imports: 1 Imported by: 2

README

go-async

A lightweight, type-safe asynchronous execution library for Go that provides elegant abstractions for running concurrent operations with channel-based result handling.

Features

  • Type-Safe Generics: Leverages Go generics for compile-time type safety
  • Context-Aware: Full support for context.Context for cancellation and timeout handling
  • Simple API: Clean, intuitive interface for async operations
  • Result Pattern: Encapsulates success and error states in a unified Result type
  • Single & Stream Operations: Support for both one-shot async calls and streaming results
  • Zero Dependencies: Built using only Go's standard library

Installation

go get github.com/uoul/go-async

Quick Start

Single Async Operation

Execute a single asynchronous operation and receive the result through a channel:

package main

import (
    "context"
    "fmt"
    "time"
    
    "github.com/uoul/go-async"
)

func main() {
    ctx := context.Background()
    
    // Execute an async operation
    result := async.Do(ctx, func(ctx context.Context) (string, error) {
        time.Sleep(100 * time.Millisecond)
        return "Hello, Async!", nil
    })
    
    // Receive the result
    r := <-result
    if r.Error != nil {
        fmt.Printf("Error: %v\n", r.Error)
    } else {
        fmt.Printf("Success: %v\n", r.Value)
    }
}
Streaming Results

Process multiple results asynchronously:

package main

import (
	"context"
	"fmt"
	"time"

	"github.com/uoul/go-async"
)

func main() {
	v := 0
	seq := async.Stream[int](context.Background(), func(ctx context.Context) (int, error, bool) {
		v++
		time.Sleep(2 * time.Second)
		if v >= 10 {
			return v, nil, false
		}
		return v, nil, true
	})

	for result := range seq {
		if result.Error != nil {
			fmt.Printf("Error: %v\n", result.Error)
			continue
		}
		fmt.Printf("Received: %v\n", result.Value)
	}
}

API Reference

Types
Result[T]

A channel type that carries async operation results:

type Result[T any] chan _Result[T]
Stream[T]

A channel type for streaming multiple results:

type Stream[T any] chan _Result[T]
_Result[T]

Internal result structure containing either a value or an error:

type _Result[T any] struct {
    Value T
    Error error
}
Functions
Do[T any](ctx context.Context, action func(ctx context.Context) (T, error)) Result[T]

Executes an action asynchronously and returns a Result[T] channel that receives exactly one value.

Parameters:

  • ctx: Context for cancellation and timeout handling
  • action: Function to execute asynchronously

Returns: A Result[T] channel that will receive one result and then close

Stream[T any](ctx context.Context, step func(ctx context.Context) (T, error, bool)) Stream[T]

Executes a step function repeatedly and streams results through a channel.

Parameters:

  • ctx: Context for cancellation and timeout handling
  • step: Function that returns (value, error, shouldContinue)

Returns: A Stream[T] channel that receives multiple results

Design Philosophy

This library embraces Go's native concurrency primitives while providing a cleaner abstraction layer. It follows these principles:

  • Explicit over implicit: Operations are clearly async through the API
  • Context-first: All operations respect context cancellation
  • Type safety: Generics ensure compile-time type checking
  • Simplicity: Minimal API surface with maximum utility

Contributing

Contributions are welcome! Please feel free to submit issues or pull requests.


Made with ❤️ for the Go community

Documentation

Index

Constants

This section is empty.

Variables

This section is empty.

Functions

func Fail added in v1.0.1

func Fail[T any](err error) _Result[T]

This generates an error async result - Anyway this function it not necessary when using Exec() or Stream

func Success added in v1.0.1

func Success[T any](val T) _Result[T]

This function generates a successful async result - Anyway this function it not necessary when using Exec() or Stream

Types

type Result

type Result[T any] chan _Result[T]

func Do

func Do[T any](ctx context.Context, action func(ctx context.Context) (T, error)) Result[T]

Do executes the given action asynchronously in a goroutine and returns a Result[T] channel that will receive exactly one value.

The action is executed with the provided context, allowing for cancellation and timeout handling. The function returns immediately without blocking, and the result is sent through the returned channel once the action completes.

The returned channel is closed after the result is sent, ensuring that consumers can safely range over it or use it in select statements.

If the action returns an error, the channel receives a _Result[T] with a non-nil Error field and a zero-value Value field. If the action succeeds, the channel receives a _Result[T] with the result in the Value field and a nil Error field.

Example:

result := Do(ctx, func(ctx context.Context) (string, error) {
    return fetchData(ctx)
})
r := <-result
if r.Error != nil {
    log.Printf("error: %v", r.Error)
} else {
    log.Printf("Success: %v", r.Value)
}

type Sequence

type Sequence[T any] Result[T]

Sequence is technically the same as Result, but it has other semantics - A Result is meant to return a single result while a Sequence is meant to return multiple

func Stream

func Stream[T any](ctx context.Context, step func(ctx context.Context) (T, error, bool)) Sequence[T]

Stream executes the given step function repeatedly in a goroutine and returns a Sequence[T] channel that receives multiple results.

The step function is called in a loop with the provided context. Each iteration produces a result of type T, an error, and a boolean indicating whether to continue (true) or stop (false).

The function returns immediately without blocking, and results are sent through the returned channel as they are produced. The channel is closed when the step function returns false or when the goroutine completes.

For each iteration:

  • If step returns an error, a _Result[T] with a non-nil Error field is sent
  • If step succeeds, a _Result[T] with the result in the Value field is sent
  • If the next boolean is false, the loop terminates and the channel closes

This is useful for streaming operations where multiple values are produced over time, such as paginated API calls, database cursors, or iterative computations.

Example:

seq := Stream(ctx, func(ctx context.Context) (int, error, bool) {
    value, hasMore := fetchNextBatch(ctx)
    return value, nil, hasMore
})
for result := range seq {
    if result.Error != nil {
        log.Printf("error: %v", result.Error)
        continue
    }
    log.Printf("received: %v", result.Value)
}

Jump to

Keyboard shortcuts

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