Basic Examples
Fire-and-Forget
Spawn a background goroutine. Errors are logged automatically.
go
package main
import (
"context"
"fmt"
"time"
"github.com/foomo/gofuncy"
)
func main() {
ctx := context.Background()
gofuncy.Go(ctx, func(ctx context.Context) error {
fmt.Println("running in the background")
return nil
})
time.Sleep(100 * time.Millisecond)
}Custom Error Handler
Override the default slog handler to handle errors yourself.
go
package main
import (
"context"
"errors"
"fmt"
"time"
"github.com/foomo/gofuncy"
)
func main() {
ctx := context.Background()
gofuncy.Go(ctx, func(ctx context.Context) error {
return errors.New("something went wrong")
},
gofuncy.WithName("custom-handler"),
gofuncy.WithErrorHandler(func(ctx context.Context, err error) {
fmt.Printf("[%s] error: %v\n", gofuncy.NameFromContext(ctx), err)
}),
)
time.Sleep(100 * time.Millisecond)
// Output: [custom-handler] error: something went wrong
}Async with Deferred Result
Launch work now, collect the result when you need it. The wait function is safe to call from multiple goroutines.
go
package main
import (
"context"
"fmt"
"github.com/foomo/gofuncy"
)
func main() {
ctx := context.Background()
var user string
var orders []string
// Launch two async calls
waitUser := gofuncy.Wait(ctx, func(ctx context.Context) error {
user = "Alice"
return nil
})
waitOrders := gofuncy.Wait(ctx, func(ctx context.Context) error {
orders = []string{"order-1", "order-2"}
return nil
})
// Wait for both
if err := waitUser(); err != nil {
fmt.Println("user error:", err)
return
}
if err := waitOrders(); err != nil {
fmt.Println("orders error:", err)
return
}
fmt.Printf("%s has %d orders\n", user, len(orders))
// Output: Alice has 2 orders
}Synchronous Execution with Do
Run a function through the full middleware chain without spawning a goroutine. Useful for inline calls that need retry, timeout, or circuit breaker.
go
package main
import (
"context"
"fmt"
"time"
"github.com/foomo/gofuncy"
)
func main() {
ctx := context.Background()
err := gofuncy.Do(ctx, func(ctx context.Context) error {
// Simulate a flaky call
return fmt.Errorf("connection refused")
},
gofuncy.WithRetry(3, gofuncy.RetryBackoff(gofuncy.BackoffConstant(100*time.Millisecond))),
gofuncy.WithTimeout(500*time.Millisecond),
)
if err != nil {
fmt.Println("failed after retries:", err)
}
}Basic Group
Run multiple functions concurrently and collect all errors.
go
package main
import (
"context"
"errors"
"fmt"
"github.com/foomo/gofuncy"
)
func main() {
ctx := context.Background()
g := gofuncy.NewGroup(ctx)
g.Add(func(ctx context.Context) error {
fmt.Println("task A")
return nil
})
g.Add(func(ctx context.Context) error {
fmt.Println("task B")
return errors.New("task B failed")
})
g.Add(func(ctx context.Context) error {
fmt.Println("task C")
return nil
})
if err := g.Wait(); err != nil {
fmt.Println("group error:", err)
}
// Output (order may vary):
// task A
// task B
// task C
// group error: task B failed
}All Over a Slice
Iterate over items concurrently with a concurrency limit.
go
package main
import (
"context"
"fmt"
"time"
"github.com/foomo/gofuncy"
)
func main() {
ctx := context.Background()
items := []string{"alpha", "bravo", "charlie", "delta", "echo"}
err := gofuncy.All(ctx, items, func(ctx context.Context, item string) error {
fmt.Printf("processing %s\n", item)
time.Sleep(50 * time.Millisecond) // simulate work
return nil
},
gofuncy.WithLimit(2), // process 2 at a time
)
if err != nil {
fmt.Println("errors:", err)
}
}Channel
Send and receive values through an observable channel with built-in metrics.
go
package main
import (
"context"
"fmt"
"github.com/foomo/gofuncy/channel"
)
func main() {
ctx := context.Background()
ch := channel.New[int](channel.WithBuffer[int](5))
// Send multiple values at once
if err := ch.Send(ctx, 1, 2, 3, 4, 5); err != nil {
fmt.Println("send error:", err)
return
}
fmt.Printf("buffered: %d/%d\n", ch.Len(), ch.Cap())
// Output: buffered: 5/5
// Close and drain
ch.Close()
for v := range ch.Receive() {
fmt.Println(v)
}
}Map with Result Collection
Transform items concurrently and collect results in order.
go
package main
import (
"context"
"fmt"
"github.com/foomo/gofuncy"
)
func main() {
ctx := context.Background()
numbers := []int{1, 2, 3, 4, 5}
squares, err := gofuncy.Map(ctx, numbers, func(ctx context.Context, n int) (int, error) {
return n * n, nil
})
if err != nil {
fmt.Println("error:", err)
return
}
fmt.Println(squares) // [1 4 9 16 25]
}Stoppable Goroutine with GoWithCancel
Spawn a goroutine and stop it later.
go
package main
import (
"context"
"fmt"
"time"
"github.com/foomo/gofuncy"
)
func main() {
stop := gofuncy.GoWithCancel(context.Background(), func(ctx context.Context) error {
for {
select {
case <-ctx.Done():
fmt.Println("stopped")
return nil
case <-time.After(100 * time.Millisecond):
fmt.Println("tick")
}
}
})
time.Sleep(350 * time.Millisecond)
stop()
time.Sleep(50 * time.Millisecond)
// Output:
// tick
// tick
// tick
// stopped
}