Show HN: Rill – Composable concurrency toolkit for Go

Overview of Rill

  • Channel-based concurrency toolkit for Go focused on composable “channel transformations.”
  • Provides helpers like FromSlice, Map, ForEach, batching, order preservation, and centralized error handling.
  • Zero dependencies; grows out of production use to reduce goroutine/WaitGroup boilerplate.

API Design and Use Cases

  • Treats channels as streams, not containers; supports infinite streams and large datasets.
  • Typical pattern: source channel → concurrent map/processing → concurrent sink.
  • Used or considered for HTTP fan‑out (e.g., RSS readers), analytics batching, data pipelines, and DAG-style runners.

Performance, Channels, and Backpressure

  • Main bottleneck is channel operations; library overhead is reported as negligible.
  • Considered suitable for workloads where Go channels are already appropriate; used on pipelines moving hundreds of GBs.
  • Backpressure is inherited from channel semantics; buffering can be inserted via helper functions.

Error Handling and Context/Cancellation

  • Centralized error handling is a key goal, but details get scrutiny.
  • Library is intentionally context-agnostic: callers are expected to manage context.Context themselves for timeouts and cancellation.
  • Some see lack of built-in context integration (e.g., auto-cancel on first error) as a significant gap.
  • Concern raised that early returns from pipelines don’t necessarily mean all goroutines are done, unless user wiring handles cancellation.

Comparisons to Other Tools and Paradigms

  • Compared to conc, worker-pool libs, state-machine/retry frameworks, Rx-style libs, and iterator-based APIs.
  • Rill emphasizes generics, type safety, and explicit channels rather than hiding them behind observables or iterators.
  • Some argue iterators could provide concurrency without channels; others stress channels’ many-to-many and select capabilities.

Debate on Abstractions vs Raw Go

  • Some praise the API as intuitive and closer to functional constructs like Map/ForEach.
  • Others feel these abstractions clash with Go’s preference for simple loops and explicit constructs, and worry about readability and adoption.

Testing, Concurrency Bugs, and Reliability

  • Long sub-thread debates whether comprehensive unit tests can reliably catch subtle concurrency and security issues.
  • One side argues that thorough, well-planned tests can essentially eliminate bugs.
  • Others counter that concurrency and security failures often involve complex, emergent conditions that are hard to anticipate and test exhaustively, so better abstractions and tools are still valuable.