Help us shape the future of Go! Take the 2026 Go Developer Survey

conker

package module
v0.1.0 Latest Latest
Warning

This package is not in the latest version of its module.

Go to latest
Published: May 20, 2026 License: MIT Imports: 2 Imported by: 0

README

conker: concurrency with the string attached

Go Reference Go MIT

conker is a structured concurrency library for Go 1.25+, built on the lessons of sourcegraph/conc with a modernised stdlib-first approach.

go get github.com/purpleclay/conker

At a glance

  • Use conker.WaitGroup if you want a panic-safe replacement for sync.WaitGroup
  • Use panics.Catcher if you want to catch panics in goroutines you manage yourself
  • Use panics.ErrPanic with errors.Is to detect recovered panics without a type assertion

Goals

Typed panics, not bare any

Go's recover() returns any. Every library that catches goroutine panics has to decide what to do with that opaque value, and the stdlib gives you nothing beyond the raw interface.

conker makes recovered panics first-class errors. *panics.Recovered implements error and integrates with errors.Is and errors.As — the same tools you already use for every other error in your program.

stdlib conker
done := make(chan any, 1)
go func() {
    defer func() {
        done <- recover()
    }()
    doSomethingThatMightPanic()
}()

val := <-done
if val != nil {
    // val is any — type-switch required,
    // no errors.Is/As, stack lost
    panic(val)
}
var c panics.Catcher
c.Try(doSomethingThatMightPanic)

if r := c.Recovered(); r != nil {
    // r is *panics.Recovered — a typed error
    errors.Is(r, panics.ErrPanic) // true
    errors.Is(r, ErrTimeout)      // true if panic value wrapped it
    log.Print(r.Stack)            // stack at panic site, not here
}

Panic-safe goroutines without boilerplate

Spawning goroutines safely with sync.WaitGroup requires a lot of ceremony: Add, Done, a deferred recover, and a decision about what to do with the panic value. conker.WaitGroup collapses all of that to one line.

Under the hood it delegates directly to sync.WaitGroup.Go — introduced in Go 1.25 — so there is no reimplementation of what the stdlib already does.

stdlib conker
var wg sync.WaitGroup
for i := 0; i < 10; i++ {
    wg.Add(1)
    go func() {
        defer wg.Done()
        defer func() {
            if v := recover(); v != nil {
                // swallowed, or re-panic loses stack
            }
        }()
        doSomething()
    }()
}
wg.Wait()
var wg conker.WaitGroup
for i := 0; i < 10; i++ {
    wg.Go(doSomething)
}
// re-panics as *panics.Recovered with
// the original stack trace preserved
wg.Wait()

When you want to handle a panic rather than propagate it, use WaitAndRecover:

var wg conker.WaitGroup
wg.Go(riskyOperation)

if r := wg.WaitAndRecover(); r != nil {
    log.Printf("goroutine panicked: %v\n%s", r.Value, r.Stack)
}

Roadmap

conker is pre-1.0. The following milestones track progress toward a stable API:

Milestone Theme Status
v0.1.0 Foundations ✅
v0.2.0 Pool Planned
v0.3.0 Stream Planned
v0.4.0 Iter Planned
v0.5.0 Daemons & tooling Planned

Upcoming highlights: pool.Pool with recursive task submission and bounded backpressure, pool.ResultPool[T] with submission-order results by default, stream.Stream with ordered concurrent callbacks, and native Go 1.23 iter.Seq/iter.Seq2 support in the iter package.

Documentation

Index

Constants

This section is empty.

Variables

This section is empty.

Functions

This section is empty.

Types

type WaitGroup

type WaitGroup struct {
	// contains filtered or unexported fields
}

WaitGroup is a panic-safe wrapper around sync.WaitGroup that propagates panics from goroutines spawned with WaitGroup.Go to the caller of WaitGroup.Wait or WaitGroup.WaitAndRecover.

The zero value is ready to use. WaitGroup is reusable across multiple Wait cycles when no panic occurs. If a goroutine panics, create a new WaitGroup for subsequent work rather than reusing the same instance.

Example — basic usage:

var wg conker.WaitGroup
wg.Go(func() { doWork() })
wg.Go(func() { doMoreWork() })
wg.Wait() // re-panics if any goroutine panicked

Example — recovering from a panic without propagating:

var wg conker.WaitGroup
wg.Go(func() { riskyWork() })
if r := wg.WaitAndRecover(); r != nil {
    log.Printf("goroutine panicked at:\n%s", r.Stack)
}

func (*WaitGroup) Go

func (w *WaitGroup) Go(f func())

Go spawns f in a new goroutine. Any panic raised by f is captured and surfaced when WaitGroup.Wait or WaitGroup.WaitAndRecover is called, with the stack trace preserved at the original panic site.

func (*WaitGroup) Wait

func (w *WaitGroup) Wait()

Wait blocks until all goroutines launched with WaitGroup.Go have returned, then re-panics with the first captured panic as a *panics.Recovered. It is a no-op if no goroutine panicked.

func (*WaitGroup) WaitAndRecover

func (w *WaitGroup) WaitAndRecover() *panics.Recovered

WaitAndRecover blocks until all goroutines launched with WaitGroup.Go have returned and returns the first captured panic, or nil if none occurred.

Directories

Path Synopsis
Package panics provides typed panic recovery that integrates with Go's standard errors package.
Package panics provides typed panic recovery that integrates with Go's standard errors package.

Jump to

Keyboard shortcuts

? : This menu
/ : Search site
f or F : Jump to
y or Y : Canonical URL