A Go library for parallel function execution with different error handling strategies and utilities.
- Parallel Execution: Run multiple functions concurrently with various error handling strategies
- Error Handling: Choose from different error handling approaches (fail-fast, collect all, etc.)
- Retry Logic: Built-in retry functionality with configurable backoff
- Context Support: Full context.Context support for cancellation and timeouts
- Utilities: Additional helpers for delayed execution, parallel skipping, and more
go get github.com/bborbe/runpackage main
import (
"context"
"fmt"
"github.com/bborbe/run"
)
func main() {
ctx := context.Background()
// Run functions in parallel, stop on first error
err := run.CancelOnFirstError(ctx,
func(ctx context.Context) error {
fmt.Println("Task 1")
return nil
},
func(ctx context.Context) error {
fmt.Println("Task 2")
return nil
},
)
if err != nil {
fmt.Printf("Error: %v\n", err)
}
}// Cancel all remaining functions when first one finishes
err := run.CancelOnFirstFinish(ctx, funcs...)
// Cancel all remaining functions when first error occurs
err := run.CancelOnFirstError(ctx, funcs...)
// Run all functions, collect all errors
err := run.All(ctx, funcs...)
// Run functions sequentially
err := run.Sequential(ctx, funcs...)retryableFunc := run.Retry(run.Backoff{
Delay: time.Second,
Factor: 2.0,
Retries: 3,
IsRetryAble: func(err error) bool {
// Custom logic to determine if error is retryable
return true
},
}, func(ctx context.Context) error {
// Your function that may fail
return someOperation(ctx)
})
err := retryableFunc(ctx)// Delay execution by 5 seconds
delayedFunc := run.Delayed(func(ctx context.Context) error {
fmt.Println("This runs after 5 seconds")
return nil
}, 5*time.Second)
err := delayedFunc(ctx)skipper := run.NewParallelSkipper()
// Wrap function to prevent parallel execution
protectedFunc := skipper.SkipParallel(func(ctx context.Context) error {
// This function will be skipped if already running
return expensiveOperation(ctx)
})The library is built around two main interfaces:
// Func is a function that can be executed with context
type Func func(context.Context) error
// Runnable interface for objects that can be run
type Runnable interface {
Run(ctx context.Context) error
}// Get a channel of errors for custom processing
errorChan := run.Run(ctx, funcs...)
for err := range errorChan {
if err != nil {
log.Printf("Function failed: %v", err)
}
}// For long-running background tasks
runner := run.NewBackgroundRunner()
// ... (see source code for full API)func startServer(ctx context.Context) error {
server := &http.Server{Addr: ":8080"}
return run.CancelOnFirstFinish(ctx,
func(ctx context.Context) error {
// Start server
return server.ListenAndServe()
},
func(ctx context.Context) error {
// Wait for context cancellation
<-ctx.Done()
// Graceful shutdown
return server.Shutdown(context.Background())
},
)
}func processData(ctx context.Context, items []string) error {
var funcs []run.Func
for _, item := range items {
item := item // capture loop variable
funcs = append(funcs, func(ctx context.Context) error {
return processItem(ctx, item)
})
}
// Process all items, collect all errors
return run.All(ctx, funcs...)
}Contributions are welcome! Please feel free to submit a Pull Request.
This project is licensed under the BSD-style license. See the LICENSE file for details.