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

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