Stop using
go func, start usinggofuncy!
Context-aware, observable goroutine management with built-in resilience patterns.
- 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
go get github.com/foomo/gofuncyctx := 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()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 |
// 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-inMetrics (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 |
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 |
Contributions are welcome! Please read the contributing guide.
Distributed under MIT License, please see the license file within the code for more details.
