It is a concurrency tool that gets the first value or all the errors.
First
is a synchronization tool. It gets the first result that does not return an error. Otherwise, it gets all the errors.
You might think of it as similar to sync.WaitGroup
. Except, it either waits for the first result or all of the errors.
You might think of it as similar to an errgroup.Group
. Except, it does not wait for all functions to return. It waits for the first function to return a value or it waits for all the functions to return an error.
One example is retrieving from a fast and slow data store concurrently. You might do this if you have no issue putting the full load on both resources.
Basically, you might use it any time you want to concurrently perform multiple tasks, but only need to wait for one of them to complete without error.
First, install the package.
go get github.com/justindfuller/first
Then, use it.
package main
type example struct{
name string
}
func main() {
var f first.First[*example]
f.Do(func() (*example, error) {
time.Sleep(10 * time.Millisecond)
return &example{name: "one"}, nil
})
f.Do(func() (*example, error) {
return &example{name: "two"}, nil
})
res, err := f.Wait()
if err != nil {
log.Fatalf("Error: %s", err)
}
log.Printf("Result: %v", res) // prints "two"
}
It also supports using contexts.
package main
type example struct{
name string
}
func main() {
f, ctx := first.WithContext[*example](context.Background())
f.Do(func() (*example, error) {
select {
case <-time.After(10 * time.Millisecond):
return &example{name: "one"}, nil
case <-ctx.Done():
log.Print("Skipped one")
return nil, ctx.Err()
}
})
f.Do(func() (*example, error) {
select {
case <-time.After(1 * time.Millisecond):
return &example{name: "two"}, nil
case <-ctx.Done():
log.Print("Skipped two")
return nil, ctx.Err()
}
})
res, err := f.Wait()
if err != nil {
log.Fatalf("Error: %s", err)
}
log.Printf("Result: %v", res) // prints "two"
// Also prints, "skipped one"
log.Printf("Context: %s", ctx.Err())
// Prints: "Context: context canceled"
}
Please refer to the go documentation hosted on pkg.go.dev. You can see all available types and methods and runnable examples.