Skip to content

Reject an empty effective processor chain before starting Batch #77

Description

@MasterOfBinary

Current outcome

Prevent accidentally consuming and discarding an input stream when a caller forgets the processor chain, while keeping intentional discard explicit.

Replanned on 2026-09-06 against GoBatch master 63ef757 and ShitQuant's recorder, enrichment, paper/replay, and flow workloads. This is an implementation target, not a claim that the behavior already exists.

Required behavior

  • Reject zero processors, an empty slice and an all-interface-nil chain with a documented startup error before reading the source or consuming the Batch's single-use state.
  • Specify typed-nil processor handling rather than assuming an interface comparison removes typed nil pointers.
  • Keep an explicit processor.Nil stage as an intentional drain/discard operation.
  • Match ErrNilSource-style failed-start retry/error-channel behavior; document whether the same instance can be correctly configured and started after validation fails.
  • Update all affected examples/tests and document the v0 migration.

Verification and completion

Assert no source reads on failed start, effective-chain cases, the chosen typed-nil behavior, successful corrected retry where promised, and deliberate discard.

Follow the repository's formatting, race-test, vet/lint, package documentation, example and changelog requirements for the changed surface. Report the actual supported behavior and migration; do not treat a passing coverage percentage as proof of these outcomes.

Scope and relationships

Independent of request batching and flow. Reconcile edits with open core PRs without requiring unrelated documentation PRs to merge first.

Design history

The earlier report/prototype remains below for provenance; the requirements above supersede conflicting prescriptions. Existing discussion is preserved.

Original issue: Require at least one Processor in Batch.Go (use processor.Nil for explicit drain)

Summary

Batch.Go(ctx, s, procs ...Processor[T]) currently accepts zero processors. With no processors the pipeline reads the source, discards every item, surfaces source errors, and fires Done(). That is a silent-data-discard footgun: forgetting to pass a processor produces a clean, error-free run that did nothing with the data — the same class of issue as a nil source (now ErrNilSource, see #64).

Proposal

Require at least one Processor. Callers who genuinely want to drain/discard a source pass an explicit no-op (&processor.Nil[T]{}, which already exists), so the intent is explicit at the call site instead of implicit.

Why

Tradeoffs to weigh

  • Breaks variadic ergonomics for the degenerate zero-stage case.
  • Breaks graceful handling of dynamically built processor lists that can legitimately be empty — callers would need to guard or substitute processor.Nil.
  • Breaks existing tests that assert no-processors is allowed: TestBatch_NoProcessors (batch/batch_test.go) and the empty-processor-slice case in batch/error_handling_test.go.
  • Breaking change (v0) → migration note + CHANGELOG entry.

Alternatives considered

  • Document current behavior — keep allowing zero processors, add a godoc line that it drains and discards items (source errors still surface). Lower friction, keeps the footgun.
  • Leave entirely as-is.

References

Activity

  1. MasterOfBinary commented on Jun 11, 2026

    @MasterOfBinary
    OwnerAuthor

    Validated against master @ 58cee73: zero processors still starts cleanly and silently discards all items (batch/batch.go:278-284 filters nil processors with no emptiness check; doProcessors skips the chain and only scans pre-set item.Error), and the behavior is undocumented in Go's godoc — the proposal is current with the #64 (<-chan error, error) contract, where an ErrNoProcessors sentinel fits naturally alongside ErrNilSource/ErrBatchUsed. One correction: the empty-processor-slice test is the second subtest of TestBatch_NoProcessors in batch/batch_test.go (~:703), not batch/error_handling_test.go (that file's related cases are "nil processor filtering" at ~:75 and an incidental no-processor call in TestBatch_NilChannelHandling at ~:116, which would also need updating). processor.Nil exists, so the explicit-drain idiom works today. No overlap with #70-75/#79 or open PRs. Coordinate merge order with #65/#76, which also touch batch/batch.go.

  2. changed the title [-]Require at least one Processor in Batch.Go (use processor.Nil for explicit drain)[/-] [+]Reject an empty effective processor chain before starting Batch[/+] on Sep 6, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions