gofuncy

package module
v0.2.0 Latest Latest
Warning

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

Go to latest
Published: Apr 13, 2026 License: MIT Imports: 19 Imported by: 0

README

Build Status Go Report Card GoDoc

gofuncy

gofuncy

Stop using go func, start using gofuncy!

Context-aware, observable goroutine management with built-in resilience patterns.

Features

  • Context propagation with routine name and parent chain
  • Automatic panic recovery
  • Built-in telemetry (metrics and tracing via OpenTelemetry)
  • Resilience: retry with exponential backoff, circuit breaker, fallback
  • Concurrency control via semaphores and group limits
  • Stall detection

Installation

go get github.com/foomo/gofuncy

Quick Start

ctx := gofuncy.Ctx(context.Background()).Root()

// Fire-and-forget goroutine
gofuncy.Go(ctx, func(ctx context.Context) error {
    return doWork(ctx)
})

// Synchronous execution with middleware chain
err := gofuncy.Do(ctx, fetchData)

// Goroutine with wait
wait := gofuncy.Wait(ctx, processItems)
// ... do other work ...
err := wait()

Core API

Every function wraps a gofuncy.Func:

type Func func(ctx context.Context) error
Function Description
Go(ctx, fn, ...GoOption) Fire-and-forget goroutine with error logging
Start(ctx, fn, ...GoOption) Like Go, blocks until the goroutine is running
StartWithReady(ctx, fn, ...GoOption) Like Go, blocks until fn signals readiness
StartWithStop(ctx, fn, ...GoOption) Like Go, goroutine receives a stop function to cancel itself
GoWithCancel(ctx, fn, ...GoOption) Like Go, returns a stop function
Do(ctx, fn, ...GoOption) Synchronous execution, returns error directly
Wait(ctx, fn, ...GoOption) Goroutine that returns a wait function
WaitWithStop(ctx, fn, ...GoOption) Like Wait, goroutine receives a stop function
WaitWithReady(ctx, fn, ...GoOption) Like Wait, blocks until fn signals readiness
NewGroup(ctx, ...GroupOption) Concurrent group with shared lifecycle
All(ctx, items, fn, ...GroupOption) Execute fn for each item concurrently
Map(ctx, items, fn, ...GroupOption) Transform items concurrently, preserving order

Options

// Naming (optional)
gofuncy.WithName("my-routine")

// Resilience
gofuncy.WithTimeout(5 * time.Second)
gofuncy.WithRetry(3)
gofuncy.WithCircuitBreaker(cb)
gofuncy.WithFallback(fallbackFn)

// Concurrency
gofuncy.WithLimit(10)      // Group only
gofuncy.WithLimiter(sem)   // Shared semaphore

// Telemetry (on by default, opt-out)
gofuncy.WithoutTracing()
gofuncy.WithoutStartedCounter()
gofuncy.WithoutErrorCounter()
gofuncy.WithoutActiveUpDownCounter()
gofuncy.WithDurationHistogram() // opt-in

Telemetry

Metrics (all via OpenTelemetry):

Name Type Default
gofuncy.goroutines.started Counter on
gofuncy.goroutines.errors Counter on
gofuncy.goroutines.active UpDownCounter on
gofuncy.goroutines.stalled Counter on
gofuncy.goroutines.duration.seconds Histogram off
gofuncy.groups.duration.seconds Histogram off

Channel

The channel subpackage provides a generic, observable channel:

import "github.com/foomo/gofuncy/channel"

ch := channel.New[string](channel.WithBuffer[string](100))
defer ch.Close()

ch.Send(ctx, "hello", "world")

for msg := range ch.Receive() {
    fmt.Println(msg)
}

Channel metrics:

Name Type Default
gofuncy.chans.current UpDownCounter on
gofuncy.messages.sent Counter on
gofuncy.messages.duration.seconds Histogram off

How to Contribute

Contributions are welcome! Please read the contributing guide.

Contributors

License

Distributed under MIT License, please see the license file within the code for more details.

Made with ♥ foomo by bestbytes

Documentation

Overview

Package gofuncy provides context-aware, observable goroutine management with built-in resilience patterns (retry, circuit breaker, fallback).

It replaces raw go func() calls with structured APIs that propagate context, recover from panics, and emit OpenTelemetry metrics and traces.

Index

Examples

Constants

View Source
const (
	// NameRoot is the default root name used for setting or retrieving the root context in a routine hierarchy.
	NameRoot string = "root"
	// NameNoName is the default name used when no routine name is explicitly set.
	NameNoName string = "noname"
)
View Source
const ScopeName = "github.com/foomo/gofuncy"

ScopeName is the OpenTelemetry instrumentation scope name used by all gofuncy metrics and traces.

Variables

View Source
var ErrCircuitOpen = errors.New("circuit breaker is open")

ErrCircuitOpen is returned when the circuit breaker is open and not accepting requests.

Functions

func All

func All[T any](ctx context.Context, items []T, fn func(ctx context.Context, item T) error, opts ...GroupOption) error

All executes fn for each item concurrently and returns the joined errors. All GroupOption options apply (WithLimit, WithFailFast, telemetry, etc.). Use WithName to set a custom metric/tracing label; defaults to "gofuncy.all".

Example
package main

import (
	"context"
	"fmt"

	"github.com/foomo/gofuncy"
)

func main() {
	urls := []string{"https://a.test", "https://b.test", "https://c.test"}

	err := gofuncy.All(context.Background(), urls,
		func(ctx context.Context, url string) error {
			fmt.Println("fetching", url)
			return nil
		},
	)

	fmt.Println("error:", err)
}
Output:
fetching https://a.test
fetching https://b.test
fetching https://c.test
error: <nil>

func Do

func Do(ctx context.Context, fn Func, opts ...GoOption) error

Do executes fn synchronously with the full middleware chain (resilience, telemetry, tracing) and returns the error directly. Unlike Go, it does not spawn a goroutine. Use WithName to set a custom metric/tracing label; defaults to "gofuncy.do".

Example
package main

import (
	"context"
	"fmt"

	"github.com/foomo/gofuncy"
)

func main() {
	err := gofuncy.Do(context.Background(), func(ctx context.Context) error {
		fmt.Println("hello")
		return nil
	})

	fmt.Println("error:", err)
}
Output:
hello
error: <nil>
Example (Fallback)
package main

import (
	"context"
	"fmt"

	"github.com/foomo/gofuncy"
)

func main() {
	err := gofuncy.Do(context.Background(),
		func(ctx context.Context) error {
			return fmt.Errorf("primary failed")
		},
		gofuncy.WithFallback(func(ctx context.Context, err error) error {
			fmt.Println("fallback called:", err)
			return nil // suppress the error
		}),
	)

	fmt.Println("error:", err)
}
Output:
fallback called: primary failed
error: <nil>
Example (Retry)
package main

import (
	"context"
	"fmt"
	"sync/atomic"
	"time"

	"github.com/foomo/gofuncy"
)

func main() {
	var attempts atomic.Int32

	err := gofuncy.Do(context.Background(),
		func(ctx context.Context) error {
			n := attempts.Add(1)
			if n < 3 {
				return fmt.Errorf("attempt %d failed", n)
			}

			fmt.Println("succeeded on attempt", n)

			return nil
		},
		gofuncy.WithRetry(5),
		gofuncy.WithTimeout(time.Second),
	)

	fmt.Println("error:", err)
}
Output:
succeeded on attempt 3
error: <nil>

func Go

func Go(ctx context.Context, fn Func, opts ...GoOption)

Go spawns a fire-and-forget goroutine with panic recovery. Errors are logged via slog by default; use WithErrorHandler to override. Use WithName to set a custom metric/tracing label; defaults to "gofuncy.go".

Example
package main

import (
	"context"
	"fmt"

	"github.com/foomo/gofuncy"
)

func main() {
	done := make(chan struct{})

	gofuncy.Go(context.Background(), func(ctx context.Context) error {
		defer close(done)

		fmt.Println("running")

		return nil
	})

	<-done
}
Output:
running

func Map

func Map[T, R any](ctx context.Context, items []T, fn func(ctx context.Context, item T) (R, error), opts ...GroupOption) ([]R, error)

Map transforms items concurrently, preserving input order. Returns results and the joined errors. All GroupOption options apply (WithLimit, WithFailFast, telemetry, etc.). Use WithName to set a custom metric/tracing label; defaults to "gofuncy.map".

Example
package main

import (
	"context"
	"fmt"

	"github.com/foomo/gofuncy"
)

func main() {
	items := []int{1, 2, 3, 4, 5}

	results, err := gofuncy.Map(context.Background(), items,
		func(ctx context.Context, n int) (int, error) {
			return n * 2, nil
		},
	)

	fmt.Println("results:", results)
	fmt.Println("error:", err)
}
Output:
results: [2 4 6 8 10]
error: <nil>

func NameFromContext

func NameFromContext(ctx context.Context) string

NameFromContext extracts the routine name from the given context, falling back to a default "noname" if not found.

func ParentFromContext

func ParentFromContext(ctx context.Context) string

ParentFromContext extracts the parent routine name from the given context.

func Start added in v0.2.0

func Start(ctx context.Context, fn Func, opts ...GoOption)

Start is like Go but blocks until the goroutine has actually started executing. This is useful in tests where you need the routine to be running before proceeding. Use WithName to set a custom metric/tracing label; defaults to "gofuncy.start".

Example
package main

import (
	"context"
	"fmt"

	"github.com/foomo/gofuncy"
)

func main() {
	done := make(chan struct{})

	gofuncy.Start(context.Background(), func(ctx context.Context) error {
		defer close(done)

		fmt.Println("running")

		return nil
	})

	<-done
}
Output:
running

func StartWithReady added in v0.2.0

func StartWithReady(ctx context.Context, fn func(ctx context.Context, ready ReadyFunc) error, opts ...GoOption)

StartWithReady spawns a goroutine and blocks until fn signals readiness by calling ready(). If fn returns before calling ready(), StartWithReady unblocks anyway. The ready function is safe to call multiple times. Use WithName to set a custom metric/tracing label; defaults to "gofuncy.startwithready".

Example
package main

import (
	"context"
	"fmt"

	"github.com/foomo/gofuncy"
)

func main() {
	proceed := make(chan struct{})
	done := make(chan struct{})

	gofuncy.StartWithReady(context.Background(), func(ctx context.Context, ready gofuncy.ReadyFunc) error {
		defer close(done)

		fmt.Println("initializing")
		ready()

		<-proceed
		fmt.Println("running")

		return nil
	})

	fmt.Println("ready")
	close(proceed)
	<-done
}
Output:
initializing
ready
running

func StartWithStop added in v0.2.0

func StartWithStop(ctx context.Context, fn func(ctx context.Context, stop StopFunc) error, opts ...GoOption)

StartWithStop spawns a fire-and-forget goroutine that receives a stop function. Calling stop cancels the goroutine's context, signaling it to shut down. The stop function is safe to call multiple times. Use WithName to set a custom metric/tracing label; defaults to "gofuncy.startwithstop".

Example
package main

import (
	"context"
	"fmt"

	"github.com/foomo/gofuncy"
)

func main() {
	done := make(chan struct{})

	gofuncy.StartWithStop(context.Background(), func(ctx context.Context, stop gofuncy.StopFunc) error {
		defer close(done)

		fmt.Println("started")
		stop() // self-cancel
		<-ctx.Done()
		fmt.Println("stopped")

		return nil
	})

	<-done
}
Output:
started
stopped

func Wait

func Wait(ctx context.Context, fn Func, opts ...GoOption) func() error

Wait spawns a goroutine with the full middleware chain and returns a wait function. Calling the wait function blocks until the goroutine completes and returns its error. The wait function is safe to call multiple times and from multiple goroutines — it always returns the same result. Use WithName to set a custom metric/tracing label; defaults to "gofuncy.wait".

Example
package main

import (
	"context"
	"fmt"

	"github.com/foomo/gofuncy"
)

func main() {
	wait := gofuncy.Wait(context.Background(), func(ctx context.Context) error {
		fmt.Println("working")
		return nil
	})

	// Do other work here while goroutine runs...

	if err := wait(); err != nil {
		fmt.Println("error:", err)
	}

	fmt.Println("done")
}
Output:
working
done

func WaitWithReady added in v0.2.0

func WaitWithReady(ctx context.Context, fn func(ctx context.Context, ready ReadyFunc) error, opts ...GoOption) func() error

WaitWithReady spawns a goroutine and blocks until fn signals readiness by calling ready(), then returns a wait function. If fn returns before calling ready(), WaitWithReady unblocks anyway. The wait function blocks until the goroutine completes and returns its error. Both the ready and wait functions are safe to call multiple times. Use WithName to set a custom metric/tracing label; defaults to "gofuncy.waitwithready".

Example
package main

import (
	"context"
	"fmt"

	"github.com/foomo/gofuncy"
)

func main() {
	proceed := make(chan struct{})

	wait := gofuncy.WaitWithReady(context.Background(), func(ctx context.Context, ready gofuncy.ReadyFunc) error {
		fmt.Println("initializing")
		ready()

		<-proceed
		fmt.Println("done")

		return nil
	})

	fmt.Println("ready")
	close(proceed)

	if err := wait(); err != nil {
		fmt.Println("error:", err)
	}
}
Output:
initializing
ready
done

func WaitWithStop added in v0.2.0

func WaitWithStop(ctx context.Context, fn func(ctx context.Context, stop StopFunc) error, opts ...GoOption) func() error

WaitWithStop spawns a goroutine that receives a stop function and returns a wait function. Calling stop cancels the goroutine's context. The wait function blocks until the goroutine completes and returns its error. Both functions are safe to call multiple times. Use WithName to set a custom metric/tracing label; defaults to "gofuncy.waitwithstop".

Example
package main

import (
	"context"
	"fmt"

	"github.com/foomo/gofuncy"
)

func main() {
	wait := gofuncy.WaitWithStop(context.Background(), func(ctx context.Context, stop gofuncy.StopFunc) error {
		fmt.Println("started")
		stop()
		<-ctx.Done()
		fmt.Println("stopped")

		return nil
	})

	err := wait()
	fmt.Println("error:", err)
}
Output:
started
stopped
error: <nil>

func WithCallerSkip

func WithCallerSkip(skip int) goOnlyOpt

WithCallerSkip sets the caller skip for error reporting.

func WithChildTrace

func WithChildTrace() baseOpt

WithChildTrace forces child spans instead of detached root spans. This is primarily useful with Go() to override its default detached behavior.

func WithCircuitBreaker

func WithCircuitBreaker(cb *CircuitBreaker) baseOpt

WithCircuitBreaker sets a circuit breaker for the operation. The circuit breaker is stateful — create one via NewCircuitBreaker and share it across all calls to the same dependency.

func WithDetachedTrace

func WithDetachedTrace() baseOpt

WithDetachedTrace creates new root spans linked to the parent span context instead of child spans. This is useful when goroutines represent independent work units (e.g., event processing) that should not be nested under the caller's trace but should still reference it.

For Go(), detached traces are the default — use WithChildTrace to opt out. For Do(), Wait(), and NewGroup(), child traces are the default.

func WithDurationHistogram

func WithDurationHistogram() baseOpt

WithDurationHistogram enables the duration histogram metric.

func WithErrorHandler

func WithErrorHandler(h ErrorHandler) goOnlyOpt

WithErrorHandler sets a custom error handler.

func WithFailFast

func WithFailFast() groupOnlyOpt

WithFailFast configures the Group to cancel remaining functions on first error.

func WithFallback

func WithFallback(fn func(ctx context.Context, err error) error, opts ...FallbackOption) baseOpt

WithFallback sets a fallback function that is called when the operation fails. The fallback receives the original error and may return nil to suppress it or a different error.

func WithLimit

func WithLimit(n int) groupOnlyOpt

WithLimit sets the maximum number of concurrently executing functions in a Group.

func WithLimiter

