{"id":27970247,"url":"https://github.com/justindfuller/first","last_synced_at":"2025-05-07T21:57:22.406Z","repository":{"id":257801051,"uuid":"862913794","full_name":"JustinDFuller/first","owner":"JustinDFuller","description":"A concurrency tool that gets the first value or all the errors.","archived":false,"fork":false,"pushed_at":"2025-05-05T23:17:46.000Z","size":25,"stargazers_count":1,"open_issues_count":2,"forks_count":0,"subscribers_count":1,"default_branch":"main","last_synced_at":"2025-05-07T21:57:16.673Z","etag":null,"topics":["concurrency","go","library"],"latest_commit_sha":null,"homepage":"https://pkg.go.dev/github.com/justindfuller/first","language":"Go","has_issues":false,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"mit","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/JustinDFuller.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":"LICENSE","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null}},"created_at":"2024-09-25T12:01:08.000Z","updated_at":"2024-09-30T15:56:05.000Z","dependencies_parsed_at":"2024-09-26T08:49:24.933Z","dependency_job_id":null,"html_url":"https://github.com/JustinDFuller/first","commit_stats":null,"previous_names":["justindfuller/first"],"tags_count":6,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/JustinDFuller%2Ffirst","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/JustinDFuller%2Ffirst/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/JustinDFuller%2Ffirst/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/JustinDFuller%2Ffirst/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/JustinDFuller","download_url":"https://codeload.github.com/JustinDFuller/first/tar.gz/refs/heads/main","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":252961817,"owners_count":21832193,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["concurrency","go","library"],"created_at":"2025-05-07T21:57:21.904Z","updated_at":"2025-05-07T21:57:22.371Z","avatar_url":"https://github.com/JustinDFuller.png","language":"Go","funding_links":[],"categories":[],"sub_categories":[],"readme":"# first\n\n[![Go Reference](https://pkg.go.dev/badge/github.com/justindfuller/first.svg)](https://pkg.go.dev/github.com/justindfuller/first)\n[![Build Status](https://github.com/JustinDFuller/first/actions/workflows/build.yml/badge.svg)](https://github.com/JustinDFuller/first/actions/workflows/build.yml)\n[![Go Report Card](https://goreportcard.com/badge/github.com/justindfuller/first)](https://goreportcard.com/report/github.com/justindfuller/first)\n![Go Test Coverage](https://img.shields.io/endpoint?url=https://gist.githubusercontent.com/justindfuller/63d4999a653a0555c9806062b40c0139/raw/first_coverage.json)\n\n## TL;DR\n\nIt is a concurrency tool that gets the first value _or_ all the errors.\n\n## 📖 Table of Contents 📖\n- [What?](#what)\n- [When?](#when)\n- [Usage](#usage)\n- [Documentation](#documentation)\n\n## What?\n\n`First` is a synchronization tool. It gets the first result that does not return an error. Otherwise, it gets all the errors.\n\nYou might think of it as similar to [`sync.WaitGroup`](https://pkg.go.dev/sync#WaitGroup). Except, it either waits for the first result _or_ all of the errors.\n\nYou might think of it as similar to an [`errgroup.Group`](https://pkg.go.dev/golang.org/x/sync/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.\n\n## When?\n\nOne 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.\n\nBasically, 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.\n\n## Usage\n\n### Install\n\nFirst, install the package.\n\n```\ngo get github.com/justindfuller/first\n```\n\n### Basic Example\n\nThen, use it.\n\n```go\npackage main\n\ntype example struct{\n    name string\n}\n\nfunc main() {\n\tvar f first.First[*example]\n\t\n\tf.Do(func() (*example, error) {\n\t\ttime.Sleep(10 * time.Millisecond)\n\t\n\t\treturn \u0026example{name: \"one\"}, nil\n\t})\n\t\n\tf.Do(func() (*example, error) {\n\t\treturn \u0026example{name: \"two\"}, nil\n\t})\n\t\n\tres, err := f.Wait()\n\tif err != nil {\n\t\tlog.Fatalf(\"Error: %s\", err)\n\t}\n\t\n\tlog.Printf(\"Result: %v\", res) // prints \"two\"\n}\n```\n\n### Context Example\n\nIt also supports using contexts.\n\n```go\npackage main\n\ntype example struct{\n    name string\n}\n\nfunc main() {\n\tf, ctx := first.WithContext[*example](context.Background())\n\t\n\tf.Do(func() (*example, error) {\n\t\tselect {\n\t\t\tcase \u003c-time.After(10 * time.Millisecond):\t\t\n\t\t\t\treturn \u0026example{name: \"one\"}, nil\n\t\t\tcase \u003c-ctx.Done():\n\t\t\t\tlog.Print(\"Skipped one\")\n\t\t\t\treturn nil, ctx.Err()\n\t\t}\n\t})\n\t\n\tf.Do(func() (*example, error) {\n\t\tselect {\n\t\t\tcase \u003c-time.After(1 * time.Millisecond):\t\t\n\t\t\t\treturn \u0026example{name: \"two\"}, nil\n\t\t\tcase \u003c-ctx.Done():\n\t\t\t\tlog.Print(\"Skipped two\")\n\t\t\t\treturn nil, ctx.Err()\n\t\t}\t\n\t})\n\t\n\tres, err := f.Wait()\n\tif err != nil {\n\t\tlog.Fatalf(\"Error: %s\", err)\n\t}\n\t\n\tlog.Printf(\"Result: %v\", res) // prints \"two\"\n\t// Also prints, \"skipped one\"\n\n\tlog.Printf(\"Context: %s\", ctx.Err())\n\t// Prints: \"Context: context canceled\"\n}\n```\n\n## Documentation\n\nPlease refer to the go documentation hosted on [pkg.go.dev](https://pkg.go.dev/github.com/justindfuller/first). You can see [all available types and methods](https://pkg.go.dev/github.com/justindfuller/first#pkg-index) and [runnable examples](https://pkg.go.dev/github.com/justindfuller/first#pkg-examples).\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fjustindfuller%2Ffirst","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fjustindfuller%2Ffirst","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fjustindfuller%2Ffirst/lists"}