func WithLimiter(l *semaphore.Weighted) baseOpt

WithLimiter sets a shared weighted semaphore for concurrency control.

func WithLogger

func WithLogger(l *slog.Logger) baseOpt

WithLogger configures the logger for the operation.

func WithMeterProvider

func WithMeterProvider(mp metric.MeterProvider) baseOpt

WithMeterProvider sets a custom meter provider.

func WithMiddleware

func WithMiddleware(m ...Middleware) baseOpt

WithMiddleware appends middleware to the operation's middleware chain.

func WithName added in v0.2.0

func WithName(name string) baseOpt

WithName sets the routine name used for context injection, metrics, and tracing. When omitted, each function uses a low-cardinality default (e.g. "gofuncy.go", "gofuncy.do").

func WithRetry

func WithRetry(maxAttempts int, opts ...RetryOption) baseOpt

WithRetry configures automatic retry with the given maximum attempts. maxAttempts is the total number of attempts (1 = no retry, 3 = initial + 2 retries).

func WithStallHandler

func WithStallHandler(h StallHandler) baseOpt

WithStallHandler sets a custom callback for stall detection. If not set, stalls are logged via slog.

func WithStallThreshold

func WithStallThreshold(d time.Duration) baseOpt

WithStallThreshold enables stall detection. If a goroutine runs longer than the threshold, a warning is logged and a metric is emitted. The goroutine is not cancelled. Use WithStallHandler to customize the callback.

func WithTimeout

func WithTimeout(timeout time.Duration) baseOpt

WithTimeout sets a per-invocation timeout. When combined with WithRetry, each retry attempt gets its own fresh deadline.

func WithTracerProvider

func WithTracerProvider(tp trace.TracerProvider) baseOpt

WithTracerProvider sets a custom tracer provider.

func WithoutActiveUpDownCounter

func WithoutActiveUpDownCounter() baseOpt

WithoutActiveUpDownCounter disables the active up-down counter metric.

func WithoutErrorCounter

func WithoutErrorCounter() baseOpt

WithoutErrorCounter disables the error counter metric.

func WithoutStartedCounter

func WithoutStartedCounter() baseOpt

WithoutStartedCounter disables the started counter metric.

func WithoutTracing

func WithoutTracing() baseOpt

WithoutTracing disables tracing for the operation.

Types

type Backoff

type Backoff func(attempt int) time.Duration

Backoff returns the delay before the nth retry attempt (0-indexed).

func BackoffConstant

func BackoffConstant(d time.Duration) Backoff

BackoffConstant returns a Backoff that always waits the same duration.

func BackoffExponential

func BackoffExponential(initial time.Duration, multiplier float64, maxDelay time.Duration) Backoff

BackoffExponential returns a Backoff with exponential growth, jitter, and a cap. The delay for attempt n is: min(initial * multiplier^n, max) +/- 25% jitter.

type CircuitBreaker

type CircuitBreaker struct {
	// contains filtered or unexported fields
}

CircuitBreaker holds the state for a circuit breaker instance. It is safe for concurrent use and should be shared across all calls to the same dependency.

func NewCircuitBreaker

func NewCircuitBreaker(opts ...CircuitBreakerOption) *CircuitBreaker

NewCircuitBreaker creates a new CircuitBreaker with the given options.

type CircuitBreakerOption

type CircuitBreakerOption func(*circuitBreakerConfig)

CircuitBreakerOption configures circuit breaker behavior.

func CircuitBreakerCooldown

func CircuitBreakerCooldown(d time.Duration) CircuitBreakerOption

CircuitBreakerCooldown sets the duration the circuit stays open before allowing a probe request. Defaults to 30s.

func CircuitBreakerIf

func CircuitBreakerIf(fn func(error) bool) CircuitBreakerOption

CircuitBreakerIf sets a custom function to determine whether an error counts as a failure. By default, all errors except context errors and panics count.

func CircuitBreakerOnStateChange

func CircuitBreakerOnStateChange(fn func(from, to CircuitState)) CircuitBreakerOption

CircuitBreakerOnStateChange sets a callback invoked when the circuit transitions between states.

func CircuitBreakerThreshold

func CircuitBreakerThreshold(n int) CircuitBreakerOption

CircuitBreakerThreshold sets the number of consecutive failures before the circuit opens. Defaults to 5.

type CircuitState

type CircuitState int

CircuitState represents the current state of a circuit breaker.

const (
	// CircuitClosed is the normal operating state where requests pass through.
	CircuitClosed CircuitState = iota
	// CircuitOpen is the state where requests are rejected immediately.
	CircuitOpen
	// CircuitHalfOpen is the state where a single probe request is allowed.
	CircuitHalfOpen
)

func (CircuitState) String

func (s CircuitState) String() string

String implements fmt.Stringer for CircuitState.

type Context

type Context struct {
	context.Context //nolint:containedctx
}

Context wraps a standard context with helper methods for accessing gofuncy routine name and parent information.

func Ctx

func Ctx(ctx context.Context) Context

Ctx wraps a context.Context with gofuncy helper methods.

Example
package main

import (
	"context"
	"fmt"

	"github.com/foomo/gofuncy"
)

func main() {
	done := make(chan struct{})

	gofuncy.Go(context.Background(), func(ctx context.Context) error {
		defer close(done)

		fmt.Println("name:", gofuncy.NameFromContext(ctx))

		return nil
	}, gofuncy.WithName("worker"))

	<-done
}
Output:
name: worker

func (Context) Name

func (c Context) Name() string

Name returns the routine name from the given context

func (Context) Parent

func (c Context) Parent() string

Parent returns the parent routine name from the given context

func (Context) Root

func (c Context) Root() context.Context

Root returns the context with the `root` name set

type ErrorHandler

type ErrorHandler func(ctx context.Context, err error)

ErrorHandler is a callback for handling errors from fire-and-forget goroutines.

type FallbackOption

type FallbackOption func(*fallbackConfig)

FallbackOption configures fallback behavior.

func FallbackIf

func FallbackIf(fn func(error) bool) FallbackOption

FallbackIf sets a custom function to determine whether an error should trigger the fallback. By default, all errors except context errors and panics trigger the fallback.

type Func

type Func func(ctx context.Context) error

Func represents a function that can be executed within a routine context.

type GoOption

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

GoOption configures Go() and Group.Add() calls.

type Group

type Group struct {
	// contains filtered or unexported fields
}

Group manages a set of concurrently executing functions with shared lifecycle control.

func NewGroup

func NewGroup(ctx context.Context, opts ...GroupOption) *Group

NewGroup creates a new Group with the given context and options. Use WithName to set a custom metric/tracing label; defaults to "gofuncy.group".

Example
package main

import (
	"context"
	"fmt"

	"github.com/foomo/gofuncy"
)

func main() {
	g := gofuncy.NewGroup(context.Background())

	g.Add(func(ctx context.Context) error {
		fmt.Println("a")
		return nil
	})
	g.Add(func(ctx context.Context) error {
		fmt.Println("b")
		return nil
	})

	if err := g.Wait(); err != nil {
		fmt.Println("error:", err)
	}

}
Output:
a
b
Example (FailFast)
package main

import (
	"context"
	"fmt"

	"github.com/foomo/gofuncy"
)

func main() {
	g := gofuncy.NewGroup(context.Background(),
		gofuncy.WithFailFast(),
		gofuncy.WithLimit(2),
	)

	g.Add(func(ctx context.Context) error {
		fmt.Println("ok")
		return nil
	})
	g.Add(func(ctx context.Context) error {
		return fmt.Errorf("something went wrong")
	})

	if err := g.Wait(); err != nil {
		fmt.Println("group error:", err)
	}

}
Output:
ok
group error: something went wrong

func (*Group) Add

func (g *Group) Add(fn Func, opts ...GoOption)

Add spawns a goroutine to execute fn immediately. Per-function opts are merged on top of the group options (additive). User middlewares and panic recovery are applied per fn. Use WithName to set a per-task label; defaults to "gofuncy.group.add".

func (*Group) Wait

func (g *Group) Wait() error

Wait blocks until all added functions complete and returns the joined errors. It is safe to call multiple times — the result is computed once.

type GroupOption

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

GroupOption configures NewGroup() calls.

type Middleware

type Middleware func(Func) Func

Middleware wraps a Func to add cross-cutting behavior.

func Fallback

func Fallback(fn func(ctx context.Context, err error) error, opts ...FallbackOption) Middleware

Fallback returns a Middleware that calls fn when the wrapped function returns an error, allowing graceful degradation. The fallback function receives the original context and error, and may return nil to suppress the error or a different error. By default, context errors and panics bypass the fallback; use FallbackIf to customize which errors trigger it.

func Retry

func Retry(maxAttempts int, opts ...RetryOption) Middleware

Retry returns a Middleware that retries the wrapped function up to maxAttempts times total (1 = no retry, 3 = initial + up to 2 retries).

type PanicError

type PanicError struct {
	Value any
	Stack []byte
}

PanicError wraps a recovered panic value with its stack trace.

func (*PanicError) Error

func (e *PanicError) Error() string

Error implements the error interface for PanicError.

func (*PanicError) Unwrap

func (e *PanicError) Unwrap() error

Unwrap returns the underlying error if the panic value implements error.

type ReadyFunc added in v0.2.0

type ReadyFunc func()

ReadyFunc signals that a goroutine has completed initialization. Safe to call multiple times.

type RetryOption

type RetryOption func(*retryConfig)

RetryOption configures retry behavior.

func RetryBackoff

func RetryBackoff(b Backoff) RetryOption

RetryBackoff sets a custom backoff strategy.

func RetryIf

func RetryIf(fn func(error) bool) RetryOption

RetryIf sets a custom function to determine whether an error is retryable.

func RetryOnRetry

func RetryOnRetry(fn func(ctx context.Context, attempt int, err error)) RetryOption

RetryOnRetry sets a callback invoked before each retry attempt. The attempt parameter is 1-indexed (1 = first retry).

type StallHandler

type StallHandler func(ctx context.Context, name string, threshold time.Duration)

StallHandler is called when a goroutine exceeds its stall threshold. The threshold parameter is the configured stall threshold duration.

type StopFunc added in v0.2.0

type StopFunc func()

StopFunc cancels a goroutine's context, signaling it to shut down. Safe to call multiple times.

func GoWithCancel added in v0.2.0

func GoWithCancel(ctx context.Context, fn Func, opts ...GoOption) StopFunc

GoWithCancel spawns a goroutine and returns a stop function. Calling stop cancels the goroutine's context, signaling it to shut down. The stop function is safe to call multiple times. Use WithName to set a custom metric/tracing label; defaults to "gofuncy.gowithcancel".

Example
package main

import (
	"context"
	"fmt"
	"sync/atomic"
	"time"

	"github.com/foomo/gofuncy"
)

func main() {
	var running atomic.Bool

	stop := gofuncy.GoWithCancel(context.Background(), func(ctx context.Context) error {
		running.Store(true)

		<-ctx.Done()
		running.Store(false)

		return nil
	})

	// Goroutine is running...
	time.Sleep(10 * time.Millisecond)
	fmt.Println("running:", running.Load())

	stop()
	time.Sleep(10 * time.Millisecond)
	fmt.Println("running:", running.Load())
}
Output:
running: true
running: false

Directories

Path Synopsis
Package channel provides a generic, observable channel with optional OpenTelemetry metrics and tracing for send operations.
Package channel provides a generic, observable channel with optional OpenTelemetry metrics and tracing for send operations.
Package semconv defines OpenTelemetry semantic convention attribute keys used by gofuncy for metrics and traces.
Package semconv defines OpenTelemetry semantic convention attribute keys used by gofuncy for metrics and traces.
gofuncyconv
Package gofuncyconv provides typed OpenTelemetry metric instrument wrappers for gofuncy's goroutine, group, channel, and message metrics.
Package gofuncyconv provides typed OpenTelemetry metric instrument wrappers for gofuncy's goroutine, group, channel, and message metrics.

Jump to

Keyboard shortcuts

